twitch-auth
Advanced tools
Comparing version 1.0.1 to 1.0.2
{ | ||
"name": "twitch-auth", | ||
"version": "1.0.1", | ||
"version": "1.0.2", | ||
"description": "Utility module for handling Twitch.tv chatbot authentication.", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
246
README.md
@@ -45,1 +45,247 @@ # twitch-auth | ||
`creds` ...same as above. | ||
# example code | ||
This is basically what I use to launch my chat bot. | ||
It is derived from Twitch's echo/haiku sample and has been built up from there (with the twitch-auth module being refactored out of it). | ||
It uses a local Redis server to cache access/refresh tokens. Run it initially with `-c <auth code>` to get your first user access token. | ||
After that, it will automatically refresh tokens as necessary. | ||
``` | ||
#!/usr/bin/nodejs --harmony | ||
//---------------------------------------------------------------- | ||
'use strict'; | ||
//---------------------------------------------------------------- | ||
const process = require('process') | ||
const minimist = require('minimist') | ||
const fs = require('fs') | ||
const tmi = require('tmi.js') | ||
const redis = require('redis'); | ||
const util = require('util') | ||
// Twitch Auth Util (tau) | ||
const tau = require('twitch-auth') | ||
const defaultConfigPath = 'config.json'; | ||
const defaultConfig = { | ||
credsPath: './creds.json', | ||
reconnect: true | ||
}; | ||
//---------------------------------------------------------------- | ||
// Called every time a message comes in: | ||
function onMessageHandler(target, context, msg, self) { | ||
// Ignore messages from the bot | ||
if (self) { | ||
return; | ||
} | ||
console.log(msg); | ||
} | ||
function parseArgs(argv) { | ||
let args = minimist(argv.slice(2)); | ||
if (args['_'].length > 0) { | ||
args._.forEach((unknownOption) => { | ||
console.log(`I don't know what "${unknownOption}" is.`); | ||
}); | ||
return (null); | ||
} | ||
return (args); | ||
} | ||
function getConfigPath(args, defaultPath=defaultConfigPath) { | ||
if ('F' in args) { | ||
return (args['F']); | ||
} | ||
return (defaultPath); | ||
} | ||
function getConfig(args) { | ||
let configPath = getConfigPath(args); | ||
let config = defaultConfig; | ||
try { | ||
fs.accessSync(configPath, fs.constants.F_OK | fs.constants.R_OK); | ||
let configString = fs.readFileSync(configPath, 'utf8'); | ||
config = Object.assign(config, JSON.parse(configString)); | ||
} | ||
catch (err) { | ||
console.log(err); | ||
} | ||
return (config); | ||
} | ||
function getCreds(credsPath) { | ||
let credString = fs.readFileSync(credsPath, 'utf8'); | ||
return (JSON.parse(credString)); | ||
} | ||
function redisValue(redisClient, key) { | ||
return (new Promise((resolve, reject) => { | ||
redisClient.get(key, (err, result) => { | ||
console.log('redis client returned: ' + result); | ||
if (err) { | ||
reject(err); | ||
} | ||
resolve(result); | ||
}); | ||
})); | ||
} | ||
function accessTokenFromAuthCode(creds, code) { | ||
return (tau.getUserAccessToken(creds, code)); | ||
} | ||
function accessTokenFromCache() { | ||
//console.log('accessTokenFromCache()'); | ||
let redisClient = redis.createClient(); | ||
let tokens = Promise.all([ | ||
redisValue(redisClient, "access_token"), | ||
redisValue(redisClient, "refresh_token")]) | ||
.then((results) => { | ||
//console.log('results: ' + results); | ||
redisClient.end(); | ||
return ({access_token: results[0], | ||
refresh_token: results[1]}); | ||
}); | ||
return (tokens); | ||
} | ||
function cacheTokenResponse(response) { | ||
let redisClient = redis.createClient(); | ||
return (new Promise((resolve, reject) => { | ||
if (('access_token' in response ) && | ||
('refresh_token' in response)) { | ||
redisClient.mset('access_token', response.access_token, | ||
'refresh_token', response.refresh_token, (err, reply) => { | ||
console.log('redis client returned: ' + reply); | ||
redisClient.end(); | ||
if (err) { | ||
reject(err); | ||
} | ||
resolve(reply); | ||
}); | ||
} | ||
})); | ||
} | ||
function reconnect(context) { | ||
return (tau.refreshUserAccessToken(context.creds, context.tokens.refresh_token) | ||
.then((response) => { | ||
// Update the tokens in our context oject. | ||
context.tokens.access_token = response.access_token; | ||
context.tokens.refresh_token = response.refresh_token; | ||
return (response);}) | ||
.then(cacheTokenResponse) | ||
.then((reply) => { | ||
// reply is useless ("OK") | ||
console.log("let's try to reconnect..."); | ||
return (context);}) | ||
.then(serve)); | ||
} | ||
function getTwitchOptions(context) { | ||
let opts = { | ||
options: { | ||
clientId: context.creds.client_id, | ||
debug: true | ||
}, | ||
identity: { | ||
username: context.config.tmi.username, | ||
password: 'oauth:' + context.tokens.access_token | ||
}, | ||
channels: context.config.tmi.channels | ||
} | ||
return (opts); | ||
} | ||
function registerTwitchEventHandlers(client, context) { | ||
// Register our event handlers: | ||
client.on('message', onMessageHandler); | ||
client.on('disconnected', (reason) => { | ||
// Login authentication failed | ||
console.log(util.format('Disconnected: %s', reason)); | ||
reconnect(context) | ||
.catch((err) => { | ||
console.log(err); | ||
}); | ||
}); | ||
} | ||
function serve(context) { | ||
// Create a client with our tmi options: | ||
let opts = getTwitchOptions(context); | ||
let client = new tmi.client(opts); | ||
// Connect to Twitch: | ||
return (client.connect() | ||
.then((data) => { | ||
console.log(JSON.stringify(data)); | ||
registerTwitchEventHandlers(client, context); | ||
}, (err) => { | ||
// Reconnect is almost always necessary because auth tokens need to be refreshed often. | ||
console.log("It's okay, we probably just need to refresh the auth tokens."); | ||
reconnect(context) | ||
.catch((err) => { | ||
console.log('Uh oh, reconnection attempt failed. Maybe this error message will be helpful:\n' + err); | ||
}); | ||
})); | ||
} | ||
function launch(args) { | ||
let config = getConfig(args); | ||
let creds = getCreds(config.credsPath); | ||
let accessToken = Promise.resolve(); | ||
if ('c' in args) { | ||
let authCode = args['c']; | ||
accessToken = accessToken | ||
.then(function() { | ||
return (accessTokenFromAuthCode(creds, authCode)); | ||
}) | ||
.then((response) => { | ||
return (cacheTokenResponse(response)); | ||
}); | ||
} | ||
else { | ||
accessToken = accessToken | ||
.then(function() { | ||
return (accessTokenFromCache()); | ||
}); | ||
} | ||
// Inject other context. | ||
accessToken | ||
.then((tokens) => { | ||
let context = { | ||
config: config, | ||
creds: creds, | ||
tokens: tokens | ||
}; | ||
return (context);}) | ||
.then(serve) | ||
.catch((err) => { | ||
console.log(err); | ||
process.exit(1); | ||
}); | ||
} | ||
//---------------------------------------------------------------- | ||
launch(parseArgs(process.argv)); | ||
//---------------------------------------------------------------- | ||
``` |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
11101
291