Main /
GS-TW-Oauth1
Oauth1.gs
(function (host, expose) {
var module = { exports: {} };
var exports = module.exports;
/****** code begin *********/
/**
* Creates a new MemoryProperties, an implementation of the Properties
* interface that stores values in memory.
* @constructor
*/
var MemoryProperties = function() {
this.properties = {};
};
/**
* @see {@link https://developers.google.com/apps-script/reference/properties/properties#deleteallproperties}
*/
MemoryProperties.prototype.deleteAllProperties = function() {
this.properties = {};
};
/**
* @see {@link https://developers.google.com/apps-script/reference/properties/properties#deletepropertykey}
*/
MemoryProperties.prototype.deleteProperty = function(key) {
delete this.properties[key];
};
/**
* @see {@link https://developers.google.com/apps-script/reference/properties/properties#getkeys}
*/
MemoryProperties.prototype.getKeys = function() {
return Object.keys(this.properties);
};
/**
* @see {@link https://developers.google.com/apps-script/reference/properties/properties#getproperties}
*/
MemoryProperties.prototype.getProperties = function() {
return extend_({}, this.properties);
};
/**
* @see {@link https://developers.google.com/apps-script/reference/properties/properties#getproperty}
*/
MemoryProperties.prototype.getProperty = function(key) {
return this.properties[key];
};
/**
* @see {@link https://developers.google.com/apps-script/reference/properties/properties#setpropertiesproperties-deleteallothers}
*/
MemoryProperties.prototype.setProperties = function(properties, opt_deleteAllOthers) {
if (opt_deleteAllOthers) {
this.deleteAllProperties();
}
Object.keys(properties).forEach(function(key) {
this.setProperty(key, properties[key]);
});
};
/**
* @see {@link https://developers.google.com/apps-script/reference/properties/properties#setpropertykey-value}
*/
MemoryProperties.prototype.setProperty = function(key, value) {
this.properties[key] = String(value);
};
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview Contains the methods exposed by the library, and performs any
* required setup.
*/
/**
* Creates a new OAuth1 service with the name specified. It's usually best to
* create and configure your service once at the start of your script, and then
* reference it during the different phases of the authorization flow.
* @param {string} serviceName The name of the service.
* @return {Service_} The service object.
*/
function createService(serviceName) {
return new Service_(serviceName);
}
/**
* Returns the callback URL that will be used for a given script. Often this URL
* needs to be entered into a configuration screen of your OAuth provider.
* @param {string} scriptId The ID of your script, which can be found in the
* Script Editor UI under "File > Project properties".
* @return {string} The callback URL.
*/
function getCallbackUrl(scriptId) {
return Utilities.formatString(
'https://script.google.com/macros/d/%s/usercallback', scriptId);
}
if (typeof module != 'undefined') {
module.exports = {
createService: createService,
getCallbackUrl: getCallbackUrl,
MemoryProperties: MemoryProperties
};
}
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview Contains the Service_ class.
*/
// Disable JSHint warnings for the use of eval(), since it's required to prevent
// scope issues in Apps Script.
// jshint evil:true
/**
* Creates a new OAuth1 service.
* @param {string} serviceName The name of the service.
* @constructor
*/
var Service_ = function(serviceName) {
validate_({
'Service name': serviceName
});
this.serviceName_ = serviceName;
this.paramLocation_ = 'auth-header';
this.method_ = 'get';
this.oauthVersion_ = '1.0a';
this.scriptId_ = eval('Script' + 'App').getScriptId();
this.signatureMethod_ = 'HMAC-SHA1';
this.propertyStore_ = new MemoryProperties();
};
/**
* The maximum amount of time that information can be cached.
* @type {Number}
*/
Service_.MAX_CACHE_TIME = 21600;
/**
* Sets the request URL for the OAuth service (required).
* @param {string} url The URL given by the OAuth service provider for obtaining
* a request token.
* @return {Service_} This service, for chaining.
*/
Service_.prototype.setRequestTokenUrl = function(url) {
this.requestTokenUrl_ = url;
return this;
};
/**
* Sets the URL for the OAuth authorization service (required).
* @param {string} url The URL given by the OAuth service provider for
* authorizing a token.
* @return {Service_} This service, for chaining.
*/
Service_.prototype.setAuthorizationUrl = function(url) {
this.authorizationUrl_ = url;
return this;
};
/**
* Sets the URL to get an OAuth access token from (required).
* @param {string} url The URL given by the OAuth service provider for obtaining
* an access token.
* @return {Service_} This service, for chaining.
*/
Service_.prototype.setAccessTokenUrl = function(url) {
this.accessTokenUrl_ = url;
return this;
};
/**
* Sets the parameter location in OAuth protocol requests (optional). The
* default parameter location is 'auth-header'.
* @param {string} location The parameter location for the OAuth request.
* Allowed values are 'post-body', 'uri-query' and 'auth-header'.
* @return {Service_} This service, for chaining.
*/
Service_.prototype.setParamLocation = function(location) {
this.paramLocation_ = location;
return this;
};
/**
* Sets the HTTP method used to complete the OAuth protocol (optional). The
* default method is 'get'.
* @param {string} method The method to be used with this service. Allowed
* values are 'get' and 'post'.
* @return {Service_} This service, for chaining.
*/
Service_.prototype.setMethod = function(method) {
this.method_ = method;
return this;
};
/**
* Sets the OAuth realm parameter to be used with this service (optional).
* @param {string} realm The realm to be used with this service.
* @return {Service_} This service, for chaining.
*/
Service_.prototype.setRealm = function(realm) {
this.realm_ = realm;
return this;
};
/**
* Sets the OAuth signature method to use. 'HMAC-SHA1' is the default.
* @param {string} signatureMethod The OAuth signature method. Allowed values
* are 'HMAC-SHA1', 'RSA-SHA1' and 'PLAINTEXT'.
* @return {Service_} This service, for chaining.
*/
Service_.prototype.setSignatureMethod = function(signatureMethod) {
this.signatureMethod_ = signatureMethod;
return this;
};
/**
* Sets the specific OAuth version to use. The default is '1.0a'.
* @param {string} oauthVersion The OAuth version. Allowed values are '1.0a'
* and '1.0'.
* @return {Service_} This service, for chaining.
*/
Service_.prototype.setOAuthVersion = function(oauthVersion) {
this.oauthVersion_ = oauthVersion;
return this;
};
/**
* Sets the ID of the script that contains the authorization callback
* function (required). The script ID can be found in the Script Editor UI
* under "File > Project properties".
* @param {string} scriptId The ID of the script containing the callback
* function.
* @return {Service_} This service, for chaining.
* @deprecated The script ID is now be determined automatically.
*/
Service_.prototype.setScriptId = function(scriptId) {
this.scriptId_ = scriptId;
return this;
};
/**
* Sets the name of the authorization callback function (required). This is the
* function that will be called when the user completes the authorization flow
* on the service provider's website. The callback accepts a request parameter,
* which should be passed to this service's <code>handleCallback()</code> method
* to complete the process.
* @param {string} callbackFunctionName The name of the callback function.
* @return {Service_} This service, for chaining.
*/
Service_.prototype.setCallbackFunction = function(callbackFunctionName) {
this.callbackFunctionName_ = callbackFunctionName;
return this;
};
/**
* Sets the consumer key, which is provided when you register with an OAuth
* service (required).
* @param {string} consumerKey The consumer key provided by the OAuth service
* provider.
* @return {Service_} This service, for chaining.
*/
Service_.prototype.setConsumerKey = function(consumerKey) {
this.consumerKey_ = consumerKey;
return this;
};
/**
* Sets the consumer secret, which is provided when you register with an OAuth
* service (required).
* @param {string} consumerSecret The consumer secret provided by the OAuth
* service provider.
* @return {Service_} This service, for chaining.
*/
Service_.prototype.setConsumerSecret = function(consumerSecret) {
this.consumerSecret_ = consumerSecret;
return this;
};
/**
* Sets the property store to use when persisting credentials (optional). In
* most cases this should be user properties, but document or script properties
* may be appropriate if you want to share access across users. If not set tokens
* will be stored in memory only.
* @param {PropertiesService.Properties} propertyStore The property store to use
* when persisting credentials.
* @return {Service_} This service, for chaining.
*/
Service_.prototype.setPropertyStore = function(propertyStore) {
this.propertyStore_ = propertyStore;
return this;
};
/**
* Sets the cache to use when persisting credentials (optional). Using a cache
* will reduce the need to read from the property store and may increase
* performance. In most cases this should be a private cache, but a public cache
* may be appropriate if you want to share access across users.
* @param {CacheService.Cache} cache The cache to use when persisting
* credentials.
* @return {Service_} This service, for chaining.
*/
Service_.prototype.setCache = function(cache) {
this.cache_ = cache;
return this;
};
/**
* Sets the access token and token secret to use (optional). For use with APIs
* that support a 1-legged flow where no user interaction is required.
* @param {string} token The access token.
* @param {string} secret The token secret.
* @return {Service_} This service, for chaining.
*/
Service_.prototype.setAccessToken = function(token, secret) {
this.saveToken_({
public: token,
secret: secret,
type: 'access'
});
return this;
};
/**
* Starts the authorization process. A new token will be generated and the
* authorization URL for that token will be returned. Have the user visit this
* URL and approve the authorization request. The user will then be redirected
* back to your application using the script ID and callback function name
* specified, so that the flow may continue.
* @returns {string} The authorization URL for a new token.
*/
Service_.prototype.authorize = function() {
validate_({
'Authorization URL': this.authorizationUrl_
});
var token = this.getRequestToken_();
this.saveToken_(token);
var oauthParams = {
oauth_token: token.public
};
if (this.oauthVersion_ == '1.0') {
oauthParams.oauth_callback = this.getCallbackUrl();
}
return buildUrl_(this.authorizationUrl_, oauthParams);
};
/**
* Completes the OAuth1 flow using the request data passed in to the callback
* function.
* @param {Object} callbackRequest The request data recieved from the callback
* function.
* @return {boolean} True if authorization was granted, false if it was denied.
*/
Service_.prototype.handleCallback = function(callbackRequest) {
var requestToken = callbackRequest.parameter.oauth_token;
var verifier = callbackRequest.parameter.oauth_verifier;
var token = this.getToken_();
if (!token || (requestToken && requestToken != token.public)) {
throw 'Error handling callback: token mismatch';
}
if (this.oauthVersion_ == '1.0a' && !verifier) {
return false;
}
token = this.getAccessToken_(verifier);
this.saveToken_(token);
return true;
};
/**
* Determines if the service has access (has been authorized).
* @return {boolean} true if the user has access to the service, false
* otherwise.
*/
Service_.prototype.hasAccess = function() {
var token = this.getToken_();
return token && token.type == 'access';
};
/**
* Fetches a URL using the OAuth1 credentials of the service. Use this method
* the same way you would use `UrlFetchApp.fetch()`.
* @param {string} url The URL to fetch.
* @param {Object} params The request parameters. See the corresponding method
* in `UrlFetchApp`.
* @returns {UrlFetchApp.HTTPResponse} The response.
*/
Service_.prototype.fetch = function(url, params) {
if (!this.hasAccess()) {
throw 'Service not authorized.';
}
var token = this.getToken_();
return this.fetchInternal_(url, params, token);
};
/**
* Resets the service, removing access and requiring the service to be
* re-authorized.
*/
Service_.prototype.reset = function() {
validate_({
'Property store': this.propertyStore_
});
var key = this.getPropertyKey_();
this.propertyStore_.deleteProperty(key);
if (this.cache_) {
this.cache_.remove(key);
}
};
/**
* Get a new request token.
* @returns {Object} A request token.
*/
Service_.prototype.getRequestToken_ = function() {
validate_({
'Request Token URL': this.requestTokenUrl_,
'Method': this.method_,
});
var url = this.requestTokenUrl_;
var params = {
method: this.method_,
muteHttpExceptions: true
};
var oauthParams = {};
if (this.oauthVersion_ == '1.0a') {
oauthParams.oauth_callback = this.getCallbackUrl();
}
var response = this.fetchInternal_(url, params, null, oauthParams);
if (response.getResponseCode() >= 400) {
throw 'Error starting OAuth flow: ' + response.getContentText();
}
var token = this.parseToken_(response.getContentText());
token.type = 'request';
return token;
};
/**
* Get a new access token.
* @param {string} opt_verifier The value of the `oauth_verifier` URL parameter
* in the callback. Not used by OAuth version '1.0'.
* @returns {Object} An access token.
*/
Service_.prototype.getAccessToken_ = function(opt_verifier) {
validate_({
'Access Token URL': this.accessTokenUrl_,
'Method': this.method_
});
var url = this.accessTokenUrl_;
var params = {
method: this.method_,
muteHttpExceptions: true
};
var token = this.getToken_();
var oauthParams = {};
if (opt_verifier) {
oauthParams.oauth_verifier = opt_verifier;
}
var response = this.fetchInternal_(url, params, token, oauthParams);
if (response.getResponseCode() >= 400) {
throw 'Error completing OAuth flow: ' + response.getContentText();
}
token = this.parseToken_(response.getContentText());
token.type = 'access';
return token;
};
/**
* Makes a `UrlFetchApp` request using the optional OAuth1 token and/or
* additional parameters.
* @param {string} url The URL to fetch.
* @param {Object} params The request parameters. See the corresponding method
* in `UrlFetchApp`.
* @params {Object} opt_token OAuth token to use to sign the request (optional).
* @param {Object} opt_oauthParams Additional OAuth parameters to use when
* signing the request (optional).
* @returns {UrlFetchApp.HTTPResponse} The response.
*/
Service_.prototype.fetchInternal_ = function(url, params, opt_token,
opt_oauthParams) {
validate_({
'URL': url,
'OAuth Parameter Location': this.paramLocation_,
'Consumer Key': this.consumerKey_,
'Consumer Secret': this.consumerSecret_
});
params = params || {};
params.method = params.method || 'get';
var token = opt_token || null;
var oauthParams = opt_oauthParams || null;
var signer = new Signer({
signature_method: this.signatureMethod_,
consumer: {
public: this.consumerKey_,
secret: this.consumerSecret_
}
});
var request = {
url: url,
method: params.method
};
if (params.payload && (!params.contentType ||
params.contentType == 'application/x-www-form-urlencoded')) {
var data = params.payload;
if (typeof(data) == 'string') {
data = signer.deParam(data);
}
request.data = data;
}
oauthParams = signer.authorize(request, token, oauthParams);
if (this.realm_ != null) {
oauthParams.realm = this.realm_;
}
switch (this.paramLocation_) {
case 'auth-header':
params.headers =
assign_({}, params.headers, signer.toHeader(oauthParams));
break;
case 'uri-query':
url = buildUrl_(url, oauthParams);
break;
case 'post-body':
// Clone the payload.
params.payload = assign_({}, params.payload, oauthParams);
break;
default:
throw 'Unknown param location: ' + this.paramLocation_;
}
if (params.payload && (!params.contentType ||
params.contentType == 'application/x-www-form-urlencoded')) {
// Disable UrlFetchApp escaping and use the signer's escaping instead.
// This will ensure that the escaping is consistent between the signature and the request.
var payload = request.data;
payload = Object.keys(payload).map(function(key) {
return signer.percentEncode(key) + '=' + signer.percentEncode(payload[key]);
}).join('&');
params.payload = payload;
params.escaping = false;
}
return UrlFetchApp.fetch(url, params);
};
/**
* Parses the token from the response.
* @param {string} content The serialized token content.
* @return {Object} The parsed token.
* @private
*/
Service_.prototype.parseToken_ = function(content) {
var token = content.split('&').reduce(function(result, pair) {
var parts = pair.split('=');
result[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]);
return result;
}, {});
// Verify that the response contains a token.
if (!token.oauth_token) {
throw 'Error parsing token: key "oauth_token" not found';
}
// Set fields that the signing library expects.
token.public = token.oauth_token;
token.secret = token.oauth_token_secret;
return token;
};
/**
* Saves a token to the service's property store and cache.
* @param {Object} token The token to save.
* @private
*/
Service_.prototype.saveToken_ = function(token) {
validate_({
'Property store': this.propertyStore_
});
var key = this.getPropertyKey_();
var value = JSON.stringify(token);
this.propertyStore_.setProperty(key, value);
if (this.cache_) {
this.cache_.put(key, value, Service_.MAX_CACHE_TIME);
}
};
/**
* Gets the token from the service's property store or cache.
* @return {Object} The token, or null if no token was found.
* @private
*/
Service_.prototype.getToken_ = function() {
validate_({
'Property store': this.propertyStore_
});
var key = this.getPropertyKey_();
var token;
if (this.cache_) {
token = this.cache_.get(key);
}
if (!token) {
token = this.propertyStore_.getProperty(key);
}
if (token) {
if (this.cache_) {
this.cache_.put(key, token, Service_.MAX_CACHE_TIME);
}
return JSON.parse(token);
} else {
return null;
}
};
/**
* Generates the property key for this service.
* @return {string} The property key.
* @private
*/
Service_.prototype.getPropertyKey_ = function() {
return 'oauth1.' + this.serviceName_;
};
/**
* Gets a callback URL to use for the OAuth flow.
* @return {string} A callback URL.
*/
Service_.prototype.getCallbackUrl = function() {
validate_({
'Callback Function Name': this.callbackFunctionName_,
'Service Name': this.serviceName_,
'Script ID': this.scriptId_
});
var stateToken = eval('Script' + 'App').newStateToken()
.withMethod(this.callbackFunctionName_)
.withArgument('serviceName', this.serviceName_)
.withTimeout(3600)
.createToken();
return buildUrl_(getCallbackUrl(this.scriptId_), {
state: stateToken
});
};
// The MIT License (MIT)
//
// Copyright (c) 2014 Ddo
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/**
* A modified version of the oauth-1.0a javascript library:
* https://github.com/ddo/oauth-1.0a
* The cryptojs dependency was removed in favor of native Apps Script functions.
* A new parameter was added to authorize() for additional oauth params.
* Support for realm authorization parameter was added in toHeader().
*/
(function(global) {
/**
* 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) {
var sig = Utilities.computeHmacSignature(Utilities.MacAlgorithm.HMAC_SHA_1, base_string, key);
return Utilities.base64Encode(sig);
};
break;
case 'PLAINTEXT':
this.hash = function(base_string, key) {
return key;
};
break;
case 'RSA-SHA1':
this.hash = function(base_string, key) {
var sig = Utilities.computeRsaSignature(Utilities.RsaAlgorithm.RSA_SHA_1, base_string, key);
return Utilities.base64Encode(sig);
};
break;
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, opt_oauth_data) {
var oauth_data = {
oauth_consumer_key: this.consumer.public,
oauth_nonce: this.getNonce(),
oauth_signature_method: this.signature_method,
oauth_timestamp: this.getTimeStamp(),
oauth_version: this.version
};
if (opt_oauth_data) {
oauth_data = this.mergeObject(oauth_data, opt_oauth_data);
}
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 || '';
// Don't percent encode the signing key (PKCS#8 PEM private key) when using
// the RSA-SHA1 method. The token secret is never used with the RSA-SHA1
// method.
if (this.signature_method === 'RSA-SHA1') {
return this.consumer.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.replace(/\+/g, ' ').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 !== 'realm' && 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;
};
global.Signer = OAuth;
})(this);
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview Contains utility methods used by the library.
*/
/**
* Builds a complete URL from a base URL and a map of URL parameters.
* @param {string} url The base URL.
* @param {Object.<string, string>} params The URL parameters and values.
* @returns {string} The complete URL.
* @private
*/
function buildUrl_(url, params) {
var paramString = Object.keys(params).map(function(key) {
return encodeURIComponent(key) + '=' + encodeURIComponent(params[key]);
}).join('&');
return url + (url.indexOf('?') >= 0 ? '&' : '?') + paramString;
}
/**
* Validates that all of the values in the object are non-empty. If an empty
* value is found, and error is thrown using the key as the name.
* @param {Object.<string, string>} params The values to validate.
* @private
*/
function validate_(params) {
Object.keys(params).forEach(function(name) {
var value = params[name];
if (!value) {
throw new Error(name + ' is required.');
}
});
}
/**
* Polyfill for Object.assign, which isn't available on the legacy runtime.
* Not assigning to Object to avoid overwriting behavior in the parent
* script(s).
* @param {Object} target The target object to apply the sources’ properties to,
* which is returned after it is modified.
* @param {...Object} sources The source object(s) containing the properties you
* want to apply.
* @returns {Object} The target object.
* @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#Polyfill}
* @license Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/
*/
function assign_(target, varArgs) {
if (typeof Object.assign === 'function') {
return Object.assign.apply(null, arguments);
}
if (target === null || target === undefined) {
throw new TypeError('Cannot convert undefined or null to object');
}
var to = Object(target);
for (var index = 1; index < arguments.length; index++) {
var nextSource = arguments[index];
if (nextSource !== null && nextSource !== undefined) {
for (var nextKey in nextSource) {
// Avoid bugs when hasOwnProperty is shadowed
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
to[nextKey] = nextSource[nextKey];
}
}
}
}
return to;
}
/**
* Gets the time in seconds, rounded down to the nearest second.
* @param {Date} date The Date object to convert.
* @returns {Number} The number of seconds since the epoch.
* @private
*/
function getTimeInSeconds_(date) {
return Math.floor(date.getTime() / 1000);
}
/****** code end *********/
;(
function copy(src, target, obj) {
obj[target] = obj[target] || {};
if (src && typeof src === 'object') {
for (var k in src) {
if (src.hasOwnProperty(k)) {
obj[target][k] = src[k];
}
}
} else {
obj[target] = src;
}
}
).call(null, module.exports, expose, host);
}).call(this, this, "OAuth1");
///////////////////////
kode.gs
var CONSUMER_KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxxx';
var CONSUMER_SECRET = 'yyyyyyyyyyyyyyyyyyyyyyyyyyyyyy';
/**
* Authorizes and makes a request to the Twitter API.
*/
function run(yess) {
yess = ""
var service = getService();
if (service.hasAccess()) {
var url = 'https://api.twitter.com/1.1/statuses/update.json';
var payload = {
status: yess
};
var response = service.fetch(url, {
method: 'post',
muteHttpExceptions: true,
payload: payload
});
var result = JSON.parse(response.getContentText());
Logger.log(JSON.stringify(result, null, 2));
console.log(payload)
} else {
var authorizationUrl = service.authorize();
Logger.log('Open the following URL and re-run the script: %s',
authorizationUrl);
}
}
/**
* Reset the authorization state, so that it can be re-tested.
*/
function reset() {
var service = getService();
service.reset();
}
/**
* Configures the service.
*/
function getService() {
return OAuth1.createService('Twitter')
// Set the endpoint URLs.
.setAccessTokenUrl('https://api.twitter.com/oauth/access_token')
.setRequestTokenUrl('https://api.twitter.com/oauth/request_token')
.setAuthorizationUrl('https://api.twitter.com/oauth/authorize')
// Set the consumer key and secret.
.setConsumerKey(CONSUMER_KEY)
.setConsumerSecret(CONSUMER_SECRET)
// Set the name of the callback function in the script referenced
// above that should be invoked to complete the OAuth flow.
.setCallbackFunction('authCallback')
// Using a cache will reduce the need to read from
// the property store and may increase performance.
.setCache(CacheService.getUserCache())
// Set the property store where authorized tokens should be persisted.
.setPropertyStore(PropertiesService.getUserProperties());
}///////////////////////////
/**
* Handles the OAuth callback.
*/
function authCallback(request) {
var service = getService();
var authorized = service.handleCallback(request);
if (authorized) {
return HtmlService.createHtmlOutput('Success!');
} else {
return HtmlService.createHtmlOutput('Denied');
}
}///////////////////////
/////////////////////////////////
/////////////////////////////////
//update usercallback
//https://script.google.com/macros/d/***********/usercallback
//*** adalah id scriptnya