I use AdonisJS v4 and I want extend Ally, the auth extension of AdonisJS.
this._getAccessTokenUrl() parse this._baseSite + this._accessTokenUrl
But the endpoint URL of Bit.ly is https://bitly.com/, the authorize URL is oauth/authorize and the access token URL is https://api-ssl.bitly.com/oauth/access_token
/**
* Base url to be used for constructing
* google oauth urls.
*
* #attribute baseUrl
*
* #return {String}
*/
get baseUrl () {
return 'https://bitly.com/'
}
/**
* Relative url to be used for redirecting
* user.
*
* #attribute authorizeUrl
*
* #return {String} [description]
*/
get authorizeUrl () {
return 'oauth/authorize'
}
/**
* Relative url to be used for exchanging
* access token.
*
* #attribute accessTokenUrl
*
* #return {String}
*/
get accessTokenUrl () {
return 'https://api-ssl.bitly.com/oauth/access_token'
}
Authorize URL will be: https://bitly.com/oauth/authorize
And Access Token URL will be (incorrect): https://bitly.com/https://api-ssl.bitly.com/oauth/access_token
It's impossible to add Bitly in provider of Ally, could you help me please?
Related
Since Microsoft has announced that they are going to deprecate password auth for their SMTP services. I am trying to substitute Password Auth for javax.mail with OAuth. However, I am getting an exception with the message 535 5.7.3 Authentication unsuccessful [MN2PR04CA0023.namprd04.prod.outlook.com].
My code snippet looks like this right now:
/**
* Class for sending email notifications.
*/
public class MailClient {
/**
* Send email (SMTP)
*
* #param params Runtime Parameters
* #param durationString Formatted duration
* #param endTime Time at which the task completed
* #param totalJournals Number of Journals read
* #param totalLines Number of Journal Lines Written
* #param outputFileStored Was output file stored?
* #param refFileStored Was Org Ref file stored?
* #param checkpointStored Was timestamp checkpoint stored?
* #param errorFile Location of error file (null if no errors)
* #throws Exception
*/
public static void send(ArgParse params, String durationString, ZonedDateTime endTime, int totalJournals,
int totalLines, Boolean outputFileStored, Boolean refFileStored, Boolean checkpointStored, String errorFile)
throws Exception {
Properties properties = System.getProperties();
properties.setProperty("mail.smtp.host", params.smtpHost);
//properties.setProperty("mail.smtp.auth", "true");
properties.setProperty("mail.smtp.starttls.enable", "true");
properties.setProperty("mail.smtp.ssl.protocols", "TLSv1.2");
properties.setProperty("mail.smtp.port", Integer.toString(params.smtpPort));
// Old password auth
/*Session session = Session.getDefaultInstance(properties, new javax.mail.Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(params.smtpUsername, params.smtpPassword);
}
});*/
Session session = Session.getDefaultInstance(properties);
Multipart multipart = new MimeMultipart();
MimeMessage message = new MimeMessage(session);
MimeBodyPart messageBodyPart;
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String endTimeString = endTime.format(formatter), endDateString = endTimeString.split("T")[0];
String subject = "secure: Journal-DataWarehouse run [" + endDateString + "]", body = "<html>";
message.setFrom(new InternetAddress(params.mailFrom));
for(int i = 0; i < params.mailTo.length; i++)
message.addRecipient(Message.RecipientType.TO, new InternetAddress(params.mailTo[i]));
message.addHeader("Date", endTime.format(DateTimeFormatter.RFC_1123_DATE_TIME));
message.setSubject(subject);
if(errorFile != null) {
messageBodyPart = new MimeBodyPart();
DataSource source = new FileDataSource(errorFile);
messageBodyPart.setDataHandler(new DataHandler(source));
messageBodyPart.setFileName("error_logs.txt");
multipart.addBodyPart(messageBodyPart);
body += "<p style=\"font-family:monospace,garamond,serif;\"><b>WARNING: Program completed with errors, error_logs.txt attached.</b></p>";
}
body += "asOfEntryDateTime (Query Parameter): " + params.asOfEntryDateTime + "<br /></p>";
body += "</html>";
messageBodyPart = new MimeBodyPart();
messageBodyPart.setContent(body, "text/html");
multipart.addBodyPart(messageBodyPart);
message.setContent(multipart);
// Fetch OAuth token and send message. (New code)
MicrosoftAuth auth = new MicrosoftAuth();
String authToken = auth.getAccessToken();
SMTPTransport transport = new SMTPTransport(session, null);
transport.connect(params.smtpHost, params.username, null);
transport.issueCommand("AUTH XOAUTH2 " + new String(BASE64EncoderStream.encode(String.format("user=%s\1auth=Bearer %s\1\1", params.username, authToken).getBytes())), 235);
transport.sendMessage(message, message.getAllRecipients());
transport.close();
}
The MicrosoftAuth class uses msal4j.ConfidentialClientApplication to fetch Auth Token using the client ID and client secret.
I use this script to upload Data from Google Sheets. Its here some way, how to set max errors? I want to just ignore all errors and upload the Data no matter how much errors. I have lot of different big Tables and they are everytime another Format etc.
I'm able to load this Data correctly manually(i set simply 100 or 1000 Errors allowed). But this script run with autodetect:true and don't allow errors. Thanks
/**
* Function to run from the UI menu.
*
* Uploads the sheets defined in the active sheet into BigQuery.
*/
function runFromUI() {
// Column indices.
const SHEET_URL = 1;
const PROJECT_ID = 2;
const DATASET_ID = 3;
const TABLE_ID = 4;
const APPEND = 5;
const STATUS = 6;
// Get the data range rows, skipping the header (first) row.
let sheet = SpreadsheetApp.getActiveSheet();
let rows = sheet.getDataRange().getValues().slice(1);
// Run the sheetToBigQuery function for every row and write the status.
rows.forEach((row, i) => {
let status = sheetToBigQuery(
row[SHEET_URL],
row[PROJECT_ID],
row[DATASET_ID],
row[TABLE_ID],
row[APPEND],
);
sheet.getRange(i+2, STATUS+1).setValue(status);
});
}
/**
* Uploads a single sheet to BigQuery.
*
* #param {string} sheetUrl - The Google Sheet Url containing the data to upload.
* #param {string} projectId - Google Cloud Project ID.
* #param {string} datasetId - BigQuery Dataset ID.
* #param {string} tableId - BigQuery Table ID.
* #param {bool} append - Appends to BigQuery table if true, otherwise replaces the content.
*
* #return {string} status - Returns the status of the job.
*/
function sheetToBigQuery(sheetUrl, projectId, datasetId, tableId, append) {
try {
createDatasetIfDoesntExist(projectId, datasetId);
} catch (e) {
return `${e}: Please verify your "Project ID" exists and you have permission to edit BigQuery`;
}
let sheet;
try {
sheet = openSheetByUrl(sheetUrl);
} catch (e) {
return `${e}: Please verify the "Sheet URL" is pasted correctly`;
}
// Get the values from the sheet's data range as a matrix of values.
let rows = sheet.getDataRange().getValues();
// Normalize the headers (first row) to valid BigQuery column names.
// https://cloud.google.com/bigquery/docs/schemas#column_names
rows[0] = rows[0].map((header) => {
header = header.toLowerCase().replace(/[^\w]+/g, '_');
if (header.match(/^\d/))
header = '_' + header;
return header;
});
// Create the BigQuery load job config. For more information, see:
// https://developers.google.com/apps-script/advanced/bigquery
let loadJob = {
configuration: {
load: {
destinationTable: {
projectId: projectId,
datasetId: datasetId,
tableId: tableId
},
autodetect: true, // Infer schema from contents.
writeDisposition: append ? 'WRITE_APPEND' : 'WRITE_TRUNCATE',
}
}
};
// BigQuery load jobs can only load files, so we need to transform our
// rows (matrix of values) into a blob (file contents as string).
// For convenience, we convert the rows into a CSV data string.
// https://cloud.google.com/bigquery/docs/loading-data-local
let csvRows = rows.map(values =>
// We use JSON.stringify() to add "quotes to strings",
// but leave numbers and booleans without quotes.
// If a string itself contains quotes ("), JSON escapes them with
// a backslash as \" but the CSV format expects them to be
// escaped as "", so we replace all the \" with "".
values.map(value => JSON.stringify(value).replace(/\\"/g, '""'))
);
let csvData = csvRows.map(values => values.join(',')).join('\n');
let blob = Utilities.newBlob(csvData, 'application/octet-stream');
// Run the BigQuery load job.
try {
BigQuery.Jobs.insert(loadJob, projectId, blob);
} catch (e) {
return e;
}
Logger.log(
'Load job started. Click here to check your jobs: ' +
`https://console.cloud.google.com/bigquery?project=${projectId}&page=jobs`
);
// The status of a successful run contains the timestamp.
// return `Last run: ${new Date().setDate }`;
return `last run: ${Utilities.formatDate(new Date(), SpreadsheetApp.getActive().getSpreadsheetTimeZone(), "yyyy-MM-dd HH:mm") }`;
}
/**
* Creates a dataset if it doesn't exist, otherwise does nothing.
*
* #param {string} projectId - Google Cloud Project ID.
* #param {string} datasetId - BigQuery Dataset ID.
*/
function createDatasetIfDoesntExist(projectId, datasetId) {
try {
BigQuery.Datasets.get(projectId, datasetId);
} catch (err) {
let dataset = {
datasetReference: {
projectId: projectId,
datasetId: datasetId,
},
};
BigQuery.Datasets.insert(dataset, projectId);
Logger.log(`Created dataset: ${projectId}:${datasetId}`);
}
}
/**
* Opens the spreadsheet sheet (tab) with the given URL.
*
* #param {string} sheetUrl - Google Sheet Url.
*
* #returns {Sheet} - The sheet corresponding to the URL.
*
* #throws Throws an error if the sheet doesn't exist.
*/
function openSheetByUrl(sheetUrl) {
// Extract the sheet (tab) ID from the Url.
let sheetIdMatch = sheetUrl.match(/gid=(\d+)/);
let sheetId = sheetIdMatch ? sheetIdMatch[1] : null;
// From the open spreadsheet, get the sheet (tab) that matches the sheetId.
let spreadsheet = SpreadsheetApp.openByUrl(sheetUrl);
let sheet = spreadsheet.getSheets().filter(sheet => sheet.getSheetId() == sheetId)[0];
if (!sheet)
throw 'Sheet tab ID does not exist';
return sheet;
}
If you want to set the number of max errors, you can use the maxBadRecords parameter in your load configration. If you want to ignore errors altogether, you can set ignoreUnknownValues to true instead.
let loadJob = {
configuration: {
load: {
destinationTable: {
projectId: projectId,
datasetId: datasetId,
tableId: tableId
},
autodetect: true, // Infer schema from contents.
// maxBadRecords: 1000,
ignoreUnknownValues: true, // use one or the other
writeDisposition: append ? 'WRITE_APPEND' : 'WRITE_TRUNCATE',
}
}
};
References:
BigQuery v2 | Job Configuration Load
I'm trying to figure out how to generate absolute frontend page URLs from CLI/Scheduler context. I've created the following helper class:
class FrontendUrlProvider
{
/**
* #var ObjectManagerInterface
*/
private $objectManager;
/**
* #var LoggerInterface
*/
private $logger;
/**
* #param ObjectManagerInterface $objectManager
* #param LoggerInterface $logger
*/
public function __construct(ObjectManagerInterface $objectManager, LoggerInterface $logger)
{
$this->objectManager = $objectManager;
$this->initializeTimeTracker();
$this->logger = $logger;
}
/**
* #param int $pageId
* #param int $languageId
* #return Uri
*/
public function pageUrl($pageId, $languageId)
{
$url = '';
$this->logger->error('generating preview link');
try {
$this->initializeTypoScriptFrontend($pageId);
$this->setUpPageDomainIfCliContext($pageId);
$contentRenderer = $this->objectManager->get(ContentObjectRenderer::class);
$command = $this->linkCommand($pageId, $languageId);
$url = $contentRenderer->typoLink_URL($command);
$this->logger->error("preview link is: $url");
} catch (\Exception $exception) {
$this->logger->error($exception->getMessage());
$this->logger->error($exception->getTraceAsString());
}
return new Uri($url);
}
private function initializeTimeTracker()
{
if (!is_object($GLOBALS['TT'])) {
$GLOBALS['TT'] = new \TYPO3\CMS\Core\TimeTracker\NullTimeTracker();
}
}
/**
* #param int $pageId
*/
private function initializeTypoScriptFrontend($pageId)
{
if (isset($GLOBALS['TSFE']) && is_object($GLOBALS['TFSE'])) {
return;
}
$GLOBALS['TSFE'] = $this->objectManager->get(TypoScriptFrontendController::class, $GLOBALS['TYPO3_CONF_VARS'], $pageId, '');
$GLOBALS['TSFE']->sys_page = $this->objectManager->get(PageRepository::class);
$GLOBALS['TSFE']->sys_page->init(false);
$GLOBALS['TSFE']->tmpl = $this->objectManager->get(TemplateService::class);
$GLOBALS['TSFE']->tmpl->init();
$GLOBALS['TSFE']->connectToDB();
$GLOBALS['TSFE']->initFEuser();
$GLOBALS['TSFE']->determineId();
$GLOBALS['TSFE']->initTemplate();
$GLOBALS['TSFE']->getConfigArray();
}
/**
* #param int $pageId
*/
private function setUpPageDomainIfCliContext($pageId)
{
if (!isset($_SERVER['HTTP_HOST']) || !$_SERVER['HTTP_HOST']) {
$domainData = $GLOBALS['TSFE']->getDomainDataForPid($pageId);
if (is_array($domainData) && isset($domainData['domainName']) && !empty($domainData['domainName'])) {
$_SERVER['HTTP_HOST'] = $domainData['domainName'] ?: '';
}
}
}
/**
* #param int $pageId
* #param int $languageId
* #return array
*/
private function linkCommand($pageId, $languageId)
{
$languageQuery = http_build_query(['L' => $languageId], null, '&', PHP_QUERY_RFC3986);
return array(
'parameter' => $pageId,
'useCacheHash' => false,
'forceAbsoluteUrl' => true,
'linkAccessRestrictedPages' => true,
'additionalParams' => '&' . $languageQuery,
);
}
}
I'm at the point that it works fine in TYPO3 7 LTS, as long as there's a domain record for the root line.
However this same snippet doesn't work in TYPO3 8 LTS and I need it working for both 7 and 8 at the same time. Obviously, I have set the domain record on the root line in v8, I cleared all the caches, etc. but I can't get an absolute URL in place. I only get the relative URL. At this point I'm not that interested in realUrl or anything like that.
For TYPO3 7 I basically reverse engineered it but with TYPO3 8 it seems a bit more complicated. Do you know what can I do more to get the page frontend URL?
It seems that the issue was an internal cache of the GeneralUtility, which cached a null value for the HTTP_HOST of $_SERVER superglobal.
Therefore the following line from my example above had no effect
$_SERVER['HTTP_HOST'] = $domainData['domainName'] ?: '';
In order to make it work under the CLI/Scheduler scope I had to clear the internal cache of the GeneralUtility by calling
TYPO3\CMS\Core\Utility\GeneralUtility::flushInternalRuntimeCaches();
before making a call to $contentRenderer->typoLink_URL($command);
Now frontend URL generation works fine on both TYPO3 7 and 8 LTS.
https://wissen.netzhaut.de/typo3/extensionentwicklung/typolink-realurl-in-scheduler-tasks/
But really: I'd recommend using a curl call against a custom page which will deliver the link (sort of as a rest API) - because thereby you go around almost all issues - and there are more beyond not having tsfe (e.g. safePath \ images).
How can I get full local path of a resource:// type url (i.e. resource://gre/modules/Services.jsm)?
For chrome:// type I use the following code:
if ((/^(chrome):/.test(url)))
{
let ios = Components.classes['#mozilla.org/network/io-service;1'].getService(Components.interfaces["nsIIOService"]),
cr = Components.classes['#mozilla.org/chrome/chrome-registry;1'].getService(Components.interfaces["nsIChromeRegistry"]),
ph = Components.classes["#mozilla.org/network/protocol;1?name=file"].createInstance(Components.interfaces.nsIFileProtocolHandler);
url = cr.convertChromeURL(ios.newURI(url, "UTF-8", null)).spec;
if (!/^file:/.test(url))
url = "file://" + url;
url = ph.getFileFromURLSpec(url).path;
}
Any ideas?
Thank you.
resouce:// URIs are implemented by a nsISubstitutingProtocolHandler. It can be instantiated from
Components.classes["#mozilla.org/network/protocol;1?name=resource"].getService(Ci.nsISubstitutingProtocolHandler)
#the8472
Thank you very much!
Using that interface we can get full local path like so:
/**
* http://mxr.mozilla.org/mozilla-release/source/devtools/server/actors/script.js#2086
*
* Resolve a URI back to physical file.
*
* Of course, this works only for URIs pointing to local resources.
*
* #param aURI
* URI to resolve
* #return
* resolved nsIURI
*/
function resolveURIToLocalPath(aURI) {
let resolved;
switch (aURI.scheme) {
case "jar":
case "file":
return aURI;
case "chrome":
resolved = Cc["#mozilla.org/chrome/chrome-registry;1"].
getService(Ci.nsIChromeRegistry).convertChromeURL(aURI);
return resolveURIToLocalPath(resolved);
case "resource":
resolved = Cc["#mozilla.org/network/protocol;1?name=resource"].
getService(Ci.nsIResProtocolHandler).resolveURI(aURI);
aURI = Services.io.newURI(resolved, null, null);
return resolveURIToLocalPath(aURI);
default:
return null;
}
}
function getLocalPath(url)
{
let uri = null;
try
{
uri = resolveURIToLocalPath(ios.newURI(url, "UTF-8", null));
}
catch(e){}
return uri ? uri.spec : uri;
}
console.log(getLocalPath("resource://gre/modules/Services.jsm"));
It accepts url string with file://, chrome:// or resource:// scheme
resolveURIToLocalPath
I am getting an invalid signature error in woocommerce rest api. I am also using the oauth 1.0a script from ddo https://github.com/ddo/oauth-1.0a. I generated the api keys twice. Also removed the version parameter inside de oauth script like requested on the woocommerce rest api documentation http://woothemes.github.io/woocommerce-rest-api-docs/
url
test.dev/wc-api/v3/orders/line_items?oauth_consumer_key=ck_858f9cf8cda8085d5677b2b1d4c12d10897e9702&oauth_nonce=MyriSapnWSopIusSjjuqJ8PLi6RWr0L9&oauth_signature=VfgINTX1FWYu551%2FxlLfipFnDQ8%3D&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1443481966
error
{"errors":[{"code":"woocommerce_api_authentication_error","message":"Invalid Signature - provided signature does not match"}]}
js
var oauth = OAuth({
consumer: {
public: 'ck_858f9cf8cda8085d5677b2b1d4c12d10897e9702',
secret: 'cs_7f429ec99905bb444e290bd4852a0c0da2545b21 '
},
signature_method: 'HMAC-SHA1'
});
var request_data = {
url: 'http://test.dev/wc-api/v3/orders/line_items',
method: 'GET',
}
$http({
url: request_data.url,
method: request_data.get,
params: oauth.authorize(request_data)
}).then(function successCallback(response) {
console.log(response);
}, function errorCallback(response) {
console.log(response);
});;
I just noticed that your $http method is getting the value of request_data.get instead of request_data.method. I'm sure that's what you were overlooking lol
Fixed it by using a service from Abdul Ahmad: httpService.js
angular.module('httpService', []).factory('httpService', httpService);
httpService.$inject = ['$http', '$q'];
function httpService($http, $q) {
var methods = {
httpGet : 'GET',
httpPost : 'POST',
httpPut : 'PUT',
httpDelete : 'DELETE'
};
function baseGet(url) {
return $http.get(url).then(
function (result) {
return result.data;
},
function (result) {
return $q.reject(result);
}
);
}
function httpWithParams(url, method, params, data) {
return $http({
url: url,
method: method,
params: params,
data: data,
dataType: "json",
headers: {
"Content-Type": "application/json"
}
}).then(
function (result) {
return result.data;
},
function (result) {
return $q.reject(result);
}
);
}
function handleError(error) {
console.log(error);
}
return {
baseGet: baseGet,
httpWithParams: httpWithParams,
handleError: handleError,
methods: methods
}
}
And then used this:
var oauth = OAuth({
consumer: {
public: 'ck_000',
secret: 'cs_000'
},
signature_method: 'HMAC-SHA1'
});
function getMyData() {
var request_data = {
url: 'http://test.dev/wc-api/v3/products',
method: 'get',
}
return returnData = httpService.httpWithParams(request_data.url, request_data.method, oauth.authorize(request_data))
.then(function(data) {
return data;
}, function(data) {
httpService.handleError(data);
return data;
});
}
Made some modification in the oauth file:
if (typeof(module) !== 'undefined' && typeof(exports) !== 'undefined') {
module.exports = OAuth;
var CryptoJS = require("crypto-js");
}
/**
* Constructor
* #param {Object} opts consumer key and secret
*/
function OAuth(opts) {
if(!(this instanceof OAuth)) {
return new OAuth(opts);
}
if(!opts) {
opts = {};
}
if(!opts.consumer) {
throw new Error('consumer option is required');
}
this.consumer = opts.consumer;
this.signature_method = opts.signature_method || 'HMAC-SHA1';
this.nonce_length = opts.nonce_length || 32;
//this.version = opts.version || '1.0';
this.parameter_seperator = opts.parameter_seperator || ', ';
if(typeof opts.last_ampersand === 'undefined') {
this.last_ampersand = true;
} else {
this.last_ampersand = opts.last_ampersand;
}
switch (this.signature_method) {
case 'HMAC-SHA1':
this.hash = function(base_string, key) {
return CryptoJS.HmacSHA1(base_string, key).toString(CryptoJS.enc.Base64);
};
break;
case 'HMAC-SHA256':
this.hash = function(base_string, key) {
return CryptoJS.HmacSHA256(base_string, key).toString(CryptoJS.enc.Base64);
};
break;
case 'PLAINTEXT':
this.hash = function(base_string, key) {
return key;
};
break;
case 'RSA-SHA1':
throw new Error('oauth-1.0a does not support this signature method right now. Coming Soon...');
default:
throw new Error('The OAuth 1.0a protocol defines three signature methods: HMAC-SHA1, RSA-SHA1, and PLAINTEXT only');
}
}
/**
* OAuth request authorize
* #param {Object} request data
* {
* method,
* url,
* data
* }
* #param {Object} public and secret token
* #return {Object} OAuth Authorized data
*/
OAuth.prototype.authorize = function(request, token) {
var oauth_data = {
oauth_consumer_key: this.consumer.public,
oauth_timestamp: this.getTimeStamp(),
oauth_nonce: this.getNonce(),
oauth_signature_method: this.signature_method
//oauth_version: this.version
};
if(!token) {
token = {};
}
if(token.public) {
oauth_data.oauth_token = token.public;
}
if(!request.data) {
request.data = {};
}
oauth_data.oauth_signature = this.getSignature(request, token.secret, oauth_data);
return oauth_data;
};
/**
* Create a OAuth Signature
* #param {Object} request data
* #param {Object} token_secret public and secret token
* #param {Object} oauth_data OAuth data
* #return {String} Signature
*/
OAuth.prototype.getSignature = function(request, token_secret, oauth_data) {
return this.hash(this.getBaseString(request, oauth_data), this.getSigningKey(token_secret));
};
/**
* Base String = Method + Base Url + ParameterString
* #param {Object} request data
* #param {Object} OAuth data
* #return {String} Base String
*/
OAuth.prototype.getBaseString = function(request, oauth_data) {
return request.method.toUpperCase() + '&' + this.percentEncode(this.getBaseUrl(request.url)) + '&' + this.percentEncode(this.getParameterString(request, oauth_data));
};
/**
* Get data from url
* -> merge with oauth data
* -> percent encode key & value
* -> sort
*
* #param {Object} request data
* #param {Object} OAuth data
* #return {Object} Parameter string data
*/
OAuth.prototype.getParameterString = function(request, oauth_data) {
var base_string_data = this.sortObject(this.percentEncodeData(this.mergeObject(oauth_data, this.mergeObject(request.data, this.deParamUrl(request.url)))));
var data_str = '';
//base_string_data to string
for(var key in base_string_data) {
data_str += key + '=' + base_string_data[key] + '&';
}
//remove the last character
data_str = data_str.substr(0, data_str.length - 1);
return data_str;
};
/**
* Create a Signing Key
* #param {String} token_secret Secret Token
* #return {String} Signing Key
*/
OAuth.prototype.getSigningKey = function(token_secret) {
token_secret = token_secret || '';
if(!this.last_ampersand && !token_secret) {
return this.percentEncode(this.consumer.secret);
}
return this.percentEncode(this.consumer.secret) + '&' + this.percentEncode(token_secret);
};
/**
* Get base url
* #param {String} url
* #return {String}
*/
OAuth.prototype.getBaseUrl = function(url) {
return url.split('?')[0];
};
/**
* Get data from String
* #param {String} string
* #return {Object}
*/
OAuth.prototype.deParam = function(string) {
var arr = string.split('&');
var data = {};
for(var i = 0; i < arr.length; i++) {
var item = arr[i].split('=');
data[item[0]] = decodeURIComponent(item[1]);
}
return data;
};
/**
* Get data from url
* #param {String} url
* #return {Object}
*/
OAuth.prototype.deParamUrl = function(url) {
var tmp = url.split('?');
if (tmp.length === 1)
return {};
return this.deParam(tmp[1]);
};
/**
* Percent Encode
* #param {String} str
* #return {String} percent encoded string
*/
OAuth.prototype.percentEncode = function(str) {
return encodeURIComponent(str)
.replace(/\!/g, "%21")
.replace(/\*/g, "%2A")
.replace(/\'/g, "%27")
.replace(/\(/g, "%28")
.replace(/\)/g, "%29");
};
/**
* Percent Encode Object
* #param {Object} data
* #return {Object} percent encoded data
*/
OAuth.prototype.percentEncodeData = function(data) {
var result = {};
for(var key in data) {
result[this.percentEncode(key)] = this.percentEncode(data[key]);
}
return result;
};
/**
* Get OAuth data as Header
* #param {Object} oauth_data
* #return {String} Header data key - value
*/
OAuth.prototype.toHeader = function(oauth_data) {
oauth_data = this.sortObject(oauth_data);
var header_value = 'OAuth ';
for(var key in oauth_data) {
if (key.indexOf('oauth_') === -1)
continue;
header_value += this.percentEncode(key) + '="' + this.percentEncode(oauth_data[key]) + '"' + this.parameter_seperator;
}
return {
Authorization: header_value.substr(0, header_value.length - this.parameter_seperator.length) //cut the last chars
};
};
/**
* Create a random word characters string with input length
* #return {String} a random word characters string
*/
OAuth.prototype.getNonce = function() {
var word_characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
var result = '';
for(var i = 0; i < this.nonce_length; i++) {
result += word_characters[parseInt(Math.random() * word_characters.length, 10)];
}
return result;
};
/**
* Get Current Unix TimeStamp
* #return {Int} current unix timestamp
*/
OAuth.prototype.getTimeStamp = function() {
return parseInt(new Date().getTime()/1000, 10);
};
////////////////////// HELPER FUNCTIONS //////////////////////
/**
* Merge object
* #param {Object} obj1
* #param {Object} obj2
* #return {Object}
*/
OAuth.prototype.mergeObject = function(obj1, obj2) {
var merged_obj = obj1;
for(var key in obj2) {
merged_obj[key] = obj2[key];
}
return merged_obj;
};
/**
* Sort object by key
* #param {Object} data
* #return {Object} sorted object
*/
OAuth.prototype.sortObject = function(data) {
var keys = Object.keys(data);
var result = {};
keys.sort();
for(var i = 0; i < keys.length; i++) {
var key = keys[i];
result[key] = data[key];
}
return result;
};