193 строки
8.3 KiB
TypeScript
193 строки
8.3 KiB
TypeScript
///<reference path='refs.ts'/>
|
|
module TDev.RT {
|
|
//? OAuth 2.0 Access Token or Error as described in http://tools.ietf.org/html/rfc6749.
|
|
//@ stem("oauth res") serializable ctx(general,cloudfield,json)
|
|
export class OAuthResponse
|
|
extends RTValue
|
|
{
|
|
private _time: DateTime;
|
|
private _accessToken: string;
|
|
private _expiresIn: number;
|
|
private _scope: string;
|
|
private _error: string;
|
|
private _errorDescription: string;
|
|
private _errorUri: string;
|
|
private _others: StringMap;
|
|
|
|
|
|
// ctx is ignored
|
|
public exportJson(ctx: JsonExportCtx): any {
|
|
return {
|
|
time: this._time && this._time.exportJson(ctx),
|
|
accessToken: this._accessToken,
|
|
expiresIn: this._expiresIn,
|
|
scope: this._scope,
|
|
error: this._error,
|
|
errorDescription: this._errorDescription,
|
|
errorUri: this._errorUri,
|
|
others: this._others && this._others.exportJson(ctx),
|
|
}
|
|
}
|
|
|
|
public importJson(ctx: JsonImportCtx, json: any): RT.RTValue {
|
|
if (typeof json != "object") json = undefined;
|
|
this._time = ctx.importDateTime(json, "time");
|
|
this._accessToken = ctx.importString(json, "accessToken");
|
|
this._expiresIn = ctx.importNumber(json, "expiresIn");
|
|
this._scope = ctx.importString(json, "scope");
|
|
this._error = ctx.importString(json, "error");
|
|
this._errorDescription = ctx.importString(json, "errorDescription");
|
|
this._errorUri= ctx.importString(json, "errorUri");
|
|
this._others = ctx.importStringMap(json, this._others, "others");
|
|
return this;
|
|
}
|
|
|
|
static parseJSON(json: JsonObject): OAuthResponse {
|
|
var accessToken: string;
|
|
var expiresIn: number = 0;
|
|
var scope: string;
|
|
var isError = false;
|
|
var error: string;
|
|
var errorDescription: string;
|
|
var errorUri: string;
|
|
var others = Collections.create_string_map();
|
|
var keys = json.keys();
|
|
for (var i = 0; i < keys.count(); ++i) {
|
|
var key = keys.at(i);
|
|
var value = json.at(i);
|
|
switch (key) {
|
|
case "access_token": accessToken = value.to_string(); break;
|
|
case "expires_in": expiresIn = Math.floor(value.to_number() || -1); break;
|
|
case "scope": scope = value.to_string(); break;
|
|
case "error": error = value.to_string(); isError = true; break;
|
|
case "error_description": errorDescription = value.to_string(); break;
|
|
case "error_uri": errorUri = value.to_string(); break;
|
|
case "state": break;
|
|
default: others.set_at(key, value.to_string()); break;
|
|
}
|
|
}
|
|
|
|
if (!accessToken && !isError)
|
|
return undefined; // not a OAuth url
|
|
else if (accessToken && !isError)
|
|
return OAuthResponse.mkAccessToken(accessToken, expiresIn, scope, others);
|
|
else
|
|
return OAuthResponse.mkError(error, errorDescription, errorUri, others);
|
|
}
|
|
|
|
static parse(redirect_url: string): OAuthResponse {
|
|
var queryIndex = redirect_url.indexOf('?');
|
|
var markerIndex = redirect_url.indexOf('#', queryIndex + 1);
|
|
if (queryIndex < 0 && markerIndex < 0)
|
|
return undefined;
|
|
|
|
var query = queryIndex < 0 ? "" : redirect_url.substring(queryIndex + 1, markerIndex < 0 ? redirect_url.length : markerIndex);
|
|
var marker = markerIndex < 0 ? "" : redirect_url.substring(markerIndex + 1);
|
|
var args = query.split('&').concat(marker.split('&'));
|
|
var accessToken: string;
|
|
var expiresIn: number = 0;
|
|
var scope: string;
|
|
var isError = false;
|
|
var error: string;
|
|
var errorDescription: string;
|
|
var errorUri: string;
|
|
var others = Collections.create_string_map();
|
|
args.forEach((arg) => {
|
|
var ei = arg.indexOf('=');
|
|
if (ei > -1) {
|
|
var key = Web.url_decode(arg.substring(0, ei));
|
|
var value = Web.url_decode(arg.substring(ei + 1));
|
|
switch (key) {
|
|
case "access_token": accessToken = value; break;
|
|
case "expires_in": expiresIn = parseInt(value) || -1; break;
|
|
case "scope": scope = value; break;
|
|
case "error": error = value; isError = true; break;
|
|
case "error_description": errorDescription = value; break;
|
|
case "error_uri": errorUri = value; break;
|
|
case "state": break;
|
|
default: others.set_at(key, value); break;
|
|
}
|
|
}
|
|
});
|
|
|
|
if (!accessToken && !isError)
|
|
return undefined; // not a OAuth url
|
|
else if (accessToken && !isError)
|
|
return OAuthResponse.mkAccessToken(accessToken, expiresIn, scope, others);
|
|
else
|
|
return OAuthResponse.mkError(error, errorDescription, errorUri, others);
|
|
}
|
|
|
|
static mkAccessToken(accessToken: string, expiresIn: number, scope: string, others : StringMap = null) : OAuthResponse {
|
|
var r = new OAuthResponse();
|
|
r._time = Time.now();
|
|
r._accessToken = accessToken;
|
|
r._expiresIn = expiresIn || 0;
|
|
r._scope = scope;
|
|
r._others = others;
|
|
return r;
|
|
}
|
|
|
|
static mkError(error: string, errorDescription: string, errorUri: string, others : StringMap = null): OAuthResponse {
|
|
var r = new OAuthResponse();
|
|
r._time = Time.now();
|
|
r._error = error;
|
|
r._errorDescription = errorDescription;
|
|
r._errorUri = errorUri;
|
|
r._others = others;
|
|
return r;
|
|
}
|
|
|
|
public toString()
|
|
{
|
|
var s: string;
|
|
if (this._error)
|
|
s = this._error + ", " + (this._errorDescription || "no description") + ", " + (this._errorUri || "no error uri");
|
|
else
|
|
s = this._accessToken + ", " + this._expiresIn + ", " + (this._scope || "no scope");
|
|
if (this._others)
|
|
s += " ," + this._others.toString();
|
|
return s;
|
|
}
|
|
|
|
//? The access token issued by the authorization server.
|
|
public access_token(): string { return this._accessToken; }
|
|
|
|
//? (Optional) The lifetime in seconds of the access token.
|
|
public expires_in(): number { return this._expiresIn; }
|
|
|
|
//? (Optional) Optional if identical to the scope requested by the client; otherwise, the scope of the access token as described by Section 3.3 of the OAuth 2.0 specification.
|
|
public scope(): string { return this._scope; }
|
|
|
|
//? A single ASCII [USASCII] error code.
|
|
public error(): string { return this._error; }
|
|
|
|
//? (Optional) A human readable error code.
|
|
public error_description(): string { return this._errorDescription; }
|
|
|
|
//? (Optional) A URI identifying a human-readable web page with information about the error, used to provide the client developer with additional information about the error.
|
|
public error_uri(): string { return this._errorUri; }
|
|
|
|
//? (Optional) Additional key-value pairs not covered by the OAuth 2.0 specification.
|
|
public others(): StringMap
|
|
{
|
|
if (!this._others)
|
|
this._others = Collections.create_string_map();
|
|
return this._others;
|
|
}
|
|
|
|
//? (Optional) Indicates if the token might expire within the next seconds.
|
|
//@ [seconds].defl(100)
|
|
public is_expiring(seconds: number): boolean {
|
|
if (this.is_error()) return true;
|
|
return this._expiresIn > 0 && this._time.add_seconds(this._expiresIn + Math.max(0, seconds)).less(Time.now());
|
|
}
|
|
|
|
//? Indicates if this response is an error.
|
|
public is_error(): boolean { return !this._accessToken; }
|
|
|
|
//? Displays the response.
|
|
public post_to_wall(s:IStackFrame) : void { super.post_to_wall(s) }
|
|
}
|
|
}
|