tidecloak-js
Version:
TideCloak client side JS SDK
180 lines (161 loc) • 6.09 kB
JavaScript
import { GetValue, StringFromUint8Array } from "../Cryptide/Serialization.js";
import InitializationCertificate from "./InitializationCertificate.js";
import RuleSettings from "./Rules/RuleSettings.js";
import CardanoTxBody from "./Cardano/CardanoTxBody.js";
export class ModelRegistry{
/**
*
* @param {string} modelId
* @returns {HumanReadableModelBuilder}
*/
static getHumanReadableModelBuilder(modelId, data, expiry){
const c = modelBuildersMap[modelId];
if(!c) throw Error("Could not find model: " + modelId);
return c.create(data, expiry);
}
}
export class HumanReadableModelBuilder{
constructor(data, expiry){
this._data = data;
this._expiry = expiry;
}
static create(data, expiry){
return new this(data, expiry);
}
getHumanReadableObject(){
throw Error("Not implemented for this model");
}
}
// MODELS ----------------------------------------------------------------
class UserContextSignRequestBuilder extends HumanReadableModelBuilder{
_name = "UserContext"; // Model ID
_humanReadableName = "Change Request";
_version = "1";
get _id() { return this._name + ":" + this._version; }
constructor(data, expiry){
super(data, expiry);
}
static create(data, expiry){
return super.create(data, expiry);
}
getHumanReadableObject(){
// deserialize draft here and return a pretty object for user
let prettyObject = {};
let draftIndex = 0;
const initCertPresent = GetValue(this._data, 0)[0];
draftIndex++;
// determine if InitCert is present
switch(initCertPresent){
case 0:
break;
case 1:
const initCert = GetValue(this._data, draftIndex);
prettyObject.InitializationCertificate = new InitializationCertificate(StringFromUint8Array(initCert)).toPrettyObject();
draftIndex++;
break;
default:
throw Error("Unexpected value");
}
// make sure user context is JSON
let cont = true;
prettyObject.UserContexts = [];
while(cont){
try{prettyObject.UserContexts.push(JSON.parse(StringFromUint8Array(GetValue(this._data, draftIndex))));draftIndex++;}
catch{cont = false;}
}
// Create summary
let summary = [];
summary.push(["Admin related", initCertPresent == 1 ? "YES" : "no"]);
// Get the clients involved in this approval
// All clients will be either realm-management or under resource_management
let clients = [];
prettyObject.UserContexts.map(c => {
if(c.realm_access) clients.push("realm_access");
if(typeof c.resource_access === "object"){
clients.push(...Object.keys(c.resource_access));
}
})
clients = [...new Set(clients)];
summary.push(["Applications affected", clients.join(", ")]);
summary.push(["Expiry", unixSecondsToLocaleString(this._expiry)])
// return a nice object of InitCert? and usercontexts
return {
summary: summary,
pretty: prettyObject
}
}
}
class CardanoTxSignRequestBuilder extends HumanReadableModelBuilder{ // this is an example class
_name = "CardanoTx"; // Model ID
_version = "1";
get _id() { return this._name + ":" + this._version; }
constructor(data, expiry){
//throw Error("Not implemented");
super(data, expiry);
}
getHumanReadableObject(){
// deserialize draft here and return a pretty object for user
const txBytes = GetValue(this._data, 0);
const body = new CardanoTxBody(txBytes);
let summary = [];
body.transaction.outputs.map(o => {
summary.push([`Outgoing ada to ${o.address}`, (o.amount / 1_000_000n).toString()]);
})
summary.push(["Fee", body.transaction.fee.toString()])
return {
summary: summary,
pretty: body.toPrettyObject()
}
}
}
class RuleSettingSignRequestBuilder extends HumanReadableModelBuilder{ // this is an example class
_name = "Rules"; // Model ID
_version = "1";
get _id() { return this._name + ":" + this._version; }
constructor(data, expiry){
//throw Error("Not implemented");
super(data, expiry);
}
getHumanReadableObject(){
// deserialize draft here and return a pretty object for user
let prettyObject = {};
let draftIndex = 0;
const previousRulesPresent = GetValue(this._data, 0)[0];
draftIndex++;
// determine if InitCert is present
switch(previousRulesPresent){
case 0:
break;
case 1:
const previousRuleSettings = GetValue(this._data, draftIndex);
prettyObject.RuleSettingToRevoke = new RuleSettings(StringFromUint8Array(previousRuleSettings)).toPrettyObject();
draftIndex += 2;
break;
default:
throw Error("Unexpected value");
}
const newRuleSettings = GetValue(this._data, draftIndex);
prettyObject.NewRuleSetting = new RuleSettings(StringFromUint8Array(newRuleSettings)).toPrettyObject();
return {
summary: [["No summary for RuleSettings"]],
pretty: prettyObject
}
}
}
const modelBuildersMap = {
[new UserContextSignRequestBuilder()._id]: UserContextSignRequestBuilder,
[new CardanoTxSignRequestBuilder()._id]: CardanoTxSignRequestBuilder,
[new RuleSettingSignRequestBuilder()._id]: RuleSettingSignRequestBuilder
}
const unixSecondsToLocaleString = (unixSeconds) => {
const milliseconds = unixSeconds * 1000;
const date = new Date(milliseconds);
return date.toLocaleString('en-GB', {
day: 'numeric',
month: 'long',
year: 'numeric',
hour: '2-digit',
minute: '2-digit',
hour12: false
});
};