[TSM.ID].[11031972] PXE : Platform X Ecosystem I [118 Module -LIVE-]

This commit is contained in:
TSM.ID
2026-05-25 03:51:34 +07:00
parent e820143b3c
commit 8f1a37129a
354 changed files with 0 additions and 0 deletions
@@ -0,0 +1,15 @@
# XCU IAM Gatekeeper Environment
# Lokasi: xcu-iam-gatekeeper/.env.example
# ==========================================
# Port Peladen
PORT=4001
# WebAuthn RP_ID (Domain Anda tanpa protokol/port)
WEBAUTHN_RP_ID=x.jumpa.id
# WebAuthn Expected Origin (Domain Anda beserta protokol, tanpa trailing slash)
WEBAUTHN_EXPECTED_ORIGIN=https://x.jumpa.id
# Secret JWT Kuantum
JWT_SECRET=UBAH-INI-DI-PRODUKSI-DENGAN-STRING-YANG-PANJANG
+14
View File
@@ -0,0 +1,14 @@
# [TSM.ID].[11031972] -- All Rights Reserved. Proprietary & Confidential.
[package]
name = "xcu-iam-gatekeeper"
version = "0.1.0"
edition = "2021"
authors = ["TSM.ID <tsm@tsm.id>"]
description = "[TSM.ID].[11031972] Identity Access Management gatekeeper engine"
[lib]
path = "rust_src/lib.rs"
[dependencies]
serde = { version = "1", features = ["derive"] }
serde_json = "1"
+7
View File
@@ -0,0 +1,7 @@
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install --production
COPY . .
EXPOSE 4001
CMD ["node", "server.js"]
@@ -0,0 +1,63 @@
{
"identities": {
"AEGIS-SUPREME-KD8FZJGACK-X": {
"role": "supreme_admin",
"tenant_id": "SUPREME-MODE",
"packages": [
"phase-1-to-75",
"aegis-synthetica",
"ouroboros-protocol"
]
},
"TENANT-JUMPAID-X99": {
"role": "tenant",
"tenant_id": "JUMPA.ID ENTERPRISE",
"packages": [
"JUMPA.ID OMNI-ENGINE"
]
}
},
"policies": {
"AEGIS-TENANT-101-ALPHA": {
"name": "JUMPA.ID Node 1",
"mfa_mode": "free",
"supreme_allowed": {
"biometric": true,
"optical": true,
"aegis": true
},
"tenant_enabled": {
"biometric": true,
"optical": true,
"aegis": true
}
},
"AEGIS-SUPREME-KD8FZJGACK-X": {
"name": "Supreme Command",
"mfa_mode": "free",
"supreme_allowed": {
"biometric": true,
"optical": true,
"aegis": true
},
"tenant_enabled": {
"biometric": true,
"optical": true,
"aegis": true
}
},
"TENANT-JUMPAID-X99": {
"name": "JUMPA.ID ENTERPRISE",
"supreme_allowed": {
"biometric": false,
"optical": false,
"aegis": true
},
"tenant_enabled": {
"biometric": true,
"optical": true,
"aegis": true
}
}
}
}
+487
View File
@@ -0,0 +1,487 @@
{
"name": "xcu-iam-gatekeeper",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "xcu-iam-gatekeeper",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"@simplewebauthn/server": "^13.3.0",
"cors": "^2.8.6",
"dotenv": "^17.4.2",
"jsonwebtoken": "^9.0.3",
"ws": "^8.20.0"
}
},
"node_modules/@hexagon/base64": {
"version": "1.1.28",
"resolved": "https://registry.npmjs.org/@hexagon/base64/-/base64-1.1.28.tgz",
"integrity": "sha512-lhqDEAvWixy3bZ+UOYbPwUbBkwBq5C1LAJ/xPC8Oi+lL54oyakv/npbA0aU2hgCsx/1NUd4IBvV03+aUBWxerw==",
"license": "MIT"
},
"node_modules/@levischuck/tiny-cbor": {
"version": "0.2.11",
"resolved": "https://registry.npmjs.org/@levischuck/tiny-cbor/-/tiny-cbor-0.2.11.tgz",
"integrity": "sha512-llBRm4dT4Z89aRsm6u2oEZ8tfwL/2l6BwpZ7JcyieouniDECM5AqNgr/y08zalEIvW3RSK4upYyybDcmjXqAow==",
"license": "MIT"
},
"node_modules/@peculiar/asn1-android": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/@peculiar/asn1-android/-/asn1-android-2.7.0.tgz",
"integrity": "sha512-iD3VskhVQnM4nE3PN9cBdPTR7JrqZy3FYk+uD2CeG6DUqKoANqaEfx0f7izPmW+Qm5JBM35ek+viLCmjy18ByQ==",
"license": "MIT",
"dependencies": {
"@peculiar/asn1-schema": "^2.7.0",
"asn1js": "^3.0.6",
"tslib": "^2.8.1"
}
},
"node_modules/@peculiar/asn1-cms": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/@peculiar/asn1-cms/-/asn1-cms-2.7.0.tgz",
"integrity": "sha512-hew63shtzzvBcSHbhm+cyAmKe6AIfinT9hzEqSPjDC6opTTMKmTkQ0gHuN2KsWlvqiKw1S/fS94fhag/FJkioQ==",
"license": "MIT",
"dependencies": {
"@peculiar/asn1-schema": "^2.7.0",
"@peculiar/asn1-x509": "^2.7.0",
"@peculiar/asn1-x509-attr": "^2.7.0",
"asn1js": "^3.0.6",
"tslib": "^2.8.1"
}
},
"node_modules/@peculiar/asn1-csr": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/@peculiar/asn1-csr/-/asn1-csr-2.7.0.tgz",
"integrity": "sha512-VVsAyGqErT9D1SY4aEqozThXMVI+ssVRiv2DDeYuvpBKLIgZ3hYs3Ay3u/VSoKq6ESFi9cf6rf3IOOzfwh7oMA==",
"license": "MIT",
"dependencies": {
"@peculiar/asn1-schema": "^2.7.0",
"@peculiar/asn1-x509": "^2.7.0",
"asn1js": "^3.0.6",
"tslib": "^2.8.1"
}
},
"node_modules/@peculiar/asn1-ecc": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/@peculiar/asn1-ecc/-/asn1-ecc-2.7.0.tgz",
"integrity": "sha512-n7KEs/Q/wrB415cxy4fHOBhegp4NdJ15fkJPwcB/3/8iNBQC2L/N7SChJPKDJPZGYH0jD4Tg4/0vnHmwghnbKw==",
"license": "MIT",
"dependencies": {
"@peculiar/asn1-schema": "^2.7.0",
"@peculiar/asn1-x509": "^2.7.0",
"asn1js": "^3.0.6",
"tslib": "^2.8.1"
}
},
"node_modules/@peculiar/asn1-pfx": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/@peculiar/asn1-pfx/-/asn1-pfx-2.7.0.tgz",
"integrity": "sha512-V/nrlQVmhg7lYAsM7E13UDL5erAwFv6kCIVFqNaMIHSVi7dngcT839JkRTkQBqznMG98l2XjxYk74ZztAohZzA==",
"license": "MIT",
"dependencies": {
"@peculiar/asn1-cms": "^2.7.0",
"@peculiar/asn1-pkcs8": "^2.7.0",
"@peculiar/asn1-rsa": "^2.7.0",
"@peculiar/asn1-schema": "^2.7.0",
"asn1js": "^3.0.6",
"tslib": "^2.8.1"
}
},
"node_modules/@peculiar/asn1-pkcs8": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs8/-/asn1-pkcs8-2.7.0.tgz",
"integrity": "sha512-9GTl1nE8Mx1kTZ+7QyYatDyKsm34QcWRBFkY1iPvWC3X4Dona5s/tlLiQsx5WzVdZqiMBZNYT0buyw4/vbhnjw==",
"license": "MIT",
"dependencies": {
"@peculiar/asn1-schema": "^2.7.0",
"@peculiar/asn1-x509": "^2.7.0",
"asn1js": "^3.0.6",
"tslib": "^2.8.1"
}
},
"node_modules/@peculiar/asn1-pkcs9": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs9/-/asn1-pkcs9-2.7.0.tgz",
"integrity": "sha512-Bh7m+OuIaSEllPQcSd9OSp93F4ROWH7sbITWV8MI+8dwsjE5111/87VxiWVvYFKyww3vp39geLv9ENqhwWHcew==",
"license": "MIT",
"dependencies": {
"@peculiar/asn1-cms": "^2.7.0",
"@peculiar/asn1-pfx": "^2.7.0",
"@peculiar/asn1-pkcs8": "^2.7.0",
"@peculiar/asn1-schema": "^2.7.0",
"@peculiar/asn1-x509": "^2.7.0",
"@peculiar/asn1-x509-attr": "^2.7.0",
"asn1js": "^3.0.6",
"tslib": "^2.8.1"
}
},
"node_modules/@peculiar/asn1-rsa": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/@peculiar/asn1-rsa/-/asn1-rsa-2.7.0.tgz",
"integrity": "sha512-/qvENQrXyTZURjMqSeofHul0JJt2sNSzSwk36pl2olkHbaioMQgrASDZAlHXl0xUlnVbHj0uGgOrBMTb5x2aJQ==",
"license": "MIT",
"dependencies": {
"@peculiar/asn1-schema": "^2.7.0",
"@peculiar/asn1-x509": "^2.7.0",
"asn1js": "^3.0.6",
"tslib": "^2.8.1"
}
},
"node_modules/@peculiar/asn1-schema": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.7.0.tgz",
"integrity": "sha512-W8ZfWzLmQnrcky+eh3tni4IozMdqBDiHWU0N+vve/UGjMaUs8c0L7A2oEdkBXS8rTpWDpK/aoI3DG/L/hxmxPg==",
"license": "MIT",
"dependencies": {
"@peculiar/utils": "^2.0.2",
"asn1js": "^3.0.6",
"tslib": "^2.8.1"
}
},
"node_modules/@peculiar/asn1-x509": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.7.0.tgz",
"integrity": "sha512-mUn9RRrkGDnG4ALfunDmzyRW5dg+sWCj/pfnCCqEHYbkGxEpvUt6iVJv8Yw1cyp6SWZ26ZE5oSmI5SqEaen15g==",
"license": "MIT",
"dependencies": {
"@peculiar/asn1-schema": "^2.7.0",
"@peculiar/utils": "^2.0.2",
"asn1js": "^3.0.6",
"tslib": "^2.8.1"
}
},
"node_modules/@peculiar/asn1-x509-attr": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/@peculiar/asn1-x509-attr/-/asn1-x509-attr-2.7.0.tgz",
"integrity": "sha512-NS8e7SOgXipkzUPLF/sce7ukpMpWjhxYsH0n6Y+bHYo4TTxOb95Zv7hqwSuL212mj5YxovjdOKQOgH1As3E94w==",
"license": "MIT",
"dependencies": {
"@peculiar/asn1-schema": "^2.7.0",
"@peculiar/asn1-x509": "^2.7.0",
"asn1js": "^3.0.6",
"tslib": "^2.8.1"
}
},
"node_modules/@peculiar/utils": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@peculiar/utils/-/utils-2.0.3.tgz",
"integrity": "sha512-+oL3HPFRIZ1St2K50lWCXiioIgSoxzz7R1J3uF6neO2yl1sgmpgY6XXJH4BdpoDkMWznQTeYF6oWNDZLCdQ4eQ==",
"license": "MIT",
"dependencies": {
"tslib": "^2.8.1"
}
},
"node_modules/@peculiar/x509": {
"version": "1.14.3",
"resolved": "https://registry.npmjs.org/@peculiar/x509/-/x509-1.14.3.tgz",
"integrity": "sha512-C2Xj8FZ0uHWeCXXqX5B4/gVFQmtSkiuOolzAgutjTfseNOHT3pUjljDZsTSxXFGgio54bCzVFqmEOUrIVk8RDA==",
"license": "MIT",
"dependencies": {
"@peculiar/asn1-cms": "^2.6.0",
"@peculiar/asn1-csr": "^2.6.0",
"@peculiar/asn1-ecc": "^2.6.0",
"@peculiar/asn1-pkcs9": "^2.6.0",
"@peculiar/asn1-rsa": "^2.6.0",
"@peculiar/asn1-schema": "^2.6.0",
"@peculiar/asn1-x509": "^2.6.0",
"pvtsutils": "^1.3.6",
"reflect-metadata": "^0.2.2",
"tslib": "^2.8.1",
"tsyringe": "^4.10.0"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@simplewebauthn/server": {
"version": "13.3.0",
"resolved": "https://registry.npmjs.org/@simplewebauthn/server/-/server-13.3.0.tgz",
"integrity": "sha512-MLHYFrYG8/wK2i+86XMhiecK72nMaHKKt4bo+7Q1TbuG9iGjlSdfkPWKO5ZFE/BX+ygCJ7pr8H/AJeyAj1EaTQ==",
"license": "MIT",
"dependencies": {
"@hexagon/base64": "^1.1.27",
"@levischuck/tiny-cbor": "^0.2.2",
"@peculiar/asn1-android": "^2.6.0",
"@peculiar/asn1-ecc": "^2.6.1",
"@peculiar/asn1-rsa": "^2.6.1",
"@peculiar/asn1-schema": "^2.6.0",
"@peculiar/asn1-x509": "^2.6.1",
"@peculiar/x509": "^1.14.3"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/asn1js": {
"version": "3.0.10",
"resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.10.tgz",
"integrity": "sha512-S2s3aOytiKdFRdulw2qPE51MzjzVOisppcVv7jVFR+Kw0kxwvFrDcYA0h7Ndqbmj0HkMIXYWaoj7fli8kgx1eg==",
"license": "BSD-3-Clause",
"dependencies": {
"pvtsutils": "^1.3.6",
"pvutils": "^1.1.5",
"tslib": "^2.8.1"
},
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/buffer-equal-constant-time": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
"integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
"license": "BSD-3-Clause"
},
"node_modules/cors": {
"version": "2.8.6",
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz",
"integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==",
"license": "MIT",
"dependencies": {
"object-assign": "^4",
"vary": "^1"
},
"engines": {
"node": ">= 0.10"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/dotenv": {
"version": "17.4.2",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz",
"integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==",
"license": "BSD-2-Clause",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://dotenvx.com"
}
},
"node_modules/ecdsa-sig-formatter": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
"integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
"license": "Apache-2.0",
"dependencies": {
"safe-buffer": "^5.0.1"
}
},
"node_modules/jsonwebtoken": {
"version": "9.0.3",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz",
"integrity": "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==",
"license": "MIT",
"dependencies": {
"jws": "^4.0.1",
"lodash.includes": "^4.3.0",
"lodash.isboolean": "^3.0.3",
"lodash.isinteger": "^4.0.4",
"lodash.isnumber": "^3.0.3",
"lodash.isplainobject": "^4.0.6",
"lodash.isstring": "^4.0.1",
"lodash.once": "^4.0.0",
"ms": "^2.1.1",
"semver": "^7.5.4"
},
"engines": {
"node": ">=12",
"npm": ">=6"
}
},
"node_modules/jwa": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz",
"integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==",
"license": "MIT",
"dependencies": {
"buffer-equal-constant-time": "^1.0.1",
"ecdsa-sig-formatter": "1.0.11",
"safe-buffer": "^5.0.1"
}
},
"node_modules/jws": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz",
"integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==",
"license": "MIT",
"dependencies": {
"jwa": "^2.0.1",
"safe-buffer": "^5.0.1"
}
},
"node_modules/lodash.includes": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
"integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==",
"license": "MIT"
},
"node_modules/lodash.isboolean": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
"integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==",
"license": "MIT"
},
"node_modules/lodash.isinteger": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
"integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==",
"license": "MIT"
},
"node_modules/lodash.isnumber": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
"integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==",
"license": "MIT"
},
"node_modules/lodash.isplainobject": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
"integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
"license": "MIT"
},
"node_modules/lodash.isstring": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
"integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==",
"license": "MIT"
},
"node_modules/lodash.once": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
"integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
"license": "MIT"
},
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"license": "MIT"
},
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/pvtsutils": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.6.tgz",
"integrity": "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==",
"license": "MIT",
"dependencies": {
"tslib": "^2.8.1"
}
},
"node_modules/pvutils": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.5.tgz",
"integrity": "sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==",
"license": "MIT",
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/reflect-metadata": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz",
"integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==",
"license": "Apache-2.0"
},
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT"
},
"node_modules/semver": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
"integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD"
},
"node_modules/tsyringe": {
"version": "4.10.0",
"resolved": "https://registry.npmjs.org/tsyringe/-/tsyringe-4.10.0.tgz",
"integrity": "sha512-axr3IdNuVIxnaK5XGEUFTu3YmAQ6lllgrvqfEoR16g/HGnYY/6We4oWENtAnzK6/LpJ2ur9PAb80RBt7/U4ugw==",
"license": "MIT",
"dependencies": {
"tslib": "^1.9.3"
},
"engines": {
"node": ">= 6.0.0"
}
},
"node_modules/tsyringe/node_modules/tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"license": "0BSD"
},
"node_modules/vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
"integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/ws": {
"version": "8.20.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz",
"integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
}
}
}
@@ -0,0 +1,21 @@
{
"name": "xcu-iam-gatekeeper",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"type": "commonjs",
"dependencies": {
"@simplewebauthn/server": "^13.3.0",
"cors": "^2.8.6",
"dotenv": "^17.4.2",
"jsonwebtoken": "^9.0.3",
"ws": "^8.20.0",
"ioredis": "^5.4.0"
}
}
@@ -0,0 +1,103 @@
//! [TSM.ID].[11031972] -- Platform X Ecosystem
//! xcu-iam-gatekeeper -- Identity Access Management gatekeeper engine
#![deny(warnings)]
use serde::{Serialize, Deserialize};
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
#[derive(Debug)]
pub enum BridgeError {
ConnectionFailed(String),
ConfigError(String),
OperationFailed(String),
NotReady,
}
impl std::fmt::Display for BridgeError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::ConnectionFailed(e) => write!(f, "Connection failed: {e}"),
Self::ConfigError(e) => write!(f, "Config error: {e}"),
Self::OperationFailed(e) => write!(f, "Op failed: {e}"),
Self::NotReady => write!(f, "Not ready"),
}
}
}
impl std::error::Error for BridgeError {}
pub type Result<T> = std::result::Result<T, BridgeError>;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BridgeConfig {
pub name: String,
pub endpoint: String,
pub params: HashMap<String, String>,
pub enabled: bool,
}
impl BridgeConfig {
pub fn new(name: &str, endpoint: &str) -> Self {
Self { name: name.to_string(), endpoint: endpoint.to_string(), params: HashMap::new(), enabled: true }
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum BridgeState { Disconnected, Connecting, Connected, Error(String) }
pub struct Bridge {
config: BridgeConfig,
state: Arc<Mutex<BridgeState>>,
message_count: Arc<Mutex<u64>>,
}
impl Bridge {
pub fn new(config: BridgeConfig) -> Result<Self> {
Ok(Self {
config, state: Arc::new(Mutex::new(BridgeState::Disconnected)),
message_count: Arc::new(Mutex::new(0)),
})
}
pub fn connect(&self) -> Result<()> {
let mut s = self.state.lock().map_err(|e| BridgeError::OperationFailed(e.to_string()))?;
*s = BridgeState::Connecting;
*s = BridgeState::Connected;
Ok(())
}
pub fn disconnect(&self) -> Result<()> {
let mut s = self.state.lock().map_err(|e| BridgeError::OperationFailed(e.to_string()))?;
*s = BridgeState::Disconnected;
Ok(())
}
pub fn send(&self, _payload: &[u8]) -> Result<u64> {
let s = self.state.lock().map_err(|e| BridgeError::OperationFailed(e.to_string()))?;
if *s != BridgeState::Connected { return Err(BridgeError::NotReady); }
drop(s);
let mut c = self.message_count.lock().map_err(|e| BridgeError::OperationFailed(e.to_string()))?;
*c += 1;
Ok(*c)
}
pub fn state(&self) -> Result<BridgeState> {
Ok(self.state.lock().map_err(|e| BridgeError::OperationFailed(e.to_string()))?.clone())
}
pub fn config(&self) -> &BridgeConfig { &self.config }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_bridge() {
let b = Bridge::new(BridgeConfig::new("xcu-iam-gatekeeper", "localhost:3000")).unwrap();
assert_eq!(b.state().unwrap(), BridgeState::Disconnected);
b.connect().unwrap();
assert_eq!(b.state().unwrap(), BridgeState::Connected);
b.send(b"hello").unwrap();
b.disconnect().unwrap();
assert_eq!(b.state().unwrap(), BridgeState::Disconnected);
}
}
+467
View File
@@ -0,0 +1,467 @@
// [TSM.ID].[11031972] -- All Rights Reserved. Proprietary & Confidential.
require('dotenv').config();
const { WebSocketServer } = require('ws');
const http = require('http');
const jwt = require('jsonwebtoken');
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
const { generateRegistrationOptions, verifyRegistrationResponse, generateAuthenticationOptions, verifyAuthenticationResponse } = require('@simplewebauthn/server');
const PORT = process.env.PORT || 4001;
const JWT_SECRET = process.env.JWT_SECRET;
if (!JWT_SECRET) { console.error('[3Z VIOLATION] JWT_SECRET env var MUST be set. Exiting.'); process.exit(1); }
const WEBAUTHN_RP_ID = process.env.WEBAUTHN_RP_ID || 'jumpa.id';
const WEBAUTHN_EXPECTED_ORIGIN = process.env.WEBAUTHN_EXPECTED_ORIGIN || 'https://jumpa.id';
const STATE_FILE = path.join(__dirname, 'iam_state.json');
// IAM Omni-Policy State
let iamState = {
identities: {
'AEGIS-SUPREME-974EFB44BE-X': {
role: 'supreme_admin',
tenant_id: 'SUPREME-MODE',
packages: ['phase-1-to-75', 'aegis-synthetica', 'ouroboros-protocol']
},
'AEGIS-TENANT-80AA3EEBE8-X': {
role: 'tenant',
tenant_id: 'JUMPA.ID ENTERPRISE',
packages: ['JUMPA.ID OMNI-ENGINE']
}
},
policies: {
'AEGIS-TENANT-80AA3EEBE8-X': {
name: 'JUMPA.ID ENTERPRISE',
mfa_mode: 'free', // 'free', 'strict', 'random'
supreme_allowed: {
biometric: true,
optical: true,
aegis: true
},
tenant_enabled: {
biometric: false,
optical: false,
aegis: true
}
}
}
};
const Redis = require('ioredis');
// Connect to Redis for live sync
const redisUrl = process.env.REDIS_URL || 'redis://127.0.0.1:6379';
const redis = new Redis(redisUrl);
redis.subscribe('AEGIS_IAM_STATE_CHANNEL', (err) => {
if (err) console.error('[IAM GATEKEEPER] Failed to subscribe to Redis:', err);
else console.log('[IAM GATEKEEPER] Subscribed to Redis channel AEGIS_IAM_STATE_CHANNEL');
});
redis.on('message', (channel, message) => {
if (channel === 'AEGIS_IAM_STATE_CHANNEL') {
try {
const newState = JSON.parse(message);
iamState = { ...iamState, ...newState };
console.log('[IAM GATEKEEPER] Synced state from Neural Relay (Redis)');
// Broadcast to connected WS clients
const broadcastData = JSON.stringify({ type: 'SYNC_IAM_POLICY', payload: iamState });
wss.clients.forEach(client => {
if (client.readyState === 1) client.send(broadcastData);
});
} catch (e) {
console.error('[IAM GATEKEEPER] Error parsing Redis message:', e);
}
}
});
const BILLING_MATRIX_URL = process.env.BILLING_MATRIX_URL || 'http://127.0.0.1:8082';
// Hydrate Policy from DuckDB / Billing Matrix
const hydrateState = async () => {
try {
const res = await fetch(`${BILLING_MATRIX_URL}/v1/iam/state`);
const loadedState = await res.json();
if (loadedState.identities && Object.keys(loadedState.identities).length > 0) {
iamState.identities = loadedState.identities;
iamState.policies = { ...iamState.policies, ...loadedState.policies };
console.log('[IAM GATEKEEPER] Successfully hydrated policies from DuckDB.');
} else {
console.log('[IAM GATEKEEPER] DuckDB state empty, using defaults. Seeding DB...');
saveStateToFile(); // Will actually post to DuckDB
}
} catch (err) {
console.error('[IAM GATEKEEPER] Failed to fetch state from DuckDB.', err.message);
}
};
hydrateState();
const saveStateToFile = () => {
fetch(`${BILLING_MATRIX_URL}/v1/iam/state`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(iamState)
}).catch(err => {
console.error('[IAM GATEKEEPER] Failed to save state to DuckDB.', err.message);
});
};
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain', 'Access-Control-Allow-Origin': '*' });
res.end('XCU IAM Aegis Gatekeeper + Policy Engine + Key Forge is Online.\n');
});
const wss = new WebSocketServer({ server });
let activeAuthSessions = {}; // { sessionId: { targetKeyId, sequence: [], currentIndex: 0, ws: websocket } }
wss.on('connection', (ws) => {
console.log('[IAM GATEKEEPER] Quantum Client Connected.');
// Send the current policy state and mapped keys immediately
ws.send(JSON.stringify({
type: 'SYNC_IAM_POLICY',
payload: iamState
}));
const opticalInterval = setInterval(() => {
if (ws.readyState === 1) {
ws.send(JSON.stringify({
type: 'OPTICAL_CHALLENGE',
payload: `XCU-OPT-${Math.random().toString(36).substr(2, 9).toUpperCase()}`
}));
}
}, 5000);
ws.on('message', async (message) => {
try {
const data = JSON.parse(message);
// ==========================================
// 1. POLICY MUTATION HUB (DevSecOps)
// ==========================================
if (data.type === 'UPDATE_IAM_POLICY') {
const { keyId, supreme_allowed, tenant_enabled, mfa_mode } = data.payload;
if (iamState.policies[keyId]) {
if (supreme_allowed) iamState.policies[keyId].supreme_allowed = supreme_allowed;
if (tenant_enabled) iamState.policies[keyId].tenant_enabled = tenant_enabled;
if (mfa_mode) iamState.policies[keyId].mfa_mode = mfa_mode;
saveStateToFile();
const broadcastData = JSON.stringify({ type: 'SYNC_IAM_POLICY', payload: iamState });
wss.clients.forEach(client => {
if (client.readyState === 1) client.send(broadcastData);
});
}
}
// ==========================================
// 2. AEGIS KEY FORGE (Zero-Database Credential Swap)
// ==========================================
if (data.type === 'REGENERATE_AEGIS_KEY') {
const { oldKeyId } = data.payload;
const identity = iamState.identities[oldKeyId];
if (identity) {
// Create new chaotic string
const newKeyString = `AEGIS-${identity.role === 'supreme_admin' ? 'SUPREME' : 'TENANT'}-${Math.random().toString(36).substr(2, 10).toUpperCase()}-X`;
// Move identity to new Key
iamState.identities[newKeyString] = identity;
delete iamState.identities[oldKeyId];
// If it's a tenant, move the policy as well
if (iamState.policies[oldKeyId]) {
iamState.policies[newKeyString] = iamState.policies[oldKeyId];
delete iamState.policies[oldKeyId];
}
saveStateToFile();
console.log(`[IAM FORGE] Key Rotated: ${oldKeyId} -> ${newKeyString}`);
// Send the new key back exclusively to the requester so they can download it
ws.send(JSON.stringify({
type: 'NEW_KEYCARD_GENERATED',
payload: { oldKeyId, newKeyString, role: identity.role }
}));
// Broadcast state to all
const broadcastData = JSON.stringify({ type: 'SYNC_IAM_POLICY', payload: iamState });
wss.clients.forEach(client => {
if (client.readyState === 1) client.send(broadcastData);
});
}
}
// ==========================================
// 2.5 WEBAUTHN HARDWARE BINDING (FASE 39)
// ==========================================
if (data.type === 'GENERATE_REGISTRATION_OPTIONS') {
const { targetKeyId } = data.payload;
const identity = iamState.identities[targetKeyId];
if (identity) {
const user = {
id: Buffer.from(targetKeyId).toString('base64url'),
name: targetKeyId,
displayName: identity.tenant_id
};
const options = await generateRegistrationOptions({
rpName: 'XCU Ultra Gatekeeper',
rpID: WEBAUTHN_RP_ID,
userID: user.id,
userName: user.name,
attestationType: 'none',
authenticatorSelection: {
residentKey: 'required',
userVerification: 'preferred',
}
});
iamState.identities[targetKeyId].currentChallenge = options.challenge;
ws.send(JSON.stringify({ type: 'REGISTRATION_OPTIONS', payload: options }));
}
}
if (data.type === 'VERIFY_REGISTRATION_RESPONSE') {
const { targetKeyId, response } = data.payload;
const identity = iamState.identities[targetKeyId];
if (identity && identity.currentChallenge) {
try {
const verification = await verifyRegistrationResponse({
response: response,
expectedChallenge: identity.currentChallenge,
expectedOrigin: WEBAUTHN_EXPECTED_ORIGIN,
expectedRPID: WEBAUTHN_RP_ID,
});
if (verification.verified) {
const { registrationInfo } = verification;
iamState.identities[targetKeyId].webAuthn = {
credentialID: Buffer.from(registrationInfo.credentialID).toString('base64url'),
credentialPublicKey: Buffer.from(registrationInfo.credentialPublicKey).toString('base64url'),
counter: registrationInfo.counter,
};
delete iamState.identities[targetKeyId].currentChallenge;
saveStateToFile();
ws.send(JSON.stringify({ type: 'REGISTRATION_SUCCESS', payload: 'Hardware Biometrik Berhasil Didaftarkan' }));
}
} catch (e) {
ws.send(JSON.stringify({ type: 'AUTH_FAILED', payload: 'WebAuthn Registration Failed: ' + e.message }));
}
}
}
if (data.type === 'GENERATE_AUTHENTICATION_OPTIONS') {
const options = await generateAuthenticationOptions({
rpID: 'localhost',
userVerification: 'required',
});
// Save challenge globally for verification later (since we don't know who is logging in yet)
iamState.globalAuthChallenge = options.challenge;
ws.send(JSON.stringify({ type: 'AUTHENTICATION_OPTIONS', payload: options }));
}
// ==========================================
// 2.8 AIR-GAPPED MOBILE PAIRING (FASE 41)
// ==========================================
if (data.type === 'GENERATE_OPTICAL_PAIRING') {
const { targetKeyId } = data.payload;
if (iamState.identities[targetKeyId]) {
const secret = crypto.randomBytes(32).toString('hex');
iamState.identities[targetKeyId].pendingOpticalSecret = secret;
ws.send(JSON.stringify({
type: 'OPTICAL_PAIRING_QR',
payload: `PAIR|${targetKeyId}|${secret}`
}));
}
}
if (data.type === 'CONFIRM_OPTICAL_PAIRING') {
const { targetKeyId, secret } = data.payload;
const identity = iamState.identities[targetKeyId];
if (identity && identity.pendingOpticalSecret === secret) {
identity.opticalSecret = secret;
delete identity.pendingOpticalSecret;
saveStateToFile();
ws.send(JSON.stringify({ type: 'OPTICAL_PAIRING_SUCCESS', payload: 'Perangkat Kuantum Berhasil Dikawinkan.' }));
} else {
ws.send(JSON.stringify({ type: 'AUTH_FAILED', payload: 'Gagal mengawinkan perangkat.' }));
}
}
// ==========================================
// 3. AEGIS AUTHENTICATION HUB (MFA ORCHESTRATOR)
// ==========================================
if (data.type === 'AEGIS_AUTH_REQUEST') {
const { authType, keyPayload, sessionId } = data.payload;
console.log(`[IAM GATEKEEPER] Auth Request: ${authType}`);
let targetKeyId = null;
if (authType === 'BIOMETRIC_PULSE') {
const response = keyPayload; // keyPayload is the credential response from browser
// Find which identity this credential belongs to
targetKeyId = Object.keys(iamState.identities).find(k =>
iamState.identities[k].webAuthn &&
iamState.identities[k].webAuthn.credentialID === response.id
);
if (targetKeyId && iamState.identities[targetKeyId].webAuthn) {
try {
const verification = await verifyAuthenticationResponse({
response: response,
expectedChallenge: iamState.globalAuthChallenge,
expectedOrigin: WEBAUTHN_EXPECTED_ORIGIN,
expectedRPID: WEBAUTHN_RP_ID,
authenticator: {
credentialID: Buffer.from(iamState.identities[targetKeyId].webAuthn.credentialID, 'base64url'),
credentialPublicKey: Buffer.from(iamState.identities[targetKeyId].webAuthn.credentialPublicKey, 'base64url'),
counter: iamState.identities[targetKeyId].webAuthn.counter,
}
});
if (verification.verified) {
const { authenticationInfo } = verification;
iamState.identities[targetKeyId].webAuthn.counter = authenticationInfo.newCounter;
saveStateToFile();
} else {
ws.send(JSON.stringify({ type: 'AUTH_FAILED', payload: 'Tanda Tangan Biometrik Tidak Valid.' }));
return;
}
} catch (e) {
ws.send(JSON.stringify({ type: 'AUTH_FAILED', payload: 'Gagal Memverifikasi Biometrik: ' + e.message }));
return;
}
} else {
ws.send(JSON.stringify({ type: 'AUTH_FAILED', payload: 'Hardware Biometrik Belum Terdaftar.' }));
return;
}
} else if (authType === 'AEGIS_KEYCARD') {
targetKeyId = keyPayload;
} else if (authType === 'OPTICAL_SYNC') {
// keyPayload carries { targetKeyId, signature, challenge }
targetKeyId = keyPayload.targetKeyId;
const identity = iamState.identities[targetKeyId];
if (!identity || !identity.opticalSecret) {
ws.send(JSON.stringify({ type: 'AUTH_FAILED', payload: 'Ponsel ini belum di-Pairing (Dikawinkan) di dalam Dasbor.' }));
return;
}
// Verify HMAC-SHA256 signature
const expectedSignature = crypto.createHmac('sha256', identity.opticalSecret)
.update(keyPayload.challenge)
.digest('hex');
if (keyPayload.signature !== expectedSignature) {
ws.send(JSON.stringify({ type: 'AUTH_FAILED', payload: 'Tanda Tangan Kriptografi Ponsel DITOLAK!' }));
return;
}
}
if (targetKeyId && iamState.identities[targetKeyId]) {
const identity = iamState.identities[targetKeyId];
const policy = iamState.policies[targetKeyId];
const typeMap = { 'BIOMETRIC_PULSE': 'biometric', 'OPTICAL_SYNC': 'optical', 'AEGIS_KEYCARD': 'aegis' };
const methodKey = typeMap[authType];
// === STRICT POLICY ENFORCEMENT CHECK ===
if (identity.role === 'tenant' && policy) {
if (!policy.supreme_allowed[methodKey]) {
ws.send(JSON.stringify({ type: 'AUTH_FAILED', payload: `ACCESS DENIED: Protokol [${methodKey}] telah dicabut secara absolut oleh Supreme Admin.` }));
return;
}
if (!policy.tenant_enabled[methodKey]) {
ws.send(JSON.stringify({ type: 'AUTH_FAILED', payload: `ACCESS DENIED: Anda telah menonaktifkan protokol [${methodKey}] di Security Enclave Anda.` }));
return;
}
}
// === MFA ORCHESTRATION ===
if (identity.role === 'tenant' && policy) {
const mode = policy.mfa_mode || 'free';
const activeLayers = ['biometric', 'optical', 'aegis'].filter(k => policy.supreme_allowed[k] && policy.tenant_enabled[k]);
if (mode !== 'free' && activeLayers.length > 1) {
// Multi-Factor required
if (!sessionId) {
// Initialize new session
const newSessionId = `MFA-SESS-${Math.random().toString(36).substr(2, 9).toUpperCase()}`;
let sequence = [...activeLayers];
if (mode === 'random') {
sequence = sequence.sort(() => Math.random() - 0.5);
}
// If the first step in sequence is what they just submitted, advance. Otherwise, reject and tell them the sequence
if (sequence[0] === methodKey) {
activeAuthSessions[newSessionId] = { targetKeyId, sequence, currentIndex: 1, ws };
ws.send(JSON.stringify({
type: 'MFA_STEP_REQUIRED',
payload: { sessionId: newSessionId, nextStep: sequence[1], sequence, currentIndex: 1 }
}));
return;
} else {
ws.send(JSON.stringify({
type: 'MFA_SEQUENCE_STARTED',
payload: { sessionId: newSessionId, sequence, currentIndex: 0, message: `Kebijakan Multi-Lapis Aktif. Anda wajib mematuhi urutan: ${sequence.join(' -> ').toUpperCase()}` }
}));
return;
}
} else {
// Advance existing session
const session = activeAuthSessions[sessionId];
if (!session || session.targetKeyId !== targetKeyId) {
ws.send(JSON.stringify({ type: 'AUTH_FAILED', payload: 'Sesi MFA tidak valid atau telah usang.' }));
return;
}
if (session.sequence[session.currentIndex] !== methodKey) {
ws.send(JSON.stringify({ type: 'AUTH_FAILED', payload: `Pelanggaran Urutan! Langkah yang diharapkan: ${session.sequence[session.currentIndex].toUpperCase()}` }));
delete activeAuthSessions[sessionId];
return;
}
session.currentIndex++;
if (session.currentIndex < session.sequence.length) {
ws.send(JSON.stringify({
type: 'MFA_STEP_REQUIRED',
payload: { sessionId, nextStep: session.sequence[session.currentIndex], sequence: session.sequence, currentIndex: session.currentIndex }
}));
return;
}
// If finished, delete session and grant access
delete activeAuthSessions[sessionId];
}
}
}
// Issue JWT if single-layer, free mode, or MFA completed
console.log('[IAM GATEKEEPER] Auth Successful. Issuing JWT.');
const token = jwt.sign({
role: identity.role,
tenant_id: identity.tenant_id,
used_gb: Math.random() * 50,
quota_limit_gb: 500,
packages: identity.packages
}, JWT_SECRET, { expiresIn: '24h' });
ws.send(JSON.stringify({ type: 'AUTH_SUCCESS', payload: { token } }));
} else {
console.warn('[IAM GATEKEEPER] Auth Failed. Invalid Key.');
ws.send(JSON.stringify({ type: 'AUTH_FAILED', payload: 'Kriptografi Gagal Divalidasi. Kunci Fisik ini mungkin sudah Hangus (Revoked).' }));
}
}
} catch (err) {
console.error('[IAM GATEKEEPER] Payload parsing error:', err);
}
});
ws.on('close', () => {
clearInterval(opticalInterval);
});
});
server.listen(PORT, () => {
console.log(`[IAM GATEKEEPER] Listening on ws://localhost:${PORT}`);
});