Jump to content

Recommended Posts

Posted

Hello,

Now that Twitter limits video downloads to registered + authenticated users and encouraged users to add 2FA… is there a 32-bit application I could use from an AutoIt script to generate a token?

#include <File.au3>
#include <Math.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#include <MsgBoxConstants.au3>
#include <StringConstants.au3>
#include <Array.au3>


Func _MakeString()
    Local $aSplit = StringSplit('abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ', '')
    Local $sHoldString = ''
    For $iCC = 1 To Random(10, 15, 1)
        $sHoldString &= $aSplit[Random(1, 62, 1)]
    Next
    Return $sHoldString
EndFunc

Const $OUTPUTDIR = "c:\tmp\"
Const $OUTPUTFILENAME = _MakeString() & ".mp4"

Const $URL = "youtube-dlp.exe --username me --password blah --abort-on-error -f worst"

Local $sURL = InputBox("Link to video", "URL?", ClipGet())
if not $sURL Then Exit ConsoleWrite("Closed inputbox" & @CRLF)
$sURL = StringStripWS($sURL,$STR_STRIPLEADING + $STR_STRIPTRAILING)

;HERE
Local $sToken = InputBox("2FA token", "Token?", ClipGet())
if not $sToken Then Exit ConsoleWrite("Closed inputbox" & @CRLF)
$sToken = StringStripWS($sToken,$STR_STRIPLEADING + $STR_STRIPTRAILING)

Const $LINE = StringFormat($URL & " --twofactor %s -o %s %s",$sToken,$OUTPUTFILENAME,$sURL)
ClipPut($LINE)
ConsoleWrite($LINE & @CRLF)

Thank you.

Posted (edited)

You need to use an app to 1) import the secret key sent by the server once, and then 2) generate time-limited tokens, which combine a hash of the secret key and the current date+time.

Having the script include the source/call a third party app would avoid having to reach for the phone, run eg. FreeOTP+  to generate a token, type it in the AutoIt script, and hit OK.

---

Edit: At least one CLI app that works is authenticator.

1. Install node.js
2. npm install --global authenticator-cli
3. authenticator --account me@acme.com --key 'SECRET_KEY' | grep -Poha "^Token.+" | sed -r "s@^Token: (.+)$@\1@"

---

Edit: Alternatively, if Python's already installed:

pip install oathtool
oathtool SECRET_KEY

 

Edited by littlebigman
Posted

Yup, it works :-)

#include-once
#include <Crypt.au3>
#include <Date.au3>

;; http://www.autoitscript.com/forum/topic/145556-solved-hmac-sha1/?p=1028830
Func _HMAC_SHA1($key, $message)
    If Not IsBinary($key) Then $key = Binary($key)
    If Not IsBinary($message) Then $message = Binary($message)
    Local $blocksize = 64
    Local $a_opad[$blocksize], $a_ipad[$blocksize]
    Local Const $oconst = 0x5C, $iconst = 0x36
    Local $opad = Binary(''), $ipad = Binary('')
    If BinaryLen($key) > $blocksize Then $key = _Crypt_HashData($key, $CALG_SHA1)
    For $i = 1 To BinaryLen($key)
        $a_ipad[$i-1] = Number(BinaryMid($key, $i, 1))
        $a_opad[$i-1] = Number(BinaryMid($key, $i, 1))
    Next
    For $i = 0 To $blocksize - 1
        $a_opad[$i] = BitXOR($a_opad[$i], $oconst)
        $a_ipad[$i] = BitXOR($a_ipad[$i], $iconst)
    Next
    For $i = 0 To $blocksize - 1
        $ipad &= Binary('0x' & Hex($a_ipad[$i], 2))
        $opad &= Binary('0x' & Hex($a_opad[$i], 2))
    Next
    Return _Crypt_HashData($opad & _Crypt_HashData($ipad & $message, $CALG_SHA1), $CALG_SHA1)
EndFunc

Func _HMAC_MD5($key, $message)
    If Not IsBinary($key) Then $key = Binary($key)
    If Not IsBinary($message) Then $message = Binary($message)
    Local $blocksize = 64
    Local $a_opad[$blocksize], $a_ipad[$blocksize]
    Local Const $oconst = 0x5C, $iconst = 0x36
    Local $opad = Binary(''), $ipad = Binary('')
    If BinaryLen($key) > $blocksize Then $key = _Crypt_HashData($key, $CALG_MD5)
    For $i = 1 To BinaryLen($key)
        $a_ipad[$i-1] = Number(BinaryMid($key, $i, 1))
        $a_opad[$i-1] = Number(BinaryMid($key, $i, 1))
    Next
    For $i = 0 To $blocksize - 1
        $a_opad[$i] = BitXOR($a_opad[$i], $oconst)
        $a_ipad[$i] = BitXOR($a_ipad[$i], $iconst)
    Next
    For $i = 0 To $blocksize - 1
        $ipad &= Binary('0x' & Hex($a_ipad[$i], 2))
        $opad &= Binary('0x' & Hex($a_opad[$i], 2))
    Next
    Return _Crypt_HashData($opad & _Crypt_HashData($ipad & $message, $CALG_MD5), $CALG_MD5)
EndFunc

;; http://tools.ietf.org/html/rfc6238
Func _GenerateTOTP($key, $keyIsBase32 = True, $time = Default, $period = 30, $digits = 6)
    Local $DIGITS_POWER[9] = [1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000]
    ; time is some number of seconds
    If $time = Default Then $time = _GetUnixTimeUTC()
    $time = StringFormat("%016X", Floor($time / $period))
    If $keyIsBase32 Then
        $key = _Base32ToHex($key, True) ; return binary
    Else
        $key = StringToBinary($key)
    EndIf
    ; HMAC function expects binary arguments
    Local $hash = _HMAC_SHA1($key, Binary("0x" & $time))
    Local $offset = BitAND(BinaryMid($hash, BinaryLen($hash), 1), 0xf)
    Local $otp = BitOR(BitShift(BitAND(BinaryMid($hash, $offset + 1, 1), 0x7f), -24), _
            BitShift(BitAND(BinaryMid($hash, $offset + 2, 1), 0xff), -16), _
            BitShift(BitAND(BinaryMid($hash, $offset + 3, 1), 0xff), -8), _
            BitAND(BinaryMid($hash, $offset + 4, 1), 0xff) _
            )
    $otp = Mod($otp, $DIGITS_POWER[$digits])
    Return StringFormat("%0" & $digits & "i", $otp)
EndFunc

;; http://www.autoitscript.com/forum/topic/153617-seconds-since-epoch-aka-unix-timestamp/
Func _GetUnixTimeUTC()
    ; returns number of seconds since EPOCH in UTC
    Local $aSysTimeInfo = _Date_Time_GetTimeZoneInformation()
    Local $utcTime = ""
    Local $sDate = _NowCalc()
    If $aSysTimeInfo[0] = 2 Then
        $utcTime = _DateAdd('n', $aSysTimeInfo[1] + $aSysTimeInfo[7], $sDate)
    Else
        $utcTime = _DateAdd('n', $aSysTimeInfo[1], $sDate)
    EndIf
    Return _DateDiff('s', "1970/01/01 00:00:00", $utcTime)
EndFunc

;; http://tomeko.net/online_tools/base32.php?lang=en
Func _Base32ToHex($sInput, $returnBinary = False)
    $sInput = StringRegExpReplace(StringUpper($sInput), "[^A-Z2-7]", "")
    Local $key = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
    Local $buffer = 0, $bitsLeft = 0, $i = 0, $count = 0, $output = "", $val
    While $i < StringLen($sInput)
        $val = StringInStr($key, StringMid($sInput, $i + 1, 1)) - 1 ; StringInStr returns 1 as 1st position
        If $val >=0 And $val < 32 Then
            $buffer = BitOR(BitShift($buffer, -5), $val)
            $bitsLeft += 5
            If $bitsLeft >= 8 Then
                $output &= Chr(BitAND(BitShift($buffer, $bitsLeft - 8), 0xFF))
                $bitsLeft -= 8
            EndIf
        EndIf
        $i += 1
    WEnd
    If $bitsLeft > 0 Then
        $buffer = BitShift($buffer, -5)
        $output &= Chr(BitAND(BitShift($buffer, $bitsLeft - 3), 0xFF))
    EndIf
    If $returnBinary Then
        Return StringToBinary($output)
    Else
        Return $output
    EndIf
EndFunc

Const $OUTPUTFILENAME = "test.mp4"
Const $URL = "youtube-dlp.exe --username me --password blah --abort-on-error -f worst"

Local $sURL = InputBox("Link to video", "URL?", ClipGet())
if not $sURL Then Exit ConsoleWrite("Closed inputbox" & @CRLF)
$sURL = StringStripWS($sURL,$STR_STRIPLEADING + $STR_STRIPTRAILING)

Local $sCurrUnixTimeUTC = _GetUnixTimeUTC()
;_GenerateTOTP($key, $keyIsBase32 = True, $time = Default, $period = 30, $digits = 6)
Local $sToken = _GenerateTOTP("SECRET_KEY", True, $sCurrUnixTimeUTC)

Const $LINE = StringFormat($URL & " --twofactor %s -o %s %s",$sToken,$OUTPUTFILENAME,$sURL)
ClipPut($LINE)
ConsoleWrite($LINE & @CRLF)

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...