2022-10-07 15:45:45 -04:00

188 lines
6.6 KiB
JavaScript

"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.OAuth1Helper = void 0;
const crypto = __importStar(require("crypto"));
class OAuth1Helper {
constructor(options) {
this.nonceLength = 32;
this.consumerKeys = options.consumerKeys;
}
static percentEncode(str) {
return encodeURIComponent(str)
.replace(/!/g, '%21')
.replace(/\*/g, '%2A')
.replace(/'/g, '%27')
.replace(/\(/g, '%28')
.replace(/\)/g, '%29');
}
hash(base, key) {
return crypto
.createHmac('sha1', key)
.update(base)
.digest('base64');
}
authorize(request, accessTokens = {}) {
const oauthInfo = {
oauth_consumer_key: this.consumerKeys.key,
oauth_nonce: this.getNonce(),
oauth_signature_method: 'HMAC-SHA1',
oauth_timestamp: this.getTimestamp(),
oauth_version: '1.0',
};
if (accessTokens.key !== undefined) {
oauthInfo.oauth_token = accessTokens.key;
}
if (!request.data) {
request.data = {};
}
oauthInfo.oauth_signature = this.getSignature(request, accessTokens.secret, oauthInfo);
return oauthInfo;
}
toHeader(oauthInfo) {
const sorted = sortObject(oauthInfo);
let header_value = 'OAuth ';
for (const element of sorted) {
if (element.key.indexOf('oauth_') !== 0) {
continue;
}
header_value += OAuth1Helper.percentEncode(element.key) + '="' + OAuth1Helper.percentEncode(element.value) + '",';
}
return {
// Remove the last ,
Authorization: header_value.slice(0, header_value.length - 1),
};
}
getNonce() {
const wordCharacters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
let result = '';
for (let i = 0; i < this.nonceLength; i++) {
result += wordCharacters[Math.trunc(Math.random() * wordCharacters.length)];
}
return result;
}
getTimestamp() {
return Math.trunc(new Date().getTime() / 1000);
}
getSignature(request, tokenSecret, oauthInfo) {
return this.hash(this.getBaseString(request, oauthInfo), this.getSigningKey(tokenSecret));
}
getSigningKey(tokenSecret) {
return OAuth1Helper.percentEncode(this.consumerKeys.secret) + '&' + OAuth1Helper.percentEncode(tokenSecret || '');
}
getBaseString(request, oauthInfo) {
return request.method.toUpperCase() + '&'
+ OAuth1Helper.percentEncode(this.getBaseUrl(request.url)) + '&'
+ OAuth1Helper.percentEncode(this.getParameterString(request, oauthInfo));
}
getParameterString(request, oauthInfo) {
const baseStringData = sortObject(percentEncodeData(mergeObject(oauthInfo, mergeObject(request.data, deParamUrl(request.url)))));
let dataStr = '';
for (const { key, value } of baseStringData) {
// check if the value is an array
// this means that this key has multiple values
if (value && Array.isArray(value)) {
// sort the array first
value.sort();
let valString = '';
// serialize all values for this key: e.g. formkey=formvalue1&formkey=formvalue2
value.forEach((item, i) => {
valString += key + '=' + item;
if (i < value.length) {
valString += '&';
}
});
dataStr += valString;
}
else {
dataStr += key + '=' + value + '&';
}
}
// Remove the last character
return dataStr.slice(0, dataStr.length - 1);
}
getBaseUrl(url) {
return url.split('?')[0];
}
}
exports.OAuth1Helper = OAuth1Helper;
exports.default = OAuth1Helper;
// Helper functions //
function mergeObject(obj1, obj2) {
return {
...obj1 || {},
...obj2 || {},
};
}
function sortObject(data) {
return Object.keys(data)
.sort()
.map(key => ({ key, value: data[key] }));
}
function deParam(string) {
const splitted = string.split('&');
const data = {};
for (const coupleKeyValue of splitted) {
const [key, value = ''] = coupleKeyValue.split('=');
// check if the key already exists
// this can occur if the QS part of the url contains duplicate keys like this: ?formkey=formvalue1&formkey=formvalue2
if (data[key]) {
// the key exists already
if (!Array.isArray(data[key])) {
// replace the value with an array containing the already present value
data[key] = [data[key]];
}
// and add the new found value to it
data[key].push(decodeURIComponent(value));
}
else {
// it doesn't exist, just put the found value in the data object
data[key] = decodeURIComponent(value);
}
}
return data;
}
function deParamUrl(url) {
const tmp = url.split('?');
if (tmp.length === 1)
return {};
return deParam(tmp[1]);
}
function percentEncodeData(data) {
const result = {};
for (const key in data) {
let value = data[key];
// check if the value is an array
if (value && Array.isArray(value)) {
value = value.map(v => OAuth1Helper.percentEncode(v));
}
else {
value = OAuth1Helper.percentEncode(value);
}
result[OAuth1Helper.percentEncode(key)] = value;
}
return result;
}