@tidecloak/js
Version:
TideCloak client side JS SDK
140 lines • 7.08 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Doken = Doken;
const index_js_1 = require("../index.js");
const BaseComponent_js_1 = require("../Cryptide/Components/BaseComponent.js");
const Ed25519Components_js_1 = require("../Cryptide/Components/Schemes/Ed25519/Ed25519Components.js");
const Serialization_js_1 = require("../Cryptide/Serialization.js");
const TideKey_js_1 = __importDefault(require("../Cryptide/TideKey.js"));
const Utils_js_1 = require("../Tools/Utils.js");
/**
*
* @param {string} data
*/
function Doken(data) {
if (!(this instanceof Doken)) {
throw new Error("The 'Doken' constructor must be invoked with 'new'.");
}
let doken = this;
const parts = data.split(".");
if (parts.length != 3)
throw Error("Doken must be a 3 part token (including signature)");
doken.dataRef = data.slice(0);
doken.header = JSON.parse((0, Serialization_js_1.StringFromUint8Array)((0, Serialization_js_1.base64ToBytes)((0, Serialization_js_1.base64UrlToBase64)(parts[0]))));
doken.payload = new DokenPayload(JSON.parse((0, Serialization_js_1.StringFromUint8Array)((0, Serialization_js_1.base64ToBytes)((0, Serialization_js_1.base64UrlToBase64)(parts[1])))));
doken.signature = (0, Serialization_js_1.base64ToBytes)((0, Serialization_js_1.base64UrlToBase64)(parts[1]));
doken.isExpired = function () {
return this.payload.exp < (0, Utils_js_1.CurrentTime)();
};
doken.setNewSessionKey = function (sessionKey) {
const temp = doken.dataRef.split(".");
let payload = (0, Serialization_js_1.StringFromUint8Array)((0, Serialization_js_1.base64ToBytes)((0, Serialization_js_1.base64UrlToBase64)(parts[1])));
payload = payload.replace(/("t.ssk"\s*:\s*)"[^"]*"/, `$1"${sessionKey}"`);
// WE DO ALL THESE MANUAL UPDATES BECAUSE JAVASCRIPT DOES NOT GUARANTEE ORDER IN JSON
// SINCE WE DON'T SEND THE DOKEN TO GET SIGNED, WE CONTRCUST THE MESSAGE HERE
// WE NEED TO ENSURE ITS THE SAME THING THE ORK SIGNS
doken.dataRef = temp[0] + "." + (0, Serialization_js_1.base64ToBase64Url)((0, Serialization_js_1.bytesToBase64)((0, Serialization_js_1.StringToUint8Array)(payload))) + (temp.length > 2 ? "." + temp[2] : ""); // update encoded string
doken.payload.sessionKey = BaseComponent_js_1.BaseComponent.DeserializeComponent(sessionKey); // update session key object in payload
};
doken.setNewSignature = function (sig) {
doken.signature = sig.slice(); // update sig object
const temp = doken.dataRef.split(".");
doken.dataRef = temp[0] + "." + temp[1] + "." + (0, Serialization_js_1.base64ToBase64Url)((0, Serialization_js_1.bytesToBase64)(doken.signature)); // update dataref object
};
/**
*
* @param {TideKey} sessionKeyToCheck
*/
doken.validate = function (sessionKeyToCheck = null) {
// When an error is thrown - its a criticial error so the whole page should stop
// But if validation just fails, then we return false with a reason why
if (doken.header.alg != "EdDSA")
throw Error("Doken header alg expected to be EdDSA but got " + header.alg);
if (doken.header.typ != "doken")
throw Error("Doken header typ expected to be doken but got " + header.typ);
// Check expiry
if (index_js_1.Utils.CurrentTime() > doken.payload.exp)
return { success: false, reason: "expired" };
// Check session key matches
if (sessionKeyToCheck) {
if (!sessionKeyToCheck.get_public_component().Equals(doken.payload.sessionKey))
return { success: false, reason: `sessionkey mismatch. actual: ${sessionKeyToCheck.get_public_component().Serialize().ToString()}. expected: ${doken.payload.sessionKey.Serialize().ToString()}` };
}
return { success: true };
};
/**
*
* @param {Ed25519PublicComponent} vendorPublic
*/
doken.verify = async function (vendorPublic) {
return new TideKey_js_1.default(vendorPublic).verify((0, Serialization_js_1.StringToUint8Array)(this.dataRef), this.signature);
};
/**
*
* @returns {string}
*/
doken.serialize = function () {
return doken.dataRef;
};
class DokenPayload {
constructor(json) {
var s = BaseComponent_js_1.BaseComponent.DeserializeComponent(json["t.ssk"]);
if (s instanceof Ed25519Components_js_1.Ed25519PublicComponent) {
this.sessionKey = s;
}
else
throw Error("Unexpected session key type");
var u = BaseComponent_js_1.BaseComponent.DeserializeComponent(json["tideuserkey"]);
if (u instanceof Ed25519Components_js_1.Ed25519PublicComponent) {
this.tideuserkey = u;
}
else
throw Error("Unexpected tide user key type");
if (typeof json.vuid === "string")
this.vuid = json.vuid;
else
throw Error("Expected vuid to be string");
if (typeof json["t.uho"] === "string")
this.homeOrk = json["t.uho"];
else
throw Error("Expected user home to be string");
// Will be affected by 2032 problem
if (typeof json.exp === "number")
this.exp = json.exp;
else
throw Error("Expected exp to be a number");
if (typeof json.aud === "string")
this.aud = json.aud;
else
throw Error("Expected aud to be string");
if (typeof json.realm_access === "object")
this.realm_access = json.realm_access;
else if (!json.realm_access)
this.realm_access = null;
else
throw Error("Expected realm_access to be string");
if (typeof json.resource_access === "object")
this.resource_access = json.resource_access;
else if (!json.resource_access)
this.resource_access = null;
else
throw Error("Expected resource_access to be string");
}
serialize() {
return ("{" +
`\"t.ssk\":\"${this.sessionKey.Serialize().ToString()}\",` +
`"\"tideuserkey\":\"${this.tideuserkey.Serialize().ToString()}\",` +
`\"vuid\":\"${this.vuid}\",` +
(this.homeOrk ? `\"t.uho\":\"${this.homeOrk}\",` : "") +
`\"exp\":${this.exp},` +
`\"aud\":\"${this.aud}\"` + // vvkid
(this.realm_access ? `,\"realm_access\":${JSON.stringify(this.realm_access)}` : "") +
(this.resource_access ? `,\"resource_access\":${JSON.stringify(this.resource_access)}` : "") +
"}");
}
}
}
//# sourceMappingURL=Doken.js.map