mTwitch.OAuth.mrc

By SReject on Aug 28, 2015

version: 0000.0000.0003

Moved to GitHub

I've moved this project to github in hopes of alleviating some of the headaches caused by maintaining 5+ pages for what is essentially the same project. I also hope the move will motivate others to get involved and contribute to the codebase

About

This is an mTwitch module that generates a full-access token for a twitch account to allow mIRC full management of the account.

Usage

After loading the script will popup a configuration dialog asking for a Twitch App Redirect URI, Twich App Client Id and Twitch App Secret. You must create your own Twitch App and use the values from it.

Once configured, from within mIRC, you can use /mTwitch.OAuth.Generate to generate a new OAuth token for the currently logged in Twitch account. This token can then supplement any other OAuth token for the account such as the one used to login to chat(prefix it with "oauth:")

Plans

Store OAuth tokens generated from such for each account to by used by potential future modules

Code

on *:LOAD:{
  if ($isfile($scriptdirmTwitch.OAuth.dat)) .remove $qt($scriptdirmTwitch.OAuth.dat)
  if ($hget(mTwitch.OAuth)) hfree $v1
  mTwitch.OAuthConfig
}
on *:START:{
  hmake mTwitch.OAuth 1
  if ($isfile($scriptdirmTwitch.OAuth.dat)) {
    hload mTwitch.OAuth $qt($scriptdirmTwitch.OAuth.dat)
  }
}
alias mTwitch.OAuthConfig {
  dialog -m mTwitch.OAuth mTwitch.OAuth
}
dialog -l mTwitch.OAuth {
  title "mTwitch OAuth Token Config"
  size -1 -1 376 376
  option pixels
  text "For mTwitch OAuth token generator to function you will need to create a", 1, 5 6 365 16
  link "Twitch App", 2, 5 22 55 16
  text "(use 'http://localhost' as the Redirect URI) and then fill in the", 3, 61 22 309 16
  text "following details about your app:", 4, 5 38 365 16
  box "App Redirect URI", 8, 5 63 365 115
  text "The Redirect URI specified when creating your Twitch App. If the default web-access port(80) is in use by another application on your machine, you may use 'http://localhost:PORT' (where port is the port number) in your twitch app instead", 9, 20 83 335 55
  edit "", 10, 20 144 335 21
  box "App Client Id", 11, 5 178 365 75
  text "The Client Id given to you by twitch after creating your app", 12, 20 198 335 16
  edit "", 13, 20 218 335 21
  box "App Secret", 14, 5 253 365 87
  text "The Secret given to you by twitch after creating your app and clicking 'New Secret'", 15, 20 273 335 32
  edit "", 16, 20 306 335 21
  button "Save", 17, 215 343 75 25
  button "Cancel", 18, 294 343 75 25, ok cancel
}
on *:DIALOG:mTwitch.OAuth:init:0:{
  if ($hget(mTwitch.OAuth)) {
    if ($hget(mTwitch.OAuth, app_uri)) did -ra $dname 10 $v1
    if ($hget(mTwitch.OAuth, app_clientid)) did -ra $dname 13 $v1
    if ($hget(mTwitch.OAuth, app_secret)) did -ra $dname 16 $v1
  }
  did -f $dname 10
}
on *:DIALOG:mTwitch.OAuth:sclick:2:{
  run http://www.twitch.tv/kraken/oauth2/clients/new
}
on *:DIALOG:mTwitch.OAuth:sclick:17:{
  if (!$regex($did($dname, 10).text, /^http:\/\/localhost(?::\d+)?$/)) {
    did -f $dname 10
    noop $input(The specified Twitch App Redirect URI is invalid; please try again, o, Invalid App URI)
  }
  elseif (!$regex($did($dname, 13).text, /^(?:[a-z\d]{30,32})$/i)) {
    did -f $dname 13
    noop $input(The specified Twitch App Client Id is invalid; please try again, o, Invalid App Client Id)
  }
  elseif (!$regex($did($dname, 16).text, /^(?:[a-z\d]{30,32})$/i)) {
    did -f $dname 16
    noop $input(The specified Twitch App Secret Key is invalid; please try again, o, Invalid App Secret Key)
  }
  else {
    if ($hget(mTwitch.OAuth)) hfree mTwitch.OAuth
    hadd -m mTwitch.OAuth app_uri $did($dname, 10).text
    hadd -m mTwitch.OAuth app_clientid $did($dname, 13).text
    hadd -m mTwitch.OAuth app_secret $did($dname, 16).text
    if ($isfile($scriptdirmTwitch.OAuth.dat)) .remove $qt($scriptdirmTwitch.OAuth.dat)
    hsave mTwitch.OAuth $qt($scriptdirmTwitch.OAuth.dat)
    dialog -x $dname
  }
}
alias mTwitch.OAuth.Generate {
  var %uri = $hget(mTwitch.OAuth, app_uri)
  var %clientId = $hget(mTwitch.OAuth, app_clientId)
  var %secret = $hget(mTwitch.OAuth, app_secret)
  var %err, %port = 80, %url
  if (!$len(%uri)) {
    %err = Twitch App Redirect URI not specified
  }
  elseif (!$regex(%uri, /^http:\/\/localhost(?::\d+)?$/)) {
    %err = Specified Twitch App Redirect URI invalid
  }
  elseif (!$len(%clientId)) {
    %err = Twitch App Client Id not specified
  }
  elseif (!$regex(%clientId, /^(?:[a-z\d]{30,32})$/i)) {
    %err = Specified Twitch App Client Id invalid
  }
  elseif (!$len(%secret)) {
    %err = Twitch App Secret not specified
  }
  elseif (!$regex(%secret, /^(?:[a-z\d]{30,32})$/i)) {
    %err = Specified Twitch App Secret invalid
  }
  elseif ($sock(mTwitch.OAuth.Listener)) {
    %err = mTwitch OAuth listening socket in use
  }
  else {
    if ($regex(%uri,/:(\d+)$/)) {
      %port = $regml(1)
    }
    if (%port !isnum 1-65535) {
      %err = Specified Twitch App Redirect Port invalid; must be a numerical value between 1 and 65535 (inclusive)
    }
    elseif (!$portfree(%port)) {
      %err = Specified Twitch app Redirect port in use; please close all programs that make use of port %port
    }
  }
  :error
  %err = $iif($error, $v1, %err)
  if (%err) {
    echo $color(info) -a [mTwitch->OAuth] %err
  }
  else {
    %uri = $urlencode(%uri)
    socklisten mTwitch.OAuth.Listener %port
    sockmark mTwitch.OAuth.Listener %clientId %secret %uri
    %url = https://api.twitch.tv/kraken/oauth2/authorize?response_type=code
    %url = %url $+ &scope=user_read+user_blocks_edit+user_blocks_read+user_follows_edit+user_subscriptions+channel_read+channel_editor+channel_commercial+channel_stream+channel_subscriptions+channel_check_subscription+chat_login
    %url = %url $+ &redirect_uri= $+ %uri
    %url = %url $+ &client_id= $+ %clientId
    run %url
    $+(.timer, mTwitch.OAuth.Listener) -oi 1 30 cleanup mTwitch.OAuth.Listener
  }
}
on *:SOCKLISTEN:mTwitch.OAuth.Listener:{
  if ($sockerr) {
    echo $color(info) -a [mTwitch->OAuth] Sock Listen Error
  }
  else {
    var %sock = 1
    while ($sock(mTwitch.OAuth.Client $+ %sock)) inc %sock
    %sock = mTwitch.OAuth.Client $+ %sock
    sockaccept %sock
    sockmark %sock $sock($sockname).mark
    $+(.timer, %sock) -io 1 30 cleanup %sock
  }
}
on *:SOCKWRITE:mTwitch.OAuth.Client*:{
  if ($sockerr) {
    cleanup $sockname
    echo $color(info) -a [mTwitch->OAuth] Unable to send data to connected client
  }
  elseif (!$sock($sockname).rq && $sock($sockname).mark === closing) {
    cleanup $sockname
  }
}
on *:SOCKREAD:mTwitch.OAuth.Client*:{
  var %w = sockwrite -n $sockname, %headers, %request, %body
  if ($sockerr) {
    cleanup $sockname
    echo $color(info) -a [mTwitch->OAuth] Client sockread error
  }
  elseif ($sock($sockname).mark !== closing) {
    noop $hget($sockname, readBuffer, &buffer)
    sockread $sock($sockname).rq &read
    bcopy -c &buffer $calc($bvar(&buffer, 0) + 1) &read 1 -1
    %headers = $bfind(&buffer, 1, $crlf $+ $crlf)
    %request = $bfind(&buffer, 1, $crlf)
    if (!%headers) {
      hadd -mb $sockname readBuffer &buffer
      return
    }
    elseif ($calc(%headers + 3) < $bvar(&buffer, 0)) {
      %w HTTP 400 BAD_REQUEST
      %w Connection: close
      %w
    }
    elseif (!%request || %request == %headers || %request > 4000) {
      %w HTTP 400 BAD_REQUEST
      %w Connection: close
      %w
    }
    elseif (!$regex(request, $bvar(&buffer, 1, $calc(%request - 1)).text, ^GET (\S+) HTTP\/\d+\.\d+$)) {
      %w HTTP 400 BAD_REQUEST
      %w Connection: close
      %w
    }
    elseif ($left($regml(request, 1), 2) !== /?) {
      %w HTTP 404 NOT_FOUND
      %w Connection: close
      %w
    }
    elseif (!$regex(code, $regml(request, 1), [\?&]code=([a-zA-Z\d]{30,})(?:\?|&|$) )) {
      %w HTTP 400 BAD_REQUEST
      %w Connection: close
      %w
    }
    else {
      cleanup mTwitch.OAuth.Listener
      %w HTTP 200 OK
      %w Connection: close
      %w Content-Type: text/plain
      %w
      %w All Good! You may close this window/tab now.
      tokenize 32 $sock($sockname).mark
      %body = grant_type=authorization_code&client_id= $+ $1 $+ &client_secret= $+ $2 $+ &redirect_uri= $+ $3 $+ &code= $+ $regml(code, 1)
      JSONOpen -uw mTwitchOAuthVerify https://api.twitch.tv/kraken/oauth2/token
      JSONUrlMethod mTwitchOAuthVerify POST
      JSONUrlHeader mTwitchOAuthVerify Content-Length $len(%body)
      JSONUrlGet mTwitchOAuthVerify %body
      if (!$JSONError && $JSON(mTwitchOAuthVerify, access_token) && !$JSONError) {
        echo $color(info) -a [mTwitch->OAuth] OAuth Token: $JSON(mTwitchOAuthVerify, access_token)
      }
      else {
        echo $color(info) -a [mTwitch->OAuth] An error occured while verifying the returned access code
      }
      JSONClose mTwitchOAuthVerify
    }
    sockmark $sockname closing
  }
}
on *:SOCKCLOSE:mTwitch.OAuth.Client*:{
  cleanup $sockname
  if ($sockerr) {
    echo $color(info) -a [mTwitch->OAuth] Client disconnected unexpectedly
  }
}
alias -l urlencode return $regsubex($1-, /([^a-z\d])/g, % $+ $base($asc(\t), 10, 16, 2))
alias -l cleanup {
  if ($sock($1)) sockclose $v1
  if ($hget($1)) hfree $v1
  if ($timer($1)) $+(.timer, $1) off
}
alias mTwitch.has.OAuth return 0000.0000.0003

Updates

v0.0.0003: Checks if port is in use before attempting to listen for connections

Comments

Sign in to comment.
Are you sure you want to unfollow this person?
Are you sure you want to delete this?
Click "Unsubscribe" to stop receiving notices pertaining to this post.
Click "Subscribe" to resume notices pertaining to this post.