heimdall-tide 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/LICENSE +334 -0
  2. package/README.md +3 -0
  3. package/dist/cjs/enclaves/ApprovalEnclave.d.ts +12 -0
  4. package/dist/cjs/enclaves/ApprovalEnclave.js +57 -0
  5. package/dist/cjs/enclaves/ApprovalEnclave.js.map +1 -0
  6. package/dist/cjs/enclaves/RequestEnclave.d.ts +38 -0
  7. package/dist/cjs/enclaves/RequestEnclave.js +204 -0
  8. package/dist/cjs/enclaves/RequestEnclave.js.map +1 -0
  9. package/dist/cjs/heimdall.d.ts +46 -0
  10. package/dist/cjs/heimdall.js +168 -0
  11. package/dist/cjs/heimdall.js.map +1 -0
  12. package/dist/cjs/index.d.ts +4 -0
  13. package/dist/cjs/index.js +8 -0
  14. package/dist/cjs/index.js.map +1 -0
  15. package/dist/cjs/wrapper.d.ts +16 -0
  16. package/dist/cjs/wrapper.js +232 -0
  17. package/dist/cjs/wrapper.js.map +1 -0
  18. package/dist/esm/enclaves/ApprovalEnclave.d.ts +12 -0
  19. package/dist/esm/enclaves/ApprovalEnclave.js +53 -0
  20. package/dist/esm/enclaves/ApprovalEnclave.js.map +1 -0
  21. package/dist/esm/enclaves/RequestEnclave.d.ts +38 -0
  22. package/dist/esm/enclaves/RequestEnclave.js +200 -0
  23. package/dist/esm/enclaves/RequestEnclave.js.map +1 -0
  24. package/dist/esm/heimdall.d.ts +46 -0
  25. package/dist/esm/heimdall.js +164 -0
  26. package/dist/esm/heimdall.js.map +1 -0
  27. package/dist/esm/index.d.ts +4 -0
  28. package/dist/esm/index.js +5 -0
  29. package/dist/esm/index.js.map +1 -0
  30. package/dist/esm/wrapper.d.ts +16 -0
  31. package/dist/esm/wrapper.js +225 -0
  32. package/dist/esm/wrapper.js.map +1 -0
  33. package/heimdall-tide-0.1.0.tgz +0 -0
  34. package/package.json +44 -0
  35. package/src/enclaves/ApprovalEnclave.ts +63 -0
  36. package/src/enclaves/RequestEnclave.ts +237 -0
  37. package/src/heimdall.ts +204 -0
  38. package/src/index.ts +4 -0
  39. package/src/wrapper.ts +258 -0
  40. package/tsconfig.cjs.json +9 -0
  41. package/tsconfig.esm.json +10 -0
  42. package/tsconfig.json +9 -0
@@ -0,0 +1,225 @@
1
+ export const version = "1";
2
+ export function wrapper(arr) {
3
+ // If array is only Uint8Arrays - create a TideMemory out of it
4
+ // If there is any entry in an array that is another array
5
+ // -> Go inside that array and repeat the process
6
+ if (arr.every(a => a instanceof Uint8Array))
7
+ return TideMemory.CreateFromArray(arr);
8
+ else {
9
+ // Go through each entry
10
+ arr.forEach((a) => {
11
+ // If the entry is an array, apply the wappa on it
12
+ if (Array.isArray(a)) {
13
+ // Reassign the value of the entry -> to the serialized wrapper
14
+ a = wrapper(a);
15
+ }
16
+ else if (a["value"]) {
17
+ // Let's check if is a number, boolean or Uint8Array. If none of those, it'll be null
18
+ const res = encode(a["value"]);
19
+ if (res) {
20
+ // serialized correctly
21
+ a = res;
22
+ }
23
+ else {
24
+ if (typeof a["value"] == "string") {
25
+ // Serialize it into Uint8Array
26
+ if (!a["encoding"]) {
27
+ // No encoding provided
28
+ // Let's default to UTF-8
29
+ a = encodeStr(a["value"], "UTF-8");
30
+ }
31
+ else {
32
+ a = encodeStr(a["value"], a["encoding"]);
33
+ }
34
+ }
35
+ else
36
+ throw 'Unsupported type';
37
+ }
38
+ }
39
+ else
40
+ throw 'Unexpected format';
41
+ });
42
+ if (arr.every(a => a instanceof Uint8Array))
43
+ return TideMemory.CreateFromArray(arr); // Check to make sure everything was serialized correctly from the wappa
44
+ else
45
+ throw 'There was an error encoding all your values';
46
+ }
47
+ }
48
+ export function encodeStr(str, enc) {
49
+ switch (enc) {
50
+ case "UTF-8":
51
+ return new TextEncoder().encode(str);
52
+ case "HEX":
53
+ // 1) Strip 0x prefix
54
+ let normalized = str.replace(/^0x/i, "");
55
+ // treat empty as invalid
56
+ if (normalized.length === 0) {
57
+ throw new Error("Empty hex string");
58
+ }
59
+ // 2) Pad odd length
60
+ if (normalized.length % 2 !== 0) {
61
+ normalized = "0" + normalized;
62
+ }
63
+ // 3) Validate
64
+ if (!/^[0-9A-Fa-f]+$/.test(normalized)) {
65
+ throw new Error("Invalid hex string");
66
+ }
67
+ // 4) Parse into bytes
68
+ const byteCount = normalized.length / 2;
69
+ const out = new Uint8Array(byteCount);
70
+ for (let i = 0; i < byteCount; i++) {
71
+ out[i] = Number.parseInt(normalized.slice(i * 2, i * 2 + 2), 16);
72
+ }
73
+ return out;
74
+ case "B64":
75
+ const binaryString = atob(str);
76
+ const len = binaryString.length;
77
+ const bytes = new Uint8Array(len);
78
+ for (let i = 0; i < len; i++) {
79
+ bytes[i] = binaryString.charCodeAt(i);
80
+ }
81
+ return bytes;
82
+ case "B64URL":
83
+ // 1) Replace URL-safe chars with standard Base64 chars
84
+ let base64 = str.replace(/-/g, '+').replace(/_/g, '/');
85
+ // 2) Pad with '=' so length is a multiple of 4
86
+ const pad = base64.length % 4;
87
+ if (pad === 2) {
88
+ base64 += '==';
89
+ }
90
+ else if (pad === 3) {
91
+ base64 += '=';
92
+ }
93
+ else if (pad === 1) {
94
+ // This shouldn’t happen for valid Base64-URL, but just in case…
95
+ base64 += '===';
96
+ }
97
+ // 3) Decode to binary string
98
+ const binary = atob(base64);
99
+ // 4) Convert to Uint8Array
100
+ const ulen = binary.length;
101
+ const ubytes = new Uint8Array(ulen);
102
+ for (let i = 0; i < ulen; i++) {
103
+ ubytes[i] = binary.charCodeAt(i);
104
+ }
105
+ return ubytes;
106
+ default:
107
+ // catches anything else (should never happen)
108
+ throw new TypeError(`Unsupported encoding: ${enc}`);
109
+ }
110
+ }
111
+ export function encode(data) {
112
+ switch (typeof data) {
113
+ case 'number':
114
+ const buffer = new ArrayBuffer(4);
115
+ const view = new DataView(buffer);
116
+ view.setUint32(0, data, true);
117
+ return new Uint8Array(buffer);
118
+ case 'boolean':
119
+ return new Uint8Array([data ? 1 : 0]);
120
+ case 'object':
121
+ // since a Uint8Array is an object at runtime, we need to check it here
122
+ if (data instanceof Uint8Array) {
123
+ return new Uint8Array(data.slice(0));
124
+ }
125
+ // if we fall through, it wasn't one of our allowed types
126
+ throw new TypeError(`Unsupported object type: ${data}`);
127
+ default:
128
+ // catches anything else (should never happen)
129
+ return undefined;
130
+ }
131
+ }
132
+ // Tide Memory Object helper functions from tide-js
133
+ export class TideMemory extends Uint8Array {
134
+ static CreateFromArray(datas) {
135
+ const length = datas.reduce((sum, next) => sum + next.length, 0);
136
+ const mem = this.Create(datas[0], length);
137
+ for (let i = 1; i < datas.length; i++) {
138
+ mem.WriteValue(i, datas[i]);
139
+ }
140
+ return mem;
141
+ }
142
+ static Create(initialValue, totalLength, version = 1) {
143
+ if (totalLength < initialValue.length + 4) {
144
+ throw new Error("Not enough space to allocate requested data. Make sure to request more space in totalLength than length of InitialValue plus 4 bytes for length.");
145
+ }
146
+ // Total buffer length is 4 (version) + totalLength
147
+ const bufferLength = 4 + totalLength;
148
+ const buffer = new TideMemory(bufferLength);
149
+ const dataView = new DataView(buffer.buffer);
150
+ // Write version at position 0 (4 bytes)
151
+ dataView.setInt32(0, version, true); // true for little-endian
152
+ let dataLocationIndex = 4;
153
+ // Write data length of initialValue at position 4 (4 bytes)
154
+ dataView.setInt32(dataLocationIndex, initialValue.length, true);
155
+ dataLocationIndex += 4;
156
+ // Write initialValue starting from position 8
157
+ buffer.set(initialValue, dataLocationIndex);
158
+ return buffer;
159
+ }
160
+ WriteValue(index, value) {
161
+ if (index < 0)
162
+ throw new Error("Index cannot be less than 0");
163
+ if (index === 0)
164
+ throw new Error("Use CreateTideMemory to set value at index 0");
165
+ if (this.length < 4 + value.length)
166
+ throw new Error("Could not write to memory. Memory too small for this value");
167
+ const dataView = new DataView(this.buffer);
168
+ let dataLocationIndex = 4; // Start after the version number
169
+ // Navigate through existing data segments
170
+ for (let i = 0; i < index; i++) {
171
+ if (dataLocationIndex + 4 > this.length) {
172
+ throw new RangeError("Index out of range.");
173
+ }
174
+ // Read data length at current position
175
+ const nextDataLength = dataView.getInt32(dataLocationIndex, true);
176
+ dataLocationIndex += 4;
177
+ dataLocationIndex += nextDataLength;
178
+ }
179
+ // Check if there's enough space to write the value
180
+ if (dataLocationIndex + 4 + value.length > this.length) {
181
+ throw new RangeError("Not enough space to write value");
182
+ }
183
+ // Check if data has already been written to this index
184
+ const existingLength = dataView.getInt32(dataLocationIndex, true);
185
+ if (existingLength !== 0) {
186
+ throw new Error("Data has already been written to this index");
187
+ }
188
+ // Write data length of value at current position
189
+ dataView.setInt32(dataLocationIndex, value.length, true);
190
+ dataLocationIndex += 4;
191
+ // Write value starting from current position
192
+ this.set(value, dataLocationIndex);
193
+ }
194
+ GetValue(index) {
195
+ // 'a' should be an ArrayBuffer or Uint8Array
196
+ if (this.length < 4) {
197
+ throw new Error("Insufficient data to read.");
198
+ }
199
+ // Create a DataView for reading integers in little-endian format
200
+ const dataView = new DataView(this.buffer, this.byteOffset, this.byteLength);
201
+ // Optional: Read the version if needed
202
+ // const version = dataView.getInt32(0, true);
203
+ let dataLocationIndex = 4;
204
+ for (let i = 0; i < index; i++) {
205
+ // Check if there's enough data to read the length of the next segment
206
+ if (dataLocationIndex + 4 > this.length) {
207
+ throw new RangeError("Index out of range.");
208
+ }
209
+ const nextDataLength = dataView.getInt32(dataLocationIndex, true);
210
+ dataLocationIndex += 4 + nextDataLength;
211
+ }
212
+ // Check if there's enough data to read the length of the final segment
213
+ if (dataLocationIndex + 4 > this.length) {
214
+ throw new RangeError("Index out of range.");
215
+ }
216
+ const finalDataLength = dataView.getInt32(dataLocationIndex, true);
217
+ dataLocationIndex += 4;
218
+ // Check if the final data segment is within bounds
219
+ if (dataLocationIndex + finalDataLength > this.length) {
220
+ throw new RangeError("Index out of range.");
221
+ }
222
+ return this.subarray(dataLocationIndex, dataLocationIndex + finalDataLength);
223
+ }
224
+ }
225
+ //# sourceMappingURL=wrapper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wrapper.js","sourceRoot":"","sources":["../../src/wrapper.ts"],"names":[],"mappings":"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"}
Binary file
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "heimdall-tide",
3
+ "version": "0.1.0",
4
+ "description": "SDK for communicating with a Tide Enclave",
5
+ "main": "dist/cjs/index.js",
6
+ "module": "dist/esm/index.js",
7
+ "typings": "dist/esm/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/esm/index.js",
11
+ "require": "./dist/cjs/index.js"
12
+ },
13
+ "./enclaves/ApprovalEnclave": {
14
+ "import": "./dist/esm/enclaves/ApprovalEnclave.js",
15
+ "require": "./dist/cjs/enclaves/ApprovalEnclave.js"
16
+ },
17
+ "./enclaves/RequestEnclave": {
18
+ "import": "./dist/esm/enclaves/RequestEnclave.js",
19
+ "require": "./dist/cjs/enclaves/RequestEnclave.js"
20
+ }
21
+ },
22
+ "scripts": {
23
+ "build:cjs": "tsc -p tsconfig.cjs.json",
24
+ "build:esm": "tsc -p tsconfig.esm.json",
25
+ "build": "npm run build:cjs && npm run build:esm"
26
+ },
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "git+https://github.com/tide-foundation/heimdall.git"
30
+ },
31
+ "keywords": [
32
+ "tide"
33
+ ],
34
+ "author": "Tide",
35
+ "license": "ISC",
36
+ "types": "./heimdall.d.ts",
37
+ "bugs": {
38
+ "url": "https://github.com/tide-foundation/heimdall/issues"
39
+ },
40
+ "homepage": "https://github.com/tide-foundation/heimdall#readme",
41
+ "devDependencies": {
42
+ "typescript": "^5.8.3"
43
+ }
44
+ }
@@ -0,0 +1,63 @@
1
+ import {Heimdall, windowType} from "../heimdall";
2
+
3
+ export class ApprovalEnclave extends Heimdall<ApprovalEnclave>{
4
+ name: string = "approval";
5
+ _windowType: windowType = windowType.Popup;
6
+ private acceptedAdminIds: string[];
7
+ enclaveUrl: URL;
8
+ private initDone: Promise<any>;
9
+
10
+ init(data: string[], enclaveUrl: string): ApprovalEnclave {
11
+ this.acceptedAdminIds = data;
12
+ this.enclaveUrl = new URL(enclaveUrl);
13
+ this.initDone = this.open();
14
+ return this;
15
+ }
16
+
17
+ async getAuthorizerAuthentication() {
18
+ await this.initDone;
19
+ // ready to accept reply
20
+ const pre_response = this.recieve("authentication");
21
+
22
+ // send to enclave
23
+ this.send({
24
+ type: "authentication",
25
+ message: "pretty please"
26
+ });
27
+
28
+ // wait for response - this does not mean that enclave it closed, just that the admin has responded to the approval request from the enclave
29
+ return await pre_response;
30
+ }
31
+
32
+
33
+ async getAuthorizerApproval(draftToApprove, modelId, expiry, encoding = "bytes", authflow = "") {
34
+ await this.initDone;
35
+ // ready to accept reply
36
+ const pre_response = this.recieve("approval");
37
+
38
+ // send to enclave
39
+ this.send({
40
+ type: "approval",
41
+ message: {
42
+ draftToAuthorize: {
43
+ data: draftToApprove,
44
+ encoding: encoding
45
+ },
46
+ modelId: modelId,
47
+ expiry: expiry,
48
+ authflow: authflow
49
+ }
50
+ });
51
+
52
+ // wait for response - this does not mean that enclave it closed, just that the admin has responded to the approval request from the enclave
53
+ return await pre_response;
54
+ }
55
+
56
+ getOrkUrl() {
57
+ // how to create approval ork url for openinging enclave?
58
+ this.enclaveUrl.searchParams.set("type", "approval");
59
+ this.enclaveUrl.searchParams.set("acceptedIds", JSON.stringify(this.acceptedAdminIds));
60
+ return this.enclaveUrl;
61
+ }
62
+
63
+ }
@@ -0,0 +1,237 @@
1
+ import { Heimdall, windowType } from "../heimdall";
2
+ import { TideMemory } from "../wrapper";
3
+
4
+ interface HiddenInit{
5
+ doken: string;
6
+ /**
7
+ * @returns A refresh doken for Heimdall
8
+ */
9
+ dokenRefreshCallback: () => Promise<string> | undefined;
10
+ /**
11
+ * @returns A function that re authenticates the current user from the client. (Used to update their session key on Identity System). Returns a new doken too.
12
+ */
13
+ requireReloginCallback: () => Promise<string>;
14
+ }
15
+
16
+ export class RequestEnclave extends Heimdall<RequestEnclave>{
17
+ private doken: string;
18
+ private dokenRefreshCallback: () => Promise<string> | undefined;
19
+ private requireReloginCallback: () => Promise<string>;
20
+
21
+ _windowType: windowType = windowType.Hidden;
22
+
23
+ private initDone: Promise<any> = this.recieve("init done");
24
+
25
+ init(data: HiddenInit): RequestEnclave {
26
+ if(!data.doken) throw 'Doken not provided';
27
+
28
+ this.doken = data.doken;
29
+ this.dokenRefreshCallback = data.dokenRefreshCallback;
30
+ this.requireReloginCallback = data.requireReloginCallback;
31
+
32
+ this.recieve("hidden enclave").then((data) => this.handleHiddenEnclaveResponse(data));
33
+
34
+ this.open().then((success: boolean) => {
35
+ if(success){
36
+ this.send({
37
+ type: "init",
38
+ message: {
39
+ doken: this.doken
40
+ }
41
+ });
42
+ }else throw 'Error opening enclave';
43
+ });
44
+
45
+ return this;
46
+ }
47
+
48
+ async handleHiddenEnclaveResponse(msg: any){
49
+ // Below is the session key mismatch flow that was implemented but then it was decided a basic relogin was more elegent
50
+ // Keeping it though because it is nearly identical to the flow where a tide user delegates a token to another tide user
51
+ // This would require the second tide user to sign a new delegated token with their current session key
52
+ // This would be gold in a cvk scenario
53
+ // if(msg == "session key mismatch" && this._windowType == windowType.Hidden){
54
+ // this.initDone = this.recieve("init done"); // await the REOPENED HIDDEN ENCLAVE INIT DONE SIGNAL
55
+ // // looks like the hidden iframe has not allowed data to be stored on the browser OR the session key is mismatched with whats on the enclave vs doken
56
+ // // either way we gotta get a doken with the appropriate session key
57
+
58
+ // // Close the hidden enclave
59
+ // this.close();
60
+
61
+ // // We're now going to open the request enclave as a popup with the mismatched doken
62
+ // // The page should recognise the doken is mismatched, generate a new one, then close
63
+ // this._windowType = windowType.Popup;
64
+
65
+ // // open popup
66
+ // await this.open();
67
+ // // send doken to refresh
68
+ // this.send({
69
+ // type: "init",
70
+ // message:{
71
+ // doken: this.doken
72
+ // }
73
+ // });
74
+ // // wait for new doken
75
+ // const resp = await this.recieve("refreshed doken");
76
+ // this.doken = resp.doken;
77
+ // if(this.requireReloginCallback) this.requireReloginCallback();
78
+
79
+ // // close pop up enclave
80
+ // this.close();
81
+
82
+ // // reset page to hidden iframe
83
+ // this._windowType = windowType.Hidden;
84
+ // // open hidden iframe
85
+ // this.open().then((success: boolean) => {
86
+ // if(success){
87
+ // this.send({
88
+ // type: "init",
89
+ // message: {
90
+ // doken: this.doken
91
+ // }
92
+ // });
93
+ // }else throw 'Error opening enclave';
94
+ // });
95
+
96
+ // }
97
+ if(msg == "session key mismatch"){
98
+ this.requireReloginCallback(); // should initiate a full client page reload, killing this
99
+ }
100
+
101
+ this.recieve("hidden enclave").then((data) => this.handleHiddenEnclaveResponse(data));
102
+ }
103
+
104
+ getOrkUrl(): URL {
105
+ // construct ork url
106
+ const url = new URL(this.enclaveOrigin);
107
+
108
+ // Set hidden status
109
+ url.searchParams.set("hidden", this._windowType == windowType.Hidden ? "true" : "false");
110
+
111
+ // Set vendor public
112
+ url.searchParams.set("vendorId", this.vendorId);
113
+
114
+ // Set client origin
115
+ url.searchParams.set("origin", encodeURIComponent(window.location.origin));
116
+
117
+ // Set client origin signature (by vendor)
118
+ url.searchParams.set("originsig", encodeURIComponent(this.signed_client_origin));
119
+
120
+ // Set voucher url
121
+ url.searchParams.set("voucherURL", encodeURIComponent(this.voucherURL));
122
+
123
+ // Set requestsed enclave
124
+ url.searchParams.set("type", "request");
125
+
126
+ return url;
127
+ }
128
+ checkEnclaveOpen(){
129
+ if(this.enclaveClosed()){
130
+ // Enclave was closed!
131
+ // We need to reopen the enclave and await the init again
132
+ this.initDone = this.recieve("init done");
133
+ this.open().then((success: boolean) => {
134
+ if(success){
135
+ this.send({
136
+ type: "init",
137
+ message:{
138
+ doken: this.doken
139
+ }
140
+ });
141
+ }else throw 'Error opening enclave';
142
+ });
143
+ }
144
+ }
145
+
146
+ async execute(data: TideMemory): Promise<Uint8Array[]>{
147
+ this.checkEnclaveOpen();
148
+ await this.initDone;
149
+ const pre_resp = this.recieve("sign request completed");
150
+ this.send({
151
+ type: "request",
152
+ message:{
153
+ flow: "sign",
154
+ request: data,
155
+ }
156
+ })
157
+ const resp = await pre_resp;
158
+ if(!Array.isArray(resp)) throw 'Expecting request completed data to be an array, not' + resp;
159
+ if(!resp.every((d: any) => d instanceof Uint8Array)) throw 'Expecting all entries in response to be Uint8Arrays';
160
+ return resp;
161
+ }
162
+ async decrypt(data: decryptRequest): Promise<Uint8Array[]>{
163
+ this.checkEnclaveOpen();
164
+ await this.initDone;
165
+ const pre_resp = this.recieve("decrypt request completed");
166
+ this.send({
167
+ type: "request",
168
+ message:{
169
+ flow: "decrypt",
170
+ request: data
171
+ }
172
+ })
173
+ const resp = await pre_resp;
174
+ if(!Array.isArray(resp)) throw 'Expecting request completed data to be an array, not' + resp;
175
+ if(!resp.every((d: any) => d instanceof Uint8Array)) throw 'Expecting all entries in response to be Uint8Arrays';
176
+ return resp;
177
+ }
178
+ async encrypt(data: encryptRequest): Promise<Uint8Array[]>{
179
+ this.checkEnclaveOpen();
180
+ await this.initDone;
181
+ const pre_resp = this.recieve("encrypt request completed");
182
+ this.send({
183
+ type: "request",
184
+ message: {
185
+ flow: "encrypt",
186
+ request: data
187
+ }
188
+ })
189
+ const resp = await pre_resp;
190
+ if(!Array.isArray(resp)) throw 'Expecting request completed data to be an array, not' + resp;
191
+ if(!resp.every((d: any) => d instanceof Uint8Array)) throw 'Expecting all entries in response to be Uint8Arrays';
192
+ return resp;
193
+ }
194
+
195
+ async updateDoken(doken: string){
196
+ this.doken = doken;
197
+ this.send({
198
+ type: "doken refresh",
199
+ message:{
200
+ doken: this.doken
201
+ }
202
+ });
203
+ }
204
+
205
+ async onerror(data: any) {
206
+ if(typeof data.message === "string"){
207
+ switch(data.message){
208
+ case "expired":
209
+ if(!this.dokenRefreshCallback){
210
+ console.error("[HEIMDALL] Doken on enclave has expired but there is no Doken Refresh Callback registered");
211
+ return;
212
+ }
213
+ console.log("[HEIMDALL] Refreshing doken");
214
+ this.doken = await this.dokenRefreshCallback();
215
+ this.send({
216
+ type: "doken refresh",
217
+ message:{
218
+ doken: this.doken
219
+ }
220
+ });
221
+ break;
222
+ default:
223
+ this.close();
224
+ throw new Error("[HEIMDALL] Recieved enclave error: " + data.message);
225
+ }
226
+ }
227
+ }
228
+ }
229
+
230
+ interface decryptRequest{
231
+ encrypted: Uint8Array;
232
+ tags: string[]
233
+ }
234
+ interface encryptRequest{
235
+ data: Uint8Array;
236
+ tags: string[]
237
+ }