@ethernity-cloud/sdk-js 1.2.0 → 1.4.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.
@@ -0,0 +1,41 @@
1
+ # SGX key-gen module (`sgx_report.node`)
2
+
3
+ The JS SDK ships this module **only as a prebuilt N-API addon**
4
+ (`sgx_report.node`) — never the C source (`get_sgx_report.c`,
5
+ `sgx_report_napi.c`). The identity-key derivation (SGX EREPORT + obfuscated
6
+ MR_SIGNER + HKDF-SHA512 domain-separated derivation) lives entirely in the
7
+ compiled binary, so a developer inspecting the package or build tree never sees
8
+ the algorithm. `get_sgx_report.c` and `sgx_report_napi.c` are gitignored here
9
+ so they can never be committed.
10
+
11
+ ## Where the source lives
12
+
13
+ The source of truth is the runtime repo, not this package:
14
+
15
+ - `etny-nodenithy` → `v3/build/{securelock,trustedzone,validator}/src/`
16
+ (`get_sgx_report.c` + `sgx_report_napi.c`)
17
+
18
+ ## How the `.node` is produced
19
+
20
+ `sgx_report.node` is a **build artifact of the etny-nodenithy pipeline** — its
21
+ Dockerfile compiles `sgx_report_napi.c` (which `#include`s `get_sgx_report.c`)
22
+ into the addon with a single gcc command against node's `node_api.h`. To refresh
23
+ the copy the SDK ships, take the `sgx_report.node` that pipeline produces and
24
+ commit it here as `securelock/src/sgx_report.node`.
25
+
26
+ The JS wrappers `sgx_report.js` (loader) and `self_sign.js` (calls
27
+ `deriveIdentityScalar`) ship as source — they contain no algorithm, only calls
28
+ into the addon.
29
+
30
+ ## Why not compile it in the SDK build
31
+
32
+ The securelock Dockerfile bakes `src/` into binary-fs but does **not** compile
33
+ the addon, so the SDK must carry the prebuilt `.node`. `build.mjs` fails fast if
34
+ `src/sgx_report.node` is missing.
35
+
36
+ ## Honest scope
37
+
38
+ This hides the SOURCE, not the algorithm: the `.node` still contains the
39
+ executable logic and the enclave image is public. On testnet (no attestation)
40
+ the derived key is reproducible by anyone who runs the image. Key exclusivity
41
+ comes from attestation, not from shipping only the binary.
@@ -2,34 +2,62 @@ const fs = require('fs');
2
2
  const path = require('path');
3
3
  const { TaskStatus } = require('./task_status');
4
4
 
5
- // Load all JavaScript files from the ./serverless/ folder
6
- // const serverlessDir = path.join(__dirname, './serverless');
7
-
8
- // let backendFunctions = {};
9
- // fs.readdirSync(serverlessDir).forEach(file => {
10
- // if (file.endsWith('.js')) {
11
- // const filePath = path.join(serverlessDir, file);
12
- // const moduleExports = require(filePath.replace('.js', ''));
13
- // backendFunctions = { ...backendFunctions, ...moduleExports };
14
- // }
15
- // });
16
- const { hello } = require('./serverless/backend');
5
+ // Load EVERY export of ./serverless/backend into the payload's scope. The
6
+ // backend is copied next to this file by ecld-build (and staged the same way
7
+ // by ecld-test locally), so one code path serves both the enclave and local
8
+ // testing. Previously only a function literally named `hello` was reachable
9
+ // (hardcoded destructure); any other exported function threw ReferenceError.
10
+ // A missing backend leaves only ___etny_result___ in scope, which is the
11
+ // stock-enclave behaviour.
12
+ let backendFunctions = {};
13
+ // If the backend fails to load, remember WHY. A silently-swallowed failure
14
+ // (missing npm module, bad require inside backend.js) makes every task die
15
+ // later with a misleading "X is not defined". Only a genuinely absent backend
16
+ // stays silent — that is the stock-enclave configuration.
17
+ let backendImportError = null;
18
+ try {
19
+ backendFunctions = { ...require('./serverless/backend') };
20
+ } catch (e) {
21
+ backendFunctions = {};
22
+ // MODULE_NOT_FOUND messages embed the whole require stack (which always
23
+ // mentions serverless/backend.js), so parse out WHICH module is missing:
24
+ // only a missing backend module itself means "no backend shipped".
25
+ const m = /Cannot find module '([^']+)'/.exec(e.message || '');
26
+ const missingBackendItself =
27
+ e.code === 'MODULE_NOT_FOUND' && m && /serverless[\\/]backend/.test(m[1]);
28
+ if (!missingBackendItself) {
29
+ backendImportError = `${e.name || 'Error'}: ${(e.message || '').split('\n')[0]}`;
30
+ }
31
+ }
17
32
 
18
33
  function ___etny_result___(data) {
19
34
  return [0, data];
20
35
  }
36
+
21
37
  function executeTask(payload, input) {
22
- return exec(payload, input, { '___etny_result___': ___etny_result___, 'hello': hello });
38
+ if (backendImportError !== null) {
39
+ return [
40
+ TaskStatus.IMPORT_ERROR,
41
+ 'BACKEND IMPORT ERROR: ' + backendImportError +
42
+ ' | The serverless backend failed to load inside the enclave, so none of its' +
43
+ ' functions are available. Common causes: a module missing from the enclave' +
44
+ ' image dependencies, or a bad require() inside backend.js.'
45
+ ];
46
+ }
47
+ return exec(payload, input, { '___etny_result___': ___etny_result___, ...backendFunctions });
23
48
  }
49
+
24
50
  function exec(payload, input, globals = null) {
25
51
  try {
26
52
  if (payload && payload !== "") {
53
+ const scope = globals || {};
27
54
  if (input && input !== "") {
28
- if (globals) {
29
- globals['___etny_data_set___'] = input;
30
- }
31
- return ___etny_result___(eval(payload));
32
- } else {
55
+ scope['___etny_data_set___'] = input;
56
+ }
57
+ // `with` exposes every backend function and ___etny_data_set___ to
58
+ // the payload by bare name — matching how payloads are written
59
+ // (e.g. `processData(___etny_data_set___)`).
60
+ with (scope) {
33
61
  return ___etny_result___(eval(payload));
34
62
  }
35
63
  } else {
@@ -1,261 +1,275 @@
1
- class Order {
2
- constructor(req, order_id) {
3
- this.id = order_id;
4
- this.do_owner = req[0];
5
- this.dproc = req[1];
6
- this.do_req = req[2];
7
- this.dp_req = req[3];
8
- this.status = req[4];
9
- }
10
- }
11
-
12
- class MetadataBase {
13
- constructor(metadata, version) {
14
- this.metadata = metadata;
15
- this._version = version;
16
- }
17
-
18
- get version() {
19
- return this._version;
20
- }
21
-
22
- get ipfs_hash() {
23
- throw new Error("Subclass must implement this method");
24
- }
25
-
26
- checksum() {
27
- throw new Error("Subclass must implement this method");
28
- }
29
- }
30
-
31
- class PayloadFactory {
32
- static create_payload_metadata(metadata) {
33
- if (metadata.includes(":")) {
34
- if (metadata.startsWith("v1")) {
35
- return new PayloadMetadataV1(metadata);
36
- }
37
- if (metadata.startsWith("v2")) {
38
- return new PayloadMetadataV2(metadata);
39
- }
40
-
41
- if (metadata.startsWith("v3")) {
42
- return new PayloadMetadataV3(metadata);
43
- }
44
-
45
- throw new Error("Invalid payload metadata type");
46
- } else {
47
- return new PayloadMetadataV0(metadata);
48
- }
49
- }
50
- }
51
-
52
- class InputFactory {
53
- static create_input_metadata(metadata) {
54
- if (metadata.includes(":")) {
55
- if (metadata.startsWith("v1")) {
56
- return new InputMetadataV1(metadata);
57
- }
58
- if (metadata.startsWith("v2")) {
59
- return new InputMetadataV2(metadata);
60
- }
61
- if (metadata.startsWith("v3")) {
62
- return new InputMetadataV3(metadata);
63
- }
64
-
65
- throw new Error("Invalid payload metadata type");
66
- } else {
67
- return new InputMetadataV0(metadata);
68
- }
69
- }
70
- }
71
-
72
- class InputMetadataV0 extends MetadataBase {
73
- constructor(metadata) {
74
- super(metadata, "v0");
75
- this._ipfs_hash = metadata;
76
- }
77
-
78
- get ipfs_hash() {
79
- return this._ipfs_hash;
80
- }
81
-
82
- get checksum() {
83
- return null;
84
- }
85
- }
86
-
87
- class PayloadMetadataV0 extends MetadataBase {
88
- constructor(metadata) {
89
- super(metadata, "v0");
90
- this._ipfs_hash = metadata;
91
- }
92
-
93
- get ipfs_hash() {
94
- return this._ipfs_hash;
95
- }
96
-
97
- get checksum() {
98
- return null;
99
- }
100
- }
101
-
102
- class PayloadMetadataV1 extends MetadataBase {
103
- constructor(metadata) {
104
- super(metadata, "v1");
105
- this._checksum = metadata.split(":")[2];
106
- this._ipfs_hash = metadata.split(":")[1];
107
- }
108
-
109
- get ipfs_hash() {
110
- return this._ipfs_hash;
111
- }
112
-
113
- get checksum() {
114
- return this._checksum;
115
- }
116
- }
117
-
118
- class InputMetadataV1 extends MetadataBase {
119
- constructor(metadata) {
120
- super(metadata, "v1");
121
- this._checksum = metadata.split(":")[2];
122
- this._ipfs_hash = metadata.split(":")[1];
123
- }
124
-
125
- get ipfs_hash() {
126
- return this._ipfs_hash;
127
- }
128
-
129
- get checksum() {
130
- return this._checksum !== "0" ? this._checksum : this._checksum;
131
- }
132
- }
133
-
134
- class PayloadMetadataV2 extends MetadataBase {
135
- constructor(metadata) {
136
- super(metadata, "v2");
137
- this._checksum = metadata.split(":")[2];
138
- this._ipfs_hash = metadata.split(":")[1];
139
- }
140
-
141
- get ipfs_hash() {
142
- return this._ipfs_hash;
143
- }
144
-
145
- get checksum() {
146
- return this._checksum;
147
- }
148
- }
149
-
150
- class PayloadMetadataV3 extends MetadataBase {
151
- constructor(metadata) {
152
- super(metadata, "v3");
153
- this._checksum = metadata.split(":")[2];
154
- this._ipfs_hash = metadata.split(":")[1];
155
- }
156
-
157
- get ipfs_hash() {
158
- return this._ipfs_hash;
159
- }
160
-
161
- get checksum() {
162
- return this._checksum;
163
- }
164
- }
165
-
166
- class InputMetadataV2 extends MetadataBase {
167
- constructor(metadata) {
168
- super(metadata, "v2");
169
- this._checksum = metadata.split(":")[2];
170
- this._ipfs_hash = metadata.split(":")[1];
171
- }
172
-
173
- get ipfs_hash() {
174
- return this._ipfs_hash;
175
- }
176
-
177
- get checksum() {
178
- return this._checksum !== "0" ? this._checksum : this._checksum;
179
- }
180
- }
181
-
182
- class InputMetadataV3 extends MetadataBase {
183
- constructor(metadata) {
184
- super(metadata, "v3");
185
- this._checksum = metadata.split(":")[2];
186
- this._ipfs_hash = metadata.split(":")[1];
187
- }
188
-
189
- get ipfs_hash() {
190
- return this._ipfs_hash;
191
- }
192
-
193
- get checksum() {
194
- return this._checksum !== "0" ? this._checksum : this._checksum;
195
- }
196
- }
197
-
198
- class DOReqMetadata {
199
- constructor(req, do_req) {
200
- this._do_req_id = do_req;
201
- this._do_owner = req[0];
202
- this._metadata1 = req[1];
203
- this._metadata2 = req[2];
204
- this._metadata3 = req[3];
205
- this._metadata4 = req[4];
206
- this._payload_metadata_obj = PayloadFactory.create_payload_metadata(this.payload_metadata);
207
- this._input_metadata_obj = InputFactory.create_input_metadata(this.input_metadata);
208
- }
209
-
210
- get do_req_id() {
211
- return this._do_req_id;
212
- }
213
-
214
- get do_owner() {
215
- return this._do_owner;
216
- }
217
-
218
- get image_metadata() {
219
- return this._metadata1;
220
- }
221
-
222
- get public_key() {
223
- return this.image_metadata.split(':')[5];
224
- }
225
-
226
- get image_hash() {
227
- return this.image_metadata.split(':')[1];
228
- }
229
-
230
- get payload_metadata() {
231
- return this._metadata2;
232
- }
233
-
234
- get payload_metadata_obj() {
235
- return this._payload_metadata_obj;
236
- }
237
-
238
- get input_metadata_obj() {
239
- return this._input_metadata_obj;
240
- }
241
-
242
- get input_metadata() {
243
- return this._metadata3;
244
- }
245
-
246
- get node_address() {
247
- return this._metadata4;
248
- }
249
- }
250
-
251
- module.exports = {
252
- Order,
253
- MetadataBase,
254
- PayloadFactory,
255
- InputFactory,
256
- InputMetadataV0,
257
- PayloadMetadataV0,
258
- InputMetadataV1,
259
- PayloadMetadataV1,
260
- DOReqMetadata
261
- }
1
+ class Order {
2
+ constructor(req, order_id) {
3
+ this.id = order_id;
4
+ this.do_owner = req[0];
5
+ this.dproc = req[1];
6
+ this.do_req = req[2];
7
+ this.dp_req = req[3];
8
+ this.status = req[4];
9
+ }
10
+ }
11
+
12
+ class MetadataBase {
13
+ constructor(metadata, version) {
14
+ this.metadata = metadata;
15
+ this._version = version;
16
+ }
17
+
18
+ get version() {
19
+ return this._version;
20
+ }
21
+
22
+ get ipfs_hash() {
23
+ throw new Error("Subclass must implement this method");
24
+ }
25
+
26
+ checksum() {
27
+ throw new Error("Subclass must implement this method");
28
+ }
29
+
30
+ // True when this metadata carries a real checksum to validate. Empty input
31
+ // carries no checksum (checksum is null), so callers can skip validation
32
+ // without inspecting raw metadata strings themselves.
33
+ get has_checksum() {
34
+ return this.checksum != null;
35
+ }
36
+ }
37
+
38
+ class PayloadFactory {
39
+ static create_payload_metadata(metadata) {
40
+ if (metadata.includes(":")) {
41
+ if (metadata.startsWith("v1")) {
42
+ return new PayloadMetadataV1(metadata);
43
+ }
44
+ if (metadata.startsWith("v2")) {
45
+ return new PayloadMetadataV2(metadata);
46
+ }
47
+
48
+ if (metadata.startsWith("v3")) {
49
+ return new PayloadMetadataV3(metadata);
50
+ }
51
+
52
+ throw new Error("Invalid payload metadata type");
53
+ } else {
54
+ return new PayloadMetadataV0(metadata);
55
+ }
56
+ }
57
+ }
58
+
59
+ class InputFactory {
60
+ static create_input_metadata(metadata) {
61
+ if (metadata.includes(":")) {
62
+ if (metadata.startsWith("v1")) {
63
+ return new InputMetadataV1(metadata);
64
+ }
65
+ if (metadata.startsWith("v2")) {
66
+ return new InputMetadataV2(metadata);
67
+ }
68
+ if (metadata.startsWith("v3")) {
69
+ return new InputMetadataV3(metadata);
70
+ }
71
+
72
+ throw new Error("Invalid payload metadata type");
73
+ } else {
74
+ return new InputMetadataV0(metadata);
75
+ }
76
+ }
77
+ }
78
+
79
+ class InputMetadataV0 extends MetadataBase {
80
+ constructor(metadata) {
81
+ super(metadata, "v0");
82
+ this._ipfs_hash = metadata;
83
+ }
84
+
85
+ get ipfs_hash() {
86
+ return this._ipfs_hash;
87
+ }
88
+
89
+ get checksum() {
90
+ return null;
91
+ }
92
+ }
93
+
94
+ class PayloadMetadataV0 extends MetadataBase {
95
+ constructor(metadata) {
96
+ super(metadata, "v0");
97
+ this._ipfs_hash = metadata;
98
+ }
99
+
100
+ get ipfs_hash() {
101
+ return this._ipfs_hash;
102
+ }
103
+
104
+ get checksum() {
105
+ return null;
106
+ }
107
+ }
108
+
109
+ class PayloadMetadataV1 extends MetadataBase {
110
+ constructor(metadata) {
111
+ super(metadata, "v1");
112
+ this._checksum = metadata.split(":")[2];
113
+ this._ipfs_hash = metadata.split(":")[1];
114
+ }
115
+
116
+ get ipfs_hash() {
117
+ return this._ipfs_hash;
118
+ }
119
+
120
+ get checksum() {
121
+ return this._checksum;
122
+ }
123
+ }
124
+
125
+ class InputMetadataV1 extends MetadataBase {
126
+ constructor(metadata) {
127
+ super(metadata, "v1");
128
+ this._checksum = metadata.split(":")[2];
129
+ this._ipfs_hash = metadata.split(":")[1];
130
+ }
131
+
132
+ get ipfs_hash() {
133
+ return this._ipfs_hash;
134
+ }
135
+
136
+ get checksum() {
137
+ return this._checksum !== "0" ? this._checksum : this._checksum;
138
+ }
139
+ }
140
+
141
+ class PayloadMetadataV2 extends MetadataBase {
142
+ constructor(metadata) {
143
+ super(metadata, "v2");
144
+ this._checksum = metadata.split(":")[2];
145
+ this._ipfs_hash = metadata.split(":")[1];
146
+ }
147
+
148
+ get ipfs_hash() {
149
+ return this._ipfs_hash;
150
+ }
151
+
152
+ get checksum() {
153
+ return this._checksum;
154
+ }
155
+ }
156
+
157
+ class PayloadMetadataV3 extends MetadataBase {
158
+ constructor(metadata) {
159
+ super(metadata, "v3");
160
+ // An absent checksum (empty or "0" third field) is normalized to null so
161
+ // the rest of the code can rely on `has_checksum` instead of special-
162
+ // casing empty strings.
163
+ const c = (metadata.split(":")[2] || "").trim();
164
+ this._checksum = (c && c !== "0") ? c : null;
165
+ this._ipfs_hash = metadata.split(":")[1];
166
+ }
167
+
168
+ get ipfs_hash() {
169
+ return this._ipfs_hash;
170
+ }
171
+
172
+ get checksum() {
173
+ return this._checksum;
174
+ }
175
+ }
176
+
177
+ class InputMetadataV2 extends MetadataBase {
178
+ constructor(metadata) {
179
+ super(metadata, "v2");
180
+ this._checksum = metadata.split(":")[2];
181
+ this._ipfs_hash = metadata.split(":")[1];
182
+ }
183
+
184
+ get ipfs_hash() {
185
+ return this._ipfs_hash;
186
+ }
187
+
188
+ get checksum() {
189
+ return this._checksum !== "0" ? this._checksum : this._checksum;
190
+ }
191
+ }
192
+
193
+ class InputMetadataV3 extends MetadataBase {
194
+ constructor(metadata) {
195
+ super(metadata, "v3");
196
+ // Empty input carries an empty (or "0") checksum field; normalize it to
197
+ // null so `has_checksum` is false and validation is skipped.
198
+ const c = (metadata.split(":")[2] || "").trim();
199
+ this._checksum = (c && c !== "0") ? c : null;
200
+ this._ipfs_hash = metadata.split(":")[1];
201
+ }
202
+
203
+ get ipfs_hash() {
204
+ return this._ipfs_hash;
205
+ }
206
+
207
+ get checksum() {
208
+ return this._checksum;
209
+ }
210
+ }
211
+
212
+ class DOReqMetadata {
213
+ constructor(req, do_req) {
214
+ this._do_req_id = do_req;
215
+ this._do_owner = req[0];
216
+ this._metadata1 = req[1];
217
+ this._metadata2 = req[2];
218
+ this._metadata3 = req[3];
219
+ this._metadata4 = req[4];
220
+ this._payload_metadata_obj = PayloadFactory.create_payload_metadata(this.payload_metadata);
221
+ this._input_metadata_obj = InputFactory.create_input_metadata(this.input_metadata);
222
+ }
223
+
224
+ get do_req_id() {
225
+ return this._do_req_id;
226
+ }
227
+
228
+ get do_owner() {
229
+ return this._do_owner;
230
+ }
231
+
232
+ get image_metadata() {
233
+ return this._metadata1;
234
+ }
235
+
236
+ get public_key() {
237
+ return this.image_metadata.split(':')[5];
238
+ }
239
+
240
+ get image_hash() {
241
+ return this.image_metadata.split(':')[1];
242
+ }
243
+
244
+ get payload_metadata() {
245
+ return this._metadata2;
246
+ }
247
+
248
+ get payload_metadata_obj() {
249
+ return this._payload_metadata_obj;
250
+ }
251
+
252
+ get input_metadata_obj() {
253
+ return this._input_metadata_obj;
254
+ }
255
+
256
+ get input_metadata() {
257
+ return this._metadata3;
258
+ }
259
+
260
+ get node_address() {
261
+ return this._metadata4;
262
+ }
263
+ }
264
+
265
+ module.exports = {
266
+ Order,
267
+ MetadataBase,
268
+ PayloadFactory,
269
+ InputFactory,
270
+ InputMetadataV0,
271
+ PayloadMetadataV0,
272
+ InputMetadataV1,
273
+ PayloadMetadataV1,
274
+ DOReqMetadata
275
+ }