diff --git a/demo/server/.env.example b/demo/server/.env.example
index b0344f2..88aa944 100644
--- a/demo/server/.env.example
+++ b/demo/server/.env.example
@@ -1,9 +1,8 @@
NODE_ENV=local
-
-ENDPOINT=http://127.0.0.1
+ENDPOINT=http://127.0.0.1:3001
PORT=3001
-KERIA_URL=https://dev.keria.cf-keripy.metadata.dev.cf-deployments.org
-KERIA_BOOT_URL=https://dev.keria-boot.cf-keripy.metadata.dev.cf-deployments.org
+KERIA_URL=http://127.0.0.1:3901
+KERIA_BOOT_URL=http://127.0.0.1:3903
BRAN=o123456a89aacxeaCaxkk
SIGNIFY_NAME=enterpriseServer
DB_DATABASE=cf-poc-tunnel.sql
diff --git a/demo/server/.gitignore b/demo/server/.gitignore
index a3ca1c2..8dad582 100644
--- a/demo/server/.gitignore
+++ b/demo/server/.gitignore
@@ -1,3 +1,4 @@
dist
node_modules
.vscode
+cf-poc-tunnel.sql
diff --git a/demo/server/package-lock.json b/demo/server/package-lock.json
index 2f03d59..e59451c 100644
--- a/demo/server/package-lock.json
+++ b/demo/server/package-lock.json
@@ -9,28 +9,30 @@
"version": "0.0.1",
"license": "ISC",
"dependencies": {
- "axios": "^1.5.0",
"body-parser": "^1.20.2",
"cors": "^2.8.5",
"dotenv": "^16.3.1",
"express": "^4.18.2",
"node-cache": "^5.1.2",
- "signify-ts": "github:WebOfTrust/signify-ts#858dea2464eba8288318f147a8d3ab2640f5d625",
+ "signify-ts": "github:cardano-foundation/signify-ts#c47354267b193a18b3f7d2ddc5d1076f36a2e867",
"sqlite3": "^5.1.7",
"typeorm": "^0.3.20",
"uuid": "^9.0.1",
"ws": "^8.13.0"
},
"devDependencies": {
+ "@types/cors": "^2.8.17",
+ "@types/express": "^4.17.21",
+ "@types/uuid": "^9.0.8",
"nodemon": "^3.0.1",
"rimraf": "^5.0.1",
"ts-node": "^10.9.1"
}
},
"node_modules/@babel/runtime": {
- "version": "7.23.8",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.8.tgz",
- "integrity": "sha512-Y7KbAP984rn1VGMbGqKmBLio9V7y5Je9GvU4rQPCPinCyNfUcToxIXl06d59URp/F3LwinvODxab5N/G6qggkw==",
+ "version": "7.23.9",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz",
+ "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==",
"dependencies": {
"regenerator-runtime": "^0.14.0"
},
@@ -152,18 +154,6 @@
"url": "https://github.com/sponsors/isaacs"
}
},
- "node_modules/@npmcli/move-file/node_modules/mkdirp": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
- "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
- "optional": true,
- "bin": {
- "mkdirp": "bin/cmd.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
"node_modules/@npmcli/move-file/node_modules/rimraf": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
@@ -226,16 +216,118 @@
"integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
"devOptional": true
},
+ "node_modules/@types/body-parser": {
+ "version": "1.19.5",
+ "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz",
+ "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==",
+ "dev": true,
+ "dependencies": {
+ "@types/connect": "*",
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/connect": {
+ "version": "3.4.38",
+ "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz",
+ "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/cors": {
+ "version": "2.8.17",
+ "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz",
+ "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/express": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz",
+ "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==",
+ "dev": true,
+ "dependencies": {
+ "@types/body-parser": "*",
+ "@types/express-serve-static-core": "^4.17.33",
+ "@types/qs": "*",
+ "@types/serve-static": "*"
+ }
+ },
+ "node_modules/@types/express-serve-static-core": {
+ "version": "4.17.43",
+ "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.43.tgz",
+ "integrity": "sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "*",
+ "@types/qs": "*",
+ "@types/range-parser": "*",
+ "@types/send": "*"
+ }
+ },
+ "node_modules/@types/http-errors": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz",
+ "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==",
+ "dev": true
+ },
+ "node_modules/@types/mime": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz",
+ "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==",
+ "dev": true
+ },
"node_modules/@types/node": {
"version": "20.11.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.0.tgz",
"integrity": "sha512-o9bjXmDNcF7GbM4CNQpmi+TutCgap/K3w1JyKgxAjqx41zp9qlIAVFi0IhCNsJcXolEqLWhbFbEeL0PvYm4pcQ==",
"devOptional": true,
- "peer": true,
"dependencies": {
"undici-types": "~5.26.4"
}
},
+ "node_modules/@types/qs": {
+ "version": "6.9.11",
+ "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.11.tgz",
+ "integrity": "sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ==",
+ "dev": true
+ },
+ "node_modules/@types/range-parser": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz",
+ "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==",
+ "dev": true
+ },
+ "node_modules/@types/send": {
+ "version": "0.17.4",
+ "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz",
+ "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==",
+ "dev": true,
+ "dependencies": {
+ "@types/mime": "^1",
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/serve-static": {
+ "version": "1.15.5",
+ "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz",
+ "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==",
+ "dev": true,
+ "dependencies": {
+ "@types/http-errors": "*",
+ "@types/mime": "*",
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/uuid": {
+ "version": "9.0.8",
+ "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz",
+ "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==",
+ "dev": true
+ },
"node_modules/abbrev": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
@@ -424,21 +516,6 @@
"safer-buffer": "^2.1.0"
}
},
- "node_modules/asynckit": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
- "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
- },
- "node_modules/axios": {
- "version": "1.6.5",
- "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.5.tgz",
- "integrity": "sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==",
- "dependencies": {
- "follow-redirects": "^1.15.4",
- "form-data": "^4.0.0",
- "proxy-from-env": "^1.1.0"
- }
- },
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -586,16 +663,6 @@
"ieee754": "^1.2.1"
}
},
- "node_modules/buffer-writer": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz",
- "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==",
- "optional": true,
- "peer": true,
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/bytes": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
@@ -677,18 +744,6 @@
"node": ">=8"
}
},
- "node_modules/cacache/node_modules/mkdirp": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
- "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
- "optional": true,
- "bin": {
- "mkdirp": "bin/cmd.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
"node_modules/cacache/node_modules/rimraf": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
@@ -1044,17 +1099,6 @@
"color-support": "bin.js"
}
},
- "node_modules/combined-stream": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
- "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
- "dependencies": {
- "delayed-stream": "~1.0.0"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
"node_modules/complex.js": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/complex.js/-/complex.js-2.1.1.tgz",
@@ -1195,14 +1239,6 @@
"node": ">= 0.4"
}
},
- "node_modules/delayed-stream": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
- "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
- "engines": {
- "node": ">=0.4.0"
- }
- },
"node_modules/delegates": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
@@ -1476,25 +1512,6 @@
"node": ">= 0.8"
}
},
- "node_modules/follow-redirects": {
- "version": "1.15.4",
- "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz",
- "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==",
- "funding": [
- {
- "type": "individual",
- "url": "https://github.com/sponsors/RubenVerborgh"
- }
- ],
- "engines": {
- "node": ">=4.0"
- },
- "peerDependenciesMeta": {
- "debug": {
- "optional": true
- }
- }
- },
"node_modules/foreground-child": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz",
@@ -1510,19 +1527,6 @@
"url": "https://github.com/sponsors/isaacs"
}
},
- "node_modules/form-data": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
- "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
- "dependencies": {
- "asynckit": "^0.4.0",
- "combined-stream": "^1.0.8",
- "mime-types": "^2.1.12"
- },
- "engines": {
- "node": ">= 6"
- }
- },
"node_modules/forwarded": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
@@ -2461,17 +2465,14 @@
}
},
"node_modules/mkdirp": {
- "version": "2.1.6",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.6.tgz",
- "integrity": "sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A==",
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
"bin": {
- "mkdirp": "dist/cjs/src/bin.js"
+ "mkdirp": "bin/cmd.js"
},
"engines": {
"node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/mkdirp-classic": {
@@ -2751,13 +2752,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/packet-reader": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz",
- "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==",
- "optional": true,
- "peer": true
- },
"node_modules/parse5": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz",
@@ -2821,104 +2815,6 @@
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
"integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
},
- "node_modules/pg": {
- "version": "8.11.3",
- "resolved": "https://registry.npmjs.org/pg/-/pg-8.11.3.tgz",
- "integrity": "sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==",
- "optional": true,
- "peer": true,
- "dependencies": {
- "buffer-writer": "2.0.0",
- "packet-reader": "1.0.0",
- "pg-connection-string": "^2.6.2",
- "pg-pool": "^3.6.1",
- "pg-protocol": "^1.6.0",
- "pg-types": "^2.1.0",
- "pgpass": "1.x"
- },
- "engines": {
- "node": ">= 8.0.0"
- },
- "optionalDependencies": {
- "pg-cloudflare": "^1.1.1"
- },
- "peerDependencies": {
- "pg-native": ">=3.0.1"
- },
- "peerDependenciesMeta": {
- "pg-native": {
- "optional": true
- }
- }
- },
- "node_modules/pg-cloudflare": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz",
- "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==",
- "optional": true,
- "peer": true
- },
- "node_modules/pg-connection-string": {
- "version": "2.6.2",
- "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.2.tgz",
- "integrity": "sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==",
- "optional": true,
- "peer": true
- },
- "node_modules/pg-int8": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz",
- "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==",
- "optional": true,
- "peer": true,
- "engines": {
- "node": ">=4.0.0"
- }
- },
- "node_modules/pg-pool": {
- "version": "3.6.1",
- "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.1.tgz",
- "integrity": "sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og==",
- "optional": true,
- "peer": true,
- "peerDependencies": {
- "pg": ">=8.0"
- }
- },
- "node_modules/pg-protocol": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.0.tgz",
- "integrity": "sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==",
- "optional": true,
- "peer": true
- },
- "node_modules/pg-types": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz",
- "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==",
- "optional": true,
- "peer": true,
- "dependencies": {
- "pg-int8": "1.0.1",
- "postgres-array": "~2.0.0",
- "postgres-bytea": "~1.0.0",
- "postgres-date": "~1.0.4",
- "postgres-interval": "^1.1.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/pgpass": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz",
- "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==",
- "optional": true,
- "peer": true,
- "dependencies": {
- "split2": "^4.1.0"
- }
- },
"node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
@@ -2931,49 +2827,6 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
- "node_modules/postgres-array": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz",
- "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==",
- "optional": true,
- "peer": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/postgres-bytea": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz",
- "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==",
- "optional": true,
- "peer": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/postgres-date": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz",
- "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==",
- "optional": true,
- "peer": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/postgres-interval": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz",
- "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==",
- "optional": true,
- "peer": true,
- "dependencies": {
- "xtend": "^4.0.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/prebuild-install": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz",
@@ -3030,11 +2883,6 @@
"node": ">= 0.10"
}
},
- "node_modules/proxy-from-env": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
- "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
- },
"node_modules/pstree.remy": {
"version": "1.1.8",
"resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
@@ -3347,9 +3195,9 @@
}
},
"node_modules/signify-ts": {
- "version": "0.1.1",
- "resolved": "git+ssh://git@github.com/WebOfTrust/signify-ts.git#858dea2464eba8288318f147a8d3ab2640f5d625",
- "integrity": "sha512-RepDgvxY+j6t58btwrggytVHDYMcWzN76G3wrfp7HJPUG1uyaaoGmykaizUrISfSoH4+ICK7djwF9cwkANLAcA==",
+ "version": "0.2.0",
+ "resolved": "git+ssh://git@github.com/cardano-foundation/signify-ts.git#c47354267b193a18b3f7d2ddc5d1076f36a2e867",
+ "integrity": "sha512-+G0HglICQyh+g6JS4DGR0G6QpVhJuYqhcYL7yHUJeLX6Su2grUdVnosGBDDuEfztkTjBd/0ZbR/QGKIptMyt2Q==",
"license": "Apache-2.0",
"workspaces": [
"examples/*"
@@ -3480,16 +3328,6 @@
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"optional": true
},
- "node_modules/split2": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz",
- "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==",
- "optional": true,
- "peer": true,
- "engines": {
- "node": ">= 10.x"
- }
- },
"node_modules/sprintf-js": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
@@ -3727,17 +3565,6 @@
"node": ">=8"
}
},
- "node_modules/tar/node_modules/mkdirp": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
- "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
- "bin": {
- "mkdirp": "bin/cmd.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
"node_modules/thenify": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
@@ -3994,6 +3821,20 @@
}
}
},
+ "node_modules/typeorm/node_modules/mkdirp": {
+ "version": "2.1.6",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.6.tgz",
+ "integrity": "sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A==",
+ "bin": {
+ "mkdirp": "dist/cjs/src/bin.js"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
"node_modules/typeorm/node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@@ -4023,8 +3864,7 @@
"version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
- "devOptional": true,
- "peer": true
+ "devOptional": true
},
"node_modules/unique-filename": {
"version": "1.1.1",
@@ -4269,16 +4109,6 @@
}
}
},
- "node_modules/xtend": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
- "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
- "optional": true,
- "peer": true,
- "engines": {
- "node": ">=0.4"
- }
- },
"node_modules/y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
diff --git a/demo/server/package.json b/demo/server/package.json
index 062dde5..19b6dba 100644
--- a/demo/server/package.json
+++ b/demo/server/package.json
@@ -12,19 +12,21 @@
"author": "",
"license": "ISC",
"dependencies": {
- "axios": "^1.5.0",
"body-parser": "^1.20.2",
"cors": "^2.8.5",
"dotenv": "^16.3.1",
"express": "^4.18.2",
"node-cache": "^5.1.2",
- "signify-ts": "github:WebOfTrust/signify-ts#858dea2464eba8288318f147a8d3ab2640f5d625",
+ "signify-ts": "github:cardano-foundation/signify-ts#c47354267b193a18b3f7d2ddc5d1076f36a2e867",
"sqlite3": "^5.1.7",
"typeorm": "^0.3.20",
"uuid": "^9.0.1",
"ws": "^8.13.0"
},
"devDependencies": {
+ "@types/cors": "^2.8.17",
+ "@types/express": "^4.17.21",
+ "@types/uuid": "^9.0.8",
"nodemon": "^3.0.1",
"rimraf": "^5.0.1",
"ts-node": "^10.9.1"
diff --git a/demo/server/sendReq.ts b/demo/server/sendReq.ts
new file mode 100644
index 0000000..fa0eaea
--- /dev/null
+++ b/demo/server/sendReq.ts
@@ -0,0 +1,69 @@
+import { Cipher, Matter, MtrDex, b } from "signify-ts";
+import { config } from "./src/config";
+import {
+ getIdentifierByName,
+ getKeyManager,
+ getRemoteEncrypter,
+ initSignify,
+} from "./src/services/signifyService";
+
+async function run() {
+ const client = await initSignify();
+
+ const serverAid = await getIdentifierByName(config.signifyName);
+ const ourAid = await getIdentifierByName("test-aid");
+
+ const keyManager = await getKeyManager(ourAid);
+ const encrypter = await getRemoteEncrypter(serverAid.prefix);
+
+ const toEncrypt: Uint8Array = Buffer.from(
+ JSON.stringify({
+ src: ourAid.prefix,
+ data: {
+ inner: "some data!!",
+ },
+ }),
+ );
+ const cipher: Cipher = encrypter.encrypt(
+ null,
+ new Matter({ raw: toEncrypt, code: LEAD_CODES.get(toEncrypt.length % 3) }),
+ );
+
+ const datetime = new Date().toISOString().replace("Z", "000+00:00");
+ const resp = await client.signedFetch(
+ "http://localhost:3001",
+ "/ping",
+ "POST",
+ {
+ sig: keyManager.signers[0].sign(
+ b(
+ JSON.stringify({
+ src: ourAid.prefix,
+ dest: serverAid.prefix,
+ datetime,
+ cipher: cipher.qb64,
+ }),
+ ),
+ ).qb64,
+ cipher: cipher.qb64,
+ },
+ "test-aid",
+ datetime,
+ );
+ resp.headers.forEach(function (val, key) {
+ console.log(key + " -> " + val);
+ });
+ if (resp.ok) {
+ console.log(await resp.json());
+ } else {
+ console.log(await resp.text());
+ }
+}
+
+run();
+
+const LEAD_CODES = new Map([
+ [0, MtrDex.StrB64_L0],
+ [1, MtrDex.StrB64_L1],
+ [2, MtrDex.StrB64_L2],
+]);
diff --git a/demo/server/src/apis/acdc-requirements.api.ts b/demo/server/src/apis/acdc-requirements.api.ts
deleted file mode 100644
index 84b6344..0000000
--- a/demo/server/src/apis/acdc-requirements.api.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import { Request, Response } from "express";
-import { ResponseData } from "../types/response.type";
-import { httpResponse } from "../utils/response.util";
-import { config } from "../config";
-
-function getAcdcRequirements(_: Request, res: Response) {
- const acdcRequirements = {
- user: {
- "-s": config.qviSchemaSaid,
- },
- };
- const response: ResponseData = {
- statusCode: 200,
- success: true,
- data: acdcRequirements,
- };
- httpResponse(res, response);
-}
-
-export { getAcdcRequirements };
diff --git a/demo/server/src/apis/acdcRequirements.api.ts b/demo/server/src/apis/acdcRequirements.api.ts
new file mode 100644
index 0000000..9d63de6
--- /dev/null
+++ b/demo/server/src/apis/acdcRequirements.api.ts
@@ -0,0 +1,11 @@
+import { Request, Response } from "express";
+import { config } from "../config";
+
+export function getAcdcRequirements(_: Request, res: Response) {
+ const acdcRequirements = {
+ user: {
+ "-s": config.qviSchemaSaid,
+ },
+ };
+ res.status(200).send(acdcRequirements);
+}
diff --git a/demo/server/src/apis/discloseAcdc.api.ts b/demo/server/src/apis/discloseAcdc.api.ts
new file mode 100644
index 0000000..bbc0a3d
--- /dev/null
+++ b/demo/server/src/apis/discloseAcdc.api.ts
@@ -0,0 +1,21 @@
+import { Request, Response } from "express";
+import { disclosureAcdc } from "../services/signifyService";
+import { ERROR_ACDC_NOT_FOUND } from "../services/signifyService.types";
+
+export async function discloseAcdc(req: Request, res: Response) {
+ try {
+ await disclosureAcdc(
+ req.body.aidPrefix,
+ req.body.schemaSaid,
+ req.body.issuer,
+ );
+ return res.status(200).send();
+ } catch (error) {
+ if (error instanceof Error && error["message"] === ERROR_ACDC_NOT_FOUND) {
+ return res.status(409).send(error["message"]);
+ }
+ return res
+ .status(500)
+ .send(JSON.stringify(error, Object.getOwnPropertyNames(error)));
+ }
+}
diff --git a/demo/server/src/apis/disclosure-acdc.api.ts b/demo/server/src/apis/disclosure-acdc.api.ts
deleted file mode 100644
index 70a43a8..0000000
--- a/demo/server/src/apis/disclosure-acdc.api.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-import { Request, Response } from "express";
-import { ResponseData } from "../types/response.type";
-import { httpResponse } from "../utils/response.util";
-import { disclosureAcdc } from "../modules/signifyApi";
-import { ERROR_MESSAGE } from "../utils/constants";
-
-async function disclosureAcdcApi(req: Request, res: Response) {
- try {
- await disclosureAcdc(
- req.body.aidPrefix,
- req.body.schemaSaid,
- req.body.issuer,
- );
- const response: ResponseData = {
- statusCode: 200,
- success: true,
- data: null,
- };
- httpResponse(res, response);
- } catch (error) {
- if (error && error["message"] === ERROR_MESSAGE.ACDC_NOT_FOUND) {
- const response: ResponseData = {
- statusCode: 409,
- success: false,
- data: null,
- error: error["message"],
- };
- return httpResponse(res, response);
- }
- const response: ResponseData = {
- statusCode: 500,
- success: false,
- data: null,
- error: JSON.stringify(error, Object.getOwnPropertyNames(error)),
- };
- return httpResponse(res, response);
- }
-}
-
-export { disclosureAcdcApi };
diff --git a/demo/server/src/apis/handle-req-grant.ts b/demo/server/src/apis/handle-req-grant.ts
deleted file mode 100644
index b6c1dfc..0000000
--- a/demo/server/src/apis/handle-req-grant.ts
+++ /dev/null
@@ -1,66 +0,0 @@
-import { Request, Response } from "express";
-import { ResponseData } from "../types/response.type";
-import { httpResponse } from "../utils/response.util";
-import { getCredentials, getExnMessageBySaid } from "../modules/signifyApi";
-import { Session } from "../database/entities/session";
-import { dataSource } from "../database";
-import { config } from "../config";
-
-async function handleReqGrant(req: Request, res: Response) {
- const { said } = req.params;
- try {
- const exchange = await getExnMessageBySaid(said);
- const aid = exchange.exn.a.sid;
- const acdcs= await getCredentials({
- '-i': config.issuerAidPrefix,
- '-a-i': exchange.exn.i
- });
- if (!acdcs.length) {
- return httpResponse(res, {
- statusCode: 409,
- success: false,
- data: `AID have not completed the ACDC disclosure yet.`,
- });
- }
- const session = new Session();
- const latestAcdc = acdcs.reduce((latestObj, currentObj) => {
- const maxDateTime = latestObj.sad.a.dt;
- const currentDateTime = currentObj.sad.a.dt;
- return currentDateTime > maxDateTime ? currentObj : latestObj;
- });
-
- if (new Date(latestAcdc.sad.a.dt).getTime() < new Date().getTime() - 60000) {
- return httpResponse(res, {
- statusCode: 409,
- success: false,
- data: `Latest ACDC disclosure from ${exchange.exn.i} is too old`,
- });
- }
- const acdcSchema = latestAcdc.sad.s;
- if (acdcSchema === config.qviSchemaSaid) {
- session.role = 'user';
- };
- session.aid = aid;
- const currentTime = new Date().getTime();
- const sessionDuration = 5 * 60000; //5 mins
- session.validUntil = new Date(currentTime + sessionDuration);
- const entityManager = dataSource.manager;
- await entityManager.save(session);
- const response: ResponseData = {
- statusCode: 200,
- success: true,
- data: exchange,
- };
- httpResponse(res, response);
- } catch (error) {
- console.log(`handle req grant error:`, error);
- const response: ResponseData = {
- statusCode: 500,
- success: false,
- data: (error as Error).message,
- };
- httpResponse(res, response);
- }
-}
-
-export { handleReqGrant };
diff --git a/demo/server/src/apis/handleReqGrant.ts b/demo/server/src/apis/handleReqGrant.ts
new file mode 100644
index 0000000..8a2174c
--- /dev/null
+++ b/demo/server/src/apis/handleReqGrant.ts
@@ -0,0 +1,49 @@
+import { Request, Response } from "express";
+import { getCredentials, getExnMessageBySaid } from "../services/signifyService";
+import { Session } from "../database/entities/session";
+import { dataSource } from "../database";
+import { config } from "../config";
+
+async function handleReqGrant(req: Request, res: Response) {
+ const { said } = req.params;
+ try {
+ const exchange = await getExnMessageBySaid(said);
+ const aid = exchange.exn.a.sid;
+ const acdcs = await getCredentials({
+ "-i": config.issuerAidPrefix,
+ "-a-i": exchange.exn.i,
+ });
+ if (!acdcs.length) {
+ return res.status(409).send("AID has not completed the ACDC disclosure yet.");
+ }
+ const session = new Session();
+ const latestAcdc = acdcs.reduce((latestObj, currentObj) => {
+ const maxDateTime = latestObj.sad.a.dt;
+ const currentDateTime = currentObj.sad.a.dt;
+ return currentDateTime > maxDateTime ? currentObj : latestObj;
+ });
+
+ if (
+ new Date(latestAcdc.sad.a.dt).getTime() <
+ new Date().getTime() - 60000
+ ) {
+ return res.status(409).send(`Latest ACDC disclosure from ${exchange.exn.i} is too old`);
+ }
+ const acdcSchema = latestAcdc.sad.s;
+ if (acdcSchema === config.qviSchemaSaid) {
+ session.role = "user";
+ }
+ session.aid = aid;
+ const currentTime = new Date().getTime();
+ const sessionDuration = 5 * 60000; //5 mins
+ session.validUntil = new Date(currentTime + sessionDuration);
+ const entityManager = dataSource.manager;
+ await entityManager.save(session);
+ return res.status(200).send(exchange);
+ } catch (error) {
+ console.warn(`handle req grant error:`, error);
+ return res.status(500).send((error as Error).message);
+ }
+}
+
+export { handleReqGrant };
diff --git a/demo/server/src/apis/oobi.api.ts b/demo/server/src/apis/oobi.api.ts
index 66c85f5..f8c6a53 100644
--- a/demo/server/src/apis/oobi.api.ts
+++ b/demo/server/src/apis/oobi.api.ts
@@ -1,22 +1,13 @@
import { Request, Response } from "express";
-import { ResponseData } from "../types/response.type";
-import { httpResponse } from "../utils/response.util";
-import { getOOBIs, resolveOOBI } from "../modules/signifyApi";
+import { getOOBIs, resolveOOBI } from "../services/signifyService";
import { config } from "../config";
-async function resolveClientOOBI(req: Request, res: Response) {
+export async function resolveClientOOBI(req: Request, res: Response) {
const resolveOobiResult = await resolveOOBI(req.body.oobiUrl);
- const response: ResponseData = {
- statusCode: 200,
- success: true,
- data: resolveOobiResult,
- };
- httpResponse(res, response);
+ res.status(200).send(resolveOobiResult);
}
-async function getServerOOBI(_: Request, res: Response) {
+export async function getServerOOBI(_: Request, res: Response) {
const oobisResult = await getOOBIs(config.signifyName, "agent");
res.status(200).send(oobisResult);
}
-
-export { resolveClientOOBI, getServerOOBI };
diff --git a/demo/server/src/apis/ping.api.ts b/demo/server/src/apis/ping.api.ts
index 4c7e3ac..b6ac414 100644
--- a/demo/server/src/apis/ping.api.ts
+++ b/demo/server/src/apis/ping.api.ts
@@ -1,14 +1,10 @@
-import { Request, Response } from "express";
-import { ResponseData } from "../types/response.type";
-import { httpResponse } from "../utils/response.util";
+import { NextFunction, Request, Response } from "express";
-function ping(_: Request, res: Response) {
- const response: ResponseData = {
- statusCode: 200,
- success: true,
+export function ping(_: Request, res: Response, next: NextFunction) {
+ res.locals.responseBody = {
data: "pong",
};
- httpResponse(res, response);
+ res.set("Content-Type", "application/json");
+ res.status(200);
+ next();
}
-
-export { ping };
diff --git a/demo/server/src/apis/schema.api.ts b/demo/server/src/apis/schema.api.ts
index 79034e1..a99f83f 100644
--- a/demo/server/src/apis/schema.api.ts
+++ b/demo/server/src/apis/schema.api.ts
@@ -1,13 +1,11 @@
import { Request, Response } from "express";
-import { SCHEMA_ACDC } from "../utils/schemas/schemaAcdc";
+import { SCHEMAS } from "../schemas";
-async function schemaApi(req: Request, res: Response) {
+export async function getSchema(req: Request, res: Response) {
const { id } = req.params;
- const data = SCHEMA_ACDC[id];
+ const data = SCHEMAS.get(id);
if (!data) {
return res.status(404).send("Schema for given SAID not found");
}
return res.send(data);
}
-
-export { schemaApi };
diff --git a/demo/server/src/config.ts b/demo/server/src/config.ts
index dad7091..dd66020 100644
--- a/demo/server/src/config.ts
+++ b/demo/server/src/config.ts
@@ -9,7 +9,7 @@ const bran = process.env.BRAN as string;
const signifyName = process.env.SIGNIFY_NAME as string;
const issuerAidPrefix = process.env.ISSUER_AID_PREFIX;
-const config = {
+export const config = {
endpoint: endpoint,
endpoints: [endpoint],
port,
@@ -24,11 +24,9 @@ const config = {
schema: "/oobi/:id",
disclosureAcdc: "/disclosure-acdc",
acdcRequirements: "/acdc-requirements",
- handleReqGrant: "/handle-req-grant/:said"
+ handleReqGrant: "/handle-req-grant/:said",
},
domainSchemaSaid: "EGjD1gCLi9ecZSZp9zevkgZGyEX_MbOdmhBFt4o0wvdb",
qviSchemaSaid: "EBfdlu8R27Fbx-ehrqwImnK-8Cm79sqbAQ4MmvEAYqao",
issuerAidPrefix,
};
-
-export { config };
diff --git a/demo/server/src/database/entities/session.ts b/demo/server/src/database/entities/session.ts
index 59cbcef..fe0ea56 100644
--- a/demo/server/src/database/entities/session.ts
+++ b/demo/server/src/database/entities/session.ts
@@ -1,4 +1,4 @@
-import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
+import { Entity, Column, PrimaryGeneratedColumn } from "typeorm";
@Entity()
export class Session {
@@ -13,4 +13,4 @@ export class Session {
@Column()
validUntil: Date;
-}
\ No newline at end of file
+}
diff --git a/demo/server/src/database/index.ts b/demo/server/src/database/index.ts
index d024055..57d9bbe 100644
--- a/demo/server/src/database/index.ts
+++ b/demo/server/src/database/index.ts
@@ -3,8 +3,10 @@ dotenv.config();
import { DataSource } from "typeorm";
export const dataSource = new DataSource({
- type: "sqlite",
- database: process.env.DB_DATABASE ? process.env.DB_DATABASE : 'cf-poc-tunnel.sql',
- entities: ["src/database/entities/*.ts"],
- synchronize: process.env.NODE_ENV === 'production' ? false : true
- });
+ type: "sqlite",
+ database: process.env.DB_DATABASE
+ ? process.env.DB_DATABASE
+ : "cf-poc-tunnel.sql",
+ entities: ["src/database/entities/*.ts"],
+ synchronize: process.env.NODE_ENV === "production" ? false : true,
+});
diff --git a/demo/server/src/errors.ts b/demo/server/src/errors.ts
deleted file mode 100644
index 7c0607d..0000000
--- a/demo/server/src/errors.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-const MISSING_CONNECTION_ID = "Missing connectionId";
-const MISSING_DID_ID = "Missing did";
-const CONNECTION_NOT_FOUND = "Connection not found";
-
-export { MISSING_CONNECTION_ID, CONNECTION_NOT_FOUND, MISSING_DID_ID };
diff --git a/demo/server/src/middlewares/decryptVerifyRequest.middleware.ts b/demo/server/src/middlewares/decryptVerifyRequest.middleware.ts
new file mode 100644
index 0000000..5d15801
--- /dev/null
+++ b/demo/server/src/middlewares/decryptVerifyRequest.middleware.ts
@@ -0,0 +1,100 @@
+import { NextFunction, Request, Response } from "express";
+import { Authenticater, Cigar, Cipher, Decrypter } from "signify-ts";
+import { config } from "../config";
+import {
+ getIdentifierByName,
+ getRemoteVerfer,
+ getKeyManager,
+} from "../services/signifyService";
+
+export async function decryptVerifyRequest(
+ req: Request,
+ res: Response,
+ next: NextFunction,
+) {
+ const reqAid = req.get("Signify-Resource");
+ if (!reqAid) {
+ return res.status(400).send("Missing Signify-Resource header");
+ }
+
+ const reqDateTime = req.get("Signify-Timestamp");
+ if (!reqDateTime) {
+ return res.status(400).send("Missing Signify-Timestamp header");
+ }
+
+ // For now this isn't full protection - we need to verify that the request is unique.
+ // Follow up story will cover this.
+ if (Date.now() - new Date(reqDateTime).getTime() > 1000) {
+ return res.status(409).send("Signify-Timestamp too old");
+ }
+
+ const reqVerfer = await getRemoteVerfer(reqAid);
+ const serverAid = await getIdentifierByName(config.signifyName);
+ const keyManager = await getKeyManager(serverAid);
+
+ const authenticator = new Authenticater(
+ keyManager.signers[0], // Not used here, we only need to verify so just inject our own.
+ reqVerfer,
+ );
+
+ try {
+ if (
+ !authenticator.verify(
+ new Headers(JSON.parse(JSON.stringify(req.headers))),
+ req.method.toUpperCase(),
+ req.path.split("?")[0],
+ )
+ ) {
+ return res
+ .status(400)
+ .send("Signature headers not in the correct format");
+ }
+ } catch (error) {
+ console.warn(error);
+ // @TODO - foconnor: Catch this more specifically just in case.
+ return res
+ .status(400)
+ .send("Signature header not valid for given Signify-Resource");
+ }
+
+ if (req.body) {
+ if (!req.body.sig || !req.body.cipher) {
+ return res
+ .status(400)
+ .send("Body must contain a valid ESSR ciphertext and signature");
+ }
+
+ const signature = new Cigar({ qb64: req.body.sig }); // @TODO - foconnor: Will crash if not valid CESR - handle.
+ if (
+ !reqVerfer.verify(
+ signature.raw,
+ JSON.stringify({
+ src: reqAid,
+ dest: serverAid.prefix,
+ datetime: reqDateTime,
+ cipher: req.body.cipher,
+ }),
+ )
+ ) {
+ return res
+ .status(400)
+ .send("Signature of body is not valid for given Signify-Resource");
+ }
+
+ const cipher = new Cipher({ qb64: req.body.cipher }); // @TODO - foconnor: Same here.
+ const decrypter: Decrypter = new Decrypter({}, keyManager.signers[0].qb64b);
+ const decrypted = JSON.parse(
+ Buffer.from(decrypter.decrypt(null, cipher).raw).toString(),
+ );
+
+ if (!(decrypted.src && decrypted.src === reqAid)) {
+ return res
+ .status(400)
+ .send("Invalid src identifier in plaintext of cipher");
+ }
+
+ req.body = decrypted.data;
+ }
+
+ return next();
+}
diff --git a/demo/server/src/middlewares/encryptSignResponse.middleware.ts b/demo/server/src/middlewares/encryptSignResponse.middleware.ts
new file mode 100644
index 0000000..13a29e3
--- /dev/null
+++ b/demo/server/src/middlewares/encryptSignResponse.middleware.ts
@@ -0,0 +1,91 @@
+import { Request, Response } from "express";
+import { Authenticater, Cipher, Matter, MtrDex, b } from "signify-ts";
+import {
+ getIdentifierByName,
+ getRemoteEncrypter,
+ getKeyManager,
+} from "../services/signifyService";
+import { config } from "../config";
+import { EssrBody } from "../types";
+
+/**
+ * This middleware will sign any headers, the path and query params (pending in Signify).
+ * It will also encrypt and sign the body in accordance with KERI ESSR.
+ *
+ * A future interaction could try to encrypt the header/path/query params with ESSR too,
+ * but this would actually be better done at a transport layer within the browser rather than an extension.
+ */
+export async function encryptSignResponse(req: Request, res: Response) {
+ const reqAid = req.get("Signify-Resource");
+ if (!reqAid) {
+ // Shouldn't happen if decrypt middleware
+ return res.status(400).send("Missing Signify-Resource header");
+ }
+
+ const serverAid = await getIdentifierByName(config.signifyName);
+ const keyManager = await getKeyManager(serverAid);
+
+ // SIGN HEADERS
+ const authenticator = new Authenticater(
+ keyManager.signers[0],
+ keyManager.signers[0].verfer,
+ );
+
+ const originalHeaders = JSON.parse(JSON.stringify(res.getHeaders()));
+ const headers = new Headers(originalHeaders);
+
+ const datetime = new Date().toISOString().replace("Z", "000+00:00");
+ headers.set("Signify-Resource", serverAid.prefix);
+ headers.set("Signify-Timestamp", datetime);
+ const signedHeaders = authenticator?.sign(
+ headers,
+ req.method,
+ req.path.split("?")[0],
+ );
+ signedHeaders?.forEach((value, key) => {
+ res.set(key, value);
+ });
+
+ // SIGN BODY
+ if (res.locals.responseBody) {
+ const encrypter = await getRemoteEncrypter(reqAid);
+ const toEncrypt: Uint8Array = Buffer.from(
+ JSON.stringify({
+ src: serverAid.prefix,
+ data: res.locals.responseBody,
+ }),
+ );
+ const cipher: Cipher = encrypter.encrypt(
+ null,
+ new Matter({
+ raw: toEncrypt,
+ code: LEAD_CODES.get(toEncrypt.length % 3),
+ }),
+ );
+
+ // src, datetime are both already in the headers, and dest is already known by the receiver for this (src, dest) interaction.
+ const essrBody: EssrBody = {
+ sig: keyManager.signers[0].sign(
+ b(
+ JSON.stringify({
+ src: serverAid.prefix,
+ dest: reqAid,
+ datetime,
+ cipher: cipher.qb64,
+ }),
+ ),
+ ).qb64,
+ cipher: cipher.qb64,
+ };
+
+ return res.send(essrBody);
+ }
+
+ return res.send();
+}
+
+const LEAD_CODES = new Map([
+ [0, MtrDex.StrB64_L0],
+ [1, MtrDex.StrB64_L1],
+ [2, MtrDex.StrB64_L2],
+]);
diff --git a/demo/server/src/middlewares/index.ts b/demo/server/src/middlewares/index.ts
index 0e61ed6..2e5ae83 100644
--- a/demo/server/src/middlewares/index.ts
+++ b/demo/server/src/middlewares/index.ts
@@ -1,3 +1,3 @@
-export { signResponse } from './signResponse.middleware';
-export { verifyRequest } from './verifyRequest.middleware';
-export { verifySession } from './verifySession.middleware';
+export { encryptSignResponse } from "./encryptSignResponse.middleware";
+export { decryptVerifyRequest } from "./decryptVerifyRequest.middleware";
+export { verifySession } from "./verifySession.middleware";
diff --git a/demo/server/src/middlewares/signResponse.middleware.ts b/demo/server/src/middlewares/signResponse.middleware.ts
deleted file mode 100644
index 9ec37b1..0000000
--- a/demo/server/src/middlewares/signResponse.middleware.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-import { Request, Response } from "express";
-import { getIdentifierByName, getSigner } from "../modules/signifyApi";
-import { config } from "../config";
-import { Authenticater } from "signify-ts";
-
-export const signResponse = async (req: Request, res: Response, next) => {
- const serverAID = await getIdentifierByName(config.signifyName);
-
- const signer = await getSigner(serverAID);
-
- const authenticator = new Authenticater(
- signer.signers[0],
- signer.signers[0].verfer,
- );
-
- // Intercept the response
- const originalSend = res.send;
- res.send = function (body) {
- const originalHeaders = res.getHeaders();
- const headers = new Headers(originalHeaders);
- headers.set("Signify-Resource", serverAID.prefix);
- headers.set(
- "Signify-Timestamp",
- new Date().toISOString().replace("Z", "000+00:00"),
- );
- headers.set("Content-Type", "application/json");
- if (typeof body === "string") {
- headers.set("Content-Length", String(body.length));
- } else {
- headers.set("Content-Length", String(JSON.stringify(body.length)));
- }
- const signedHeaders = authenticator?.sign(
- headers,
- req.method,
- req.path.split("?")[0],
- );
- signedHeaders?.forEach((value, key) => {
- res.set(key, value);
- });
- originalSend.call(this, JSON.stringify(body));
- };
- next();
-};
diff --git a/demo/server/src/middlewares/verifyRequest.middleware.ts b/demo/server/src/middlewares/verifyRequest.middleware.ts
deleted file mode 100644
index 24197be..0000000
--- a/demo/server/src/middlewares/verifyRequest.middleware.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import { Request, Response } from "express";
-import { getIdentifierByName, getSigner } from "../modules/signifyApi";
-import { config } from "../config";
-import { Authenticater } from "signify-ts";
-
-export const verifyRequest = async (req: Request, res: Response, next) => {
- const serverAID = await getIdentifierByName(config.signifyName);
-
- const signer = await getSigner(serverAID);
-
- const authenticator = new Authenticater(
- signer.signers[0],
- signer.signers[0].verfer,
- );
-
- try {
- console.log("verifying...");
- const verification = authenticator?.verify(
- new Headers(req.headers),
- req.method,
- req.path.split("?")[0],
- );
- console.log({ verification });
- if (!verification) {
- res.status(400).send("Request was not signed correctly");
- } else {
- next();
- }
- } catch (error) {
- console.log({ error });
- res.status(500).send((error as Error).message);
- }
-};
diff --git a/demo/server/src/middlewares/verifySession.middleware.ts b/demo/server/src/middlewares/verifySession.middleware.ts
index d98107d..751b438 100644
--- a/demo/server/src/middlewares/verifySession.middleware.ts
+++ b/demo/server/src/middlewares/verifySession.middleware.ts
@@ -4,7 +4,7 @@ import { Session } from "../database/entities/session";
export const verifySession = (validRoles: string[]) => {
return async (req: Request, res: Response, next) => {
- const aid = req.headers['signify-resource'];
+ const aid = req.headers['signify-resource'] as string;
const sessionRepository = dataSource.getRepository(Session);
const session = await sessionRepository.findOne({
where: {
@@ -28,6 +28,6 @@ export const verifySession = (validRoles: string[]) => {
userAid: session.aid,
}
}
- next();
+ return next();
}
}
diff --git a/demo/server/src/routes.ts b/demo/server/src/routes.ts
index 5938356..097b2b4 100644
--- a/demo/server/src/routes.ts
+++ b/demo/server/src/routes.ts
@@ -1,21 +1,18 @@
-import express from 'express';
-import { config } from './config';
-import { ping } from './apis/ping.api';
-import { getServerOOBI, resolveClientOOBI } from './apis/oobi.api';
-import { schemaApi } from './apis/schema.api';
-import { disclosureAcdcApi } from './apis/disclosure-acdc.api';
-import { signResponse, verifyRequest, verifySession } from "./middlewares";
-import { getAcdcRequirements } from './apis/acdc-requirements.api';
-import { handleReqGrant } from './apis/handle-req-grant';
+import express from "express";
+import { config } from "./config";
+import { ping } from "./apis/ping.api";
+import { getServerOOBI, resolveClientOOBI } from "./apis/oobi.api";
+import { getSchema } from "./apis/schema.api";
+import { discloseAcdc } from "./apis/discloseAcdc.api";
+import { decryptVerifyRequest, encryptSignResponse } from "./middlewares";
+import { getAcdcRequirements } from "./apis/acdcRequirements.api";
+import { handleReqGrant } from "./apis/handleReqGrant";
-const router = express.Router();
-// Currently, I am testing the interceptor with the ping api
-router.get(config.path.ping, verifySession(['user']), verifyRequest, signResponse, ping);
+export const router = express.Router();
+router.post(config.path.ping, decryptVerifyRequest, ping, encryptSignResponse); // POST to test ESSR
router.post(config.path.resolveOOBI, resolveClientOOBI);
router.get(config.path.oobi, getServerOOBI);
-router.get(config.path.schema, schemaApi);
-router.post(config.path.disclosureAcdc, disclosureAcdcApi);
+router.get(config.path.schema, getSchema);
+router.post(config.path.disclosureAcdc, discloseAcdc);
router.get(config.path.acdcRequirements, getAcdcRequirements);
router.get(config.path.handleReqGrant, handleReqGrant);
-
-export default router;
diff --git a/demo/server/src/schemas.ts b/demo/server/src/schemas.ts
new file mode 100644
index 0000000..b3c1e2e
--- /dev/null
+++ b/demo/server/src/schemas.ts
@@ -0,0 +1,78 @@
+import { JSONValue } from "./types";
+
+export const SCHEMAS = new Map([
+ [
+ "EGjD1gCLi9ecZSZp9zevkgZGyEX_MbOdmhBFt4o0wvdb",
+ {
+ $id: "EGjD1gCLi9ecZSZp9zevkgZGyEX_MbOdmhBFt4o0wvdb",
+ $schema: "http://json-schema.org/draft-07/schema#",
+ title: "Domain registration credential",
+ description: "A credential issued for domain registration purposes",
+ type: "object",
+ credentialType: "DomainCredential",
+ version: "1.0.0",
+ properties: {
+ v: {
+ description: "Version",
+ type: "string",
+ },
+ d: {
+ description: "Credential SAID",
+ type: "string",
+ },
+ u: {
+ description: "One time use nonce",
+ type: "string",
+ },
+ i: {
+ description: "Issuee AID",
+ type: "string",
+ },
+ ri: {
+ description: "Credential status registry",
+ type: "string",
+ },
+ s: {
+ description: "Schema SAID",
+ type: "string",
+ },
+ a: {
+ oneOf: [
+ {
+ description: "Attributes block SAID",
+ type: "string",
+ },
+ {
+ $id: "EBeI53glWgRv27Rt_r-D5aXIGBTPVO3jMV7QQKkQzA2n",
+ description: "Attributes block",
+ type: "object",
+ properties: {
+ d: {
+ description: "Attributes block SAID",
+ type: "string",
+ },
+ i: {
+ description: "Issuee AID",
+ type: "string",
+ },
+ dt: {
+ description: "Issuance date time",
+ type: "string",
+ format: "date-time",
+ },
+ domain: {
+ description: "The domain address",
+ type: "string",
+ },
+ },
+ additionalProperties: false,
+ required: ["i", "dt", "domain"],
+ },
+ ],
+ },
+ },
+ additionalProperties: false,
+ required: ["i", "ri", "s", "d"],
+ },
+ ],
+]);
diff --git a/demo/server/src/server.ts b/demo/server/src/server.ts
index 5f57148..dda3522 100644
--- a/demo/server/src/server.ts
+++ b/demo/server/src/server.ts
@@ -2,21 +2,28 @@ import express from "express";
import cors from "cors";
import bodyParser from "body-parser";
import { config } from "./config";
-import router from "./routes";
-import { log } from "./log";
-import { initKeri, initSignify } from "./modules/signifyApi";
+import { router } from "./routes";
+import { log } from "./utils/log";
+import { initKeri, initSignify } from "./services/signifyService";
import { dataSource } from "./database";
-const signifyName = config.signifyName;
-log({ signifyName });
async function startServer() {
const app = express();
- await dataSource.initialize()
- console.log('Connected to database!');
+ await dataSource.initialize();
+ console.log("Connected to database!");
- app.use('/static', express.static('static'));
- app.use(cors());
+ app.use("/static", express.static("static"));
+ app.use(
+ cors({
+ exposedHeaders: [
+ "signature",
+ "signature-input",
+ "signify-resource",
+ "signify-timestamp",
+ ],
+ }),
+ );
app.use(bodyParser.json());
app.use(router);
@@ -31,7 +38,7 @@ async function startServer() {
name: identifier.name,
prefix: identifier.prefix,
oobi: oobi.oobis[0],
- acdc : credDomain.sad
+ acdc: credDomain.sad,
});
}
diff --git a/demo/server/src/modules/signifyApi.ts b/demo/server/src/services/signifyService.ts
similarity index 77%
rename from demo/server/src/modules/signifyApi.ts
rename to demo/server/src/services/signifyService.ts
index 5cbca31..4aa04a4 100644
--- a/demo/server/src/modules/signifyApi.ts
+++ b/demo/server/src/services/signifyService.ts
@@ -1,15 +1,17 @@
import {
Controller,
+ Encrypter,
+ Operation,
Serder,
SignifyClient,
ready as signifyReady,
Tier,
+ Verfer,
} from "signify-ts";
-import { Aid } from "../types/signifyApi.types";
+import { Aid, ERROR_ACDC_NOT_FOUND } from "./signifyService.types";
import { config } from "../config";
-import { log } from "../log";
+import { log } from "../utils/log";
import { v4 as uuidv4 } from "uuid";
-import { ERROR_MESSAGE } from "../utils/constants";
const { keriaUrl, keriaBootUrl } = config;
let signifyClient: SignifyClient;
@@ -54,21 +56,19 @@ export const createIdentifier = async (name: string) => {
};
export const getOOBIs = async (name: string, role: string) => {
- const oobisResult = await signifyClient.oobis().get(name, role);
- return oobisResult;
+ return signifyClient.oobis().get(name, role);
};
-export const resolveOOBI = async (url: string) => {
- let oobiOperation = await signifyClient.oobis().resolve(url);
- oobiOperation = await waitAndGetDoneOp(oobiOperation, 15000, 250);
- return oobiOperation;
+export const resolveOOBI = async (url: string): Promise> => {
+ const oobiOperation = await signifyClient.oobis().resolve(url);
+ return waitAndGetDoneOp(oobiOperation, 15000, 250);
};
-export const waitAndGetDoneOp = async (
- op: any,
+export const waitAndGetDoneOp = async (
+ op: Operation,
timeout: number,
interval: number,
-) => {
+): Promise> => {
const startTime = new Date().getTime();
while (!op.done && new Date().getTime() < startTime + timeout) {
op = await signifyClient.operations().get(op.name);
@@ -92,7 +92,7 @@ export const issueDomainCredential = async (
schemaSAID: string,
holder: string,
domain: string,
-) => {
+): Promise => {
const vcdata = {
domain,
};
@@ -149,7 +149,7 @@ export const disclosureAcdc = async (
const identifier = await getIdentifierByName(config.signifyName);
const acdc = await getServerAcdc(identifier.prefix, schemaSaid, issuer);
if (!acdc) {
- throw new Error(ERROR_MESSAGE.ACDC_NOT_FOUND);
+ throw new Error(ERROR_ACDC_NOT_FOUND);
}
const datetime = new Date().toISOString().replace("Z", "000+00:00");
const [grant2, gsigs2, gend2] = await signifyClient.ipex().grant({
@@ -181,7 +181,11 @@ export const initKeri = async () => {
const oobi = await getOOBIs(mainAidName, "agent");
// For the development purpose, the endpoint needs to be accessible from keria
const schemaUrl = config.endpoint + "/oobi/" + schemaSaid;
- await resolveOOBI(schemaUrl);
+ if (!(await resolveOOBI(schemaUrl)).done) {
+ throw new Error(
+ "Failed to resolve schema OOBI, endpoint most likely incorrect.",
+ );
+ }
let credDomain = await getServerAcdc(identifier.prefix, schemaSaid);
@@ -202,29 +206,39 @@ export const initKeri = async () => {
return { identifier, oobi, credDomain };
};
-export const getSigner = async (aid: Aid) => {
+export const getKeyManager = async (aid: Aid) => {
const client = await getSignifyClient();
- const signer = await client.manager?.get(aid);
- return signer;
+ return client.manager?.get(aid);
};
export const getServerSignifyController = async (): Promise => {
const client = await getSignifyClient();
return client.controller;
-}
+};
-export const getExnMessageBySaid = async (said: string) => {
+export const getRemoteVerfer = async (aid: string): Promise => {
const client = await getSignifyClient();
- const exchanges = await client.exchanges().get(said);
- return exchanges;
-}
+ const pubKey = (await client.keyStates().get(aid))[0].k[0];
+ return new Verfer({ qb64: pubKey });
+};
-export const getCredentials = async (filters?: any) => {
+export const getRemoteEncrypter = async (aid: string): Promise => {
+ const client = await getSignifyClient();
+ const pubKey = (await client.keyStates().get(aid))[0].k[0];
+ return new Encrypter({}, new Verfer({ qb64: pubKey }).qb64b);
+};
+
+export const getExnMessageBySaid = async (said: string): Promise => {
+ const client = await getSignifyClient();
+ return client.exchanges().get(said);
+};
+
+export const getCredentials = async (filters?: any): Promise => {
const client = await getSignifyClient();
if (filters) {
- return await client.credentials().list({
+ return client.credentials().list({
filter: filters,
});
}
- return await client.credentials().list();
-}
+ return client.credentials().list();
+};
diff --git a/demo/server/src/types/signifyApi.types.ts b/demo/server/src/services/signifyService.types.ts
similarity index 84%
rename from demo/server/src/types/signifyApi.types.ts
rename to demo/server/src/services/signifyService.types.ts
index 41f882b..a8336a6 100644
--- a/demo/server/src/types/signifyApi.types.ts
+++ b/demo/server/src/services/signifyService.types.ts
@@ -29,3 +29,6 @@ export interface Aid {
};
windexes: number[];
}
+
+export const ERROR_ACDC_NOT_FOUND =
+ "Unable to disclose ACDC with given requirements";
diff --git a/demo/server/src/types.ts b/demo/server/src/types.ts
new file mode 100644
index 0000000..242f8f0
--- /dev/null
+++ b/demo/server/src/types.ts
@@ -0,0 +1,12 @@
+export interface EssrBody {
+ sig: string;
+ cipher: JSONValue;
+}
+
+export type JSONValue = string | number | boolean | JSONObject | JSONArray;
+
+interface JSONObject {
+ [x: string]: JSONValue;
+}
+
+interface JSONArray extends Array {}
diff --git a/demo/server/src/types/response.type.ts b/demo/server/src/types/response.type.ts
deleted file mode 100644
index 73ce5fd..0000000
--- a/demo/server/src/types/response.type.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-interface ResponseData {
- data: T;
- error?: unknown;
- success: boolean;
- statusCode: number;
-}
-
-export type { ResponseData };
diff --git a/demo/server/src/utils/constants.ts b/demo/server/src/utils/constants.ts
deleted file mode 100644
index 79dd026..0000000
--- a/demo/server/src/utils/constants.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export enum ERROR_MESSAGE {
- ACDC_NOT_FOUND = "ACDC_NOT_FOUND",
-}
diff --git a/demo/server/src/log.ts b/demo/server/src/utils/log.ts
similarity index 56%
rename from demo/server/src/log.ts
rename to demo/server/src/utils/log.ts
index 6c91c0a..71dd52a 100644
--- a/demo/server/src/log.ts
+++ b/demo/server/src/utils/log.ts
@@ -1,6 +1,4 @@
-function log(...args: unknown[]) {
+export function log(...args: unknown[]) {
// eslint-disable-next-line no-console
console.log(...args);
}
-
-export { log };
diff --git a/demo/server/src/utils/node-cache.ts b/demo/server/src/utils/node-cache.ts
deleted file mode 100644
index e719fe6..0000000
--- a/demo/server/src/utils/node-cache.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import NodeCache from "node-cache";
-
-const myCache = new NodeCache();
-
-function setCache(key: string, value: string, ttl: number | string) {
- return myCache.set(key, value, ttl);
-}
-
-function getCache(key: string): string {
- return myCache.get(key) as string;
-}
-
-export { setCache, getCache };
diff --git a/demo/server/src/utils/response.util.ts b/demo/server/src/utils/response.util.ts
deleted file mode 100644
index 2758f6a..0000000
--- a/demo/server/src/utils/response.util.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { Response } from "express";
-import { ResponseData } from "../types/response.type";
-import { v4 as uuidv4 } from "uuid";
-import { config } from "../config";
-import { setCache } from "./node-cache";
-
-const MAX_LENGTH_URL_CAN_VIEW_QR_CODE = 200;
-const MAX_QR_CODE_TTL = 300;
-
-function httpResponse(res: Response, responseData: ResponseData) {
- res.status(responseData.statusCode).send(responseData);
-}
-
-function generableQRcodeWithUrl(url: string): string {
- if (url.length > MAX_LENGTH_URL_CAN_VIEW_QR_CODE) {
- const key = uuidv4();
- setCache(key, url, MAX_QR_CODE_TTL);
- return config.endpoint + "/shorten/" + key;
- }
- return url;
-}
-
-export { httpResponse, generableQRcodeWithUrl };
diff --git a/demo/server/src/utils/schemas/schemaAcdc.ts b/demo/server/src/utils/schemas/schemaAcdc.ts
deleted file mode 100644
index c5466ec..0000000
--- a/demo/server/src/utils/schemas/schemaAcdc.ts
+++ /dev/null
@@ -1,75 +0,0 @@
-const SCHEMA_ACDC = {
- EGjD1gCLi9ecZSZp9zevkgZGyEX_MbOdmhBFt4o0wvdb: {
- $id: "EGjD1gCLi9ecZSZp9zevkgZGyEX_MbOdmhBFt4o0wvdb",
- $schema: "http://json-schema.org/draft-07/schema#",
- title: "Domain registration credential",
- description: "A credential issued for domain registration purposes",
- type: "object",
- credentialType: "DomainCredential",
- version: "1.0.0",
- properties: {
- v: {
- description: "Version",
- type: "string",
- },
- d: {
- description: "Credential SAID",
- type: "string",
- },
- u: {
- description: "One time use nonce",
- type: "string",
- },
- i: {
- description: "Issuee AID",
- type: "string",
- },
- ri: {
- description: "Credential status registry",
- type: "string",
- },
- s: {
- description: "Schema SAID",
- type: "string",
- },
- a: {
- oneOf: [
- {
- description: "Attributes block SAID",
- type: "string",
- },
- {
- $id: "EBeI53glWgRv27Rt_r-D5aXIGBTPVO3jMV7QQKkQzA2n",
- description: "Attributes block",
- type: "object",
- properties: {
- d: {
- description: "Attributes block SAID",
- type: "string",
- },
- i: {
- description: "Issuee AID",
- type: "string",
- },
- dt: {
- description: "Issuance date time",
- type: "string",
- format: "date-time",
- },
- domain: {
- description: "The domain address",
- type: "string",
- },
- },
- additionalProperties: false,
- required: ["i", "dt", "domain"],
- },
- ],
- },
- },
- additionalProperties: false,
- required: ["i", "ri", "s", "d"],
- },
-};
-
-export { SCHEMA_ACDC };
diff --git a/demo/server/tsconfig.json b/demo/server/tsconfig.json
index 756c516..88f6b15 100644
--- a/demo/server/tsconfig.json
+++ b/demo/server/tsconfig.json
@@ -7,7 +7,7 @@
"target": "es2018",
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
- "noUnusedLocals": true,
+ "noUnusedLocals": false,
"pretty": true,
"strict": true,
"sourceMap": true,
@@ -18,7 +18,7 @@
"declaration": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
- "strictPropertyInitialization": false,
+ "strictPropertyInitialization": false
},
"include": ["src/**/*"],
"compileOnSave": false
diff --git a/demo/ui/.env.example b/demo/ui/.env.example
new file mode 100644
index 0000000..8ebd037
--- /dev/null
+++ b/demo/ui/.env.example
@@ -0,0 +1 @@
+VITE_SERVER_ENDPOINT=http://localhost:3001
diff --git a/demo/ui/package.json b/demo/ui/package.json
index bf4ea61..a9ab4dc 100644
--- a/demo/ui/package.json
+++ b/demo/ui/package.json
@@ -5,7 +5,7 @@
"type": "module",
"scripts": {
"dev": "vite",
- "build": "tsc && vite build",
+ "build": "tsc --noEmit && vite build",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
},
diff --git a/demo/ui/src/App.tsx b/demo/ui/src/App.tsx
index 565eb87..9dc50b7 100644
--- a/demo/ui/src/App.tsx
+++ b/demo/ui/src/App.tsx
@@ -1,57 +1,49 @@
-// src/App.tsx
-import React, { useEffect, useState } from "react";
+import React, { useState } from "react";
import govLogo from "./assets/gov.png";
import "./App.scss";
-import { createAxiosClient, ExtensionMessageType } from "./axiosClient";
+import { createAxiosClient } from "./extension/axiosClient";
import {
generateMessageId,
listenForExtensionMessage,
sendMessageToExtension,
-} from "./utils/extensionCommunication";
+} from "./extension/communication";
+import { ExtensionMessageType } from "./extension/types";
+
+const SERVER_ENDPOINT = import.meta.env.VITE_SERVER_ENDPOINT;
const App: React.FC = () => {
const [sessionCreated, setSessionCreated] = useState(false);
const [signedHeaders, setSignedHeaders] = useState>(
{},
);
+ const [responseBody, setResponseBody] = useState();
const handleCreateSession = async () => {
- const enterpriseData = {};
-
const messageId = generateMessageId(ExtensionMessageType.CREATE_SESSION);
-
const extMessage = listenForExtensionMessage>(
- ExtensionMessageType.SESSION_CREATED,
- messageId,
- );
-
- sendMessageToExtension(
+ ExtensionMessageType.CREATE_SESSION_RESULT,
messageId,
- ExtensionMessageType.CREATE_SESSION,
- enterpriseData,
);
- const { success } = await extMessage;
+ sendMessageToExtension({
+ id: messageId,
+ type: ExtensionMessageType.CREATE_SESSION,
+ data: {
+ url: SERVER_ENDPOINT,
+ },
+ });
- if (success) {
- setSessionCreated(true);
- }
+ await extMessage;
+ setSessionCreated(true);
};
const handleFetch = async () => {
- try {
- const axiosClient = createAxiosClient();
- const response = await axiosClient.get("http://localhost:3001/ping");
- console.log("Data:", response.data);
- } catch (error) {
- const serializedHeads = {};
- if (error.config.headers) {
- Object.entries(error.config.headers).forEach(([key, value]) => {
- serializedHeads[key] = value;
- });
- setSignedHeaders(serializedHeads);
- }
- }
+ const axiosClient = createAxiosClient();
+ const response = await axiosClient.post(`${SERVER_ENDPOINT}/ping`, {
+ dummy: "data",
+ });
+ setSignedHeaders(JSON.parse(JSON.stringify(response.headers)));
+ setResponseBody(response.data);
};
return (
@@ -85,6 +77,16 @@ const App: React.FC = () => {
>
) : null}
{" "}
+
+ {responseBody && (
+ <>
+
Decrypted response body
+
+
{JSON.stringify(responseBody, null, 2)}
+
+ >
+ )}
+
>
) : null}
>
diff --git a/demo/ui/src/axiosClient.ts b/demo/ui/src/axiosClient.ts
deleted file mode 100644
index b4e7db8..0000000
--- a/demo/ui/src/axiosClient.ts
+++ /dev/null
@@ -1,100 +0,0 @@
-import axios, {
- AxiosInstance,
- AxiosRequestHeaders,
- AxiosResponse,
- InternalAxiosRequestConfig,
-} from "axios";
-import {
- generateMessageId,
- listenForExtensionMessage,
- sendMessageToExtension,
-} from "./utils/extensionCommunication";
-
-enum ExtensionMessageType {
- SIGN_HEADERS = "SIGN_HEADERS",
- VERIFY_HEADERS = "VERIFY_HEADERS",
- HEADERS_VERIFIED = "HEADERS_VERIFIED",
- SIGNED_HEADERS = "SIGNED_HEADERS",
- CREATE_SESSION = "CREATE_SESSION",
- SESSION_CREATED = "SESSION_CREATED",
-}
-
-/**
- * Creates an Axios client configured with request and response interceptors.
- * @param apiURL The base URL for HTTP requests.
- * @returns client A configured Axios instance.
- *
- * The client includes a request interceptor to add signed headers to every request
- * by communicating with an extension. It also includes a response interceptor
- * to verify response headers with the extension, ensuring they meet
- * the expected security criteria.
- */
-const createAxiosClient = (): AxiosInstance => {
- const client = axios.create();
-
- client.interceptors.request.use(
- async (config: InternalAxiosRequestConfig) => {
- const serializedHeaders = {};
- if (config.headers) {
- Object.entries(config.headers).forEach(([key, value]) => {
- serializedHeaders[key] = value;
- });
- }
-
- const messageId = generateMessageId(ExtensionMessageType.SIGN_HEADERS);
-
- const extMessage = listenForExtensionMessage>(
- ExtensionMessageType.SIGNED_HEADERS,
- messageId,
- );
-
- sendMessageToExtension(messageId, ExtensionMessageType.SIGN_HEADERS, {
- headers: serializedHeaders,
- baseURL: config.baseURL,
- path: config.url,
- method: config.method,
- });
-
- const { signedHeaders } = await extMessage;
- config.headers = {
- ...config.headers,
- ...signedHeaders,
- } as AxiosRequestHeaders;
-
- return config;
- },
- (error) => {
- return Promise.reject(error);
- },
- );
-
- client.interceptors.response.use(
- async (response: AxiosResponse) => {
- const messageId = generateMessageId(ExtensionMessageType.SIGN_HEADERS);
-
- const extMessage = listenForExtensionMessage(
- ExtensionMessageType.HEADERS_VERIFIED,
- messageId,
- );
-
- sendMessageToExtension(messageId, ExtensionMessageType.VERIFY_HEADERS, {
- headers: response.headers,
- });
-
- const verificationResult = await extMessage;
-
- if (!verificationResult) {
- throw new Error("Response headers verification failed.");
- }
-
- return response;
- },
- async (error) => {
- return Promise.reject(error);
- },
- );
-
- return client;
-};
-
-export { createAxiosClient, ExtensionMessageType };
diff --git a/demo/ui/src/extension/axiosClient.ts b/demo/ui/src/extension/axiosClient.ts
new file mode 100644
index 0000000..9a719e3
--- /dev/null
+++ b/demo/ui/src/extension/axiosClient.ts
@@ -0,0 +1,93 @@
+import axios, {
+ AxiosInstance,
+ AxiosRequestHeaders,
+ AxiosResponse,
+ InternalAxiosRequestConfig,
+} from "axios";
+import {
+ generateMessageId,
+ listenForExtensionMessage,
+ sendMessageToExtension,
+} from "./communication";
+import { ExtensionMessageType, SignEncryptResponse } from "./types";
+
+/**
+ * Creates an Axios client configured with request and response interceptors.
+ * @returns client A configured Axios instance.
+ *
+ * The client includes a request interceptor to verify response signatures and decrypt any cipher material.
+ * It also includes a response interceptor to sign and/or encrypt the response.
+ */
+const createAxiosClient = (): AxiosInstance => {
+ const client = axios.create();
+
+ client.interceptors.request.use(
+ async (config: InternalAxiosRequestConfig) => {
+ const messageId = generateMessageId(
+ ExtensionMessageType.SIGN_ENCRYPT_REQ,
+ );
+ const extMessage = listenForExtensionMessage(
+ ExtensionMessageType.SIGN_ENCRPYT_REQ_RESULT,
+ messageId,
+ );
+
+ sendMessageToExtension({
+ id: messageId,
+ type: ExtensionMessageType.SIGN_ENCRYPT_REQ,
+ data: {
+ url: config.baseURL ? `${config.baseURL}/${config.url}` : config.url,
+ method: config.method?.toUpperCase(),
+ body: config.data,
+ },
+ });
+
+ const { signedHeaders, essrBody } = await extMessage;
+ config.headers = {
+ ...config.headers,
+ ...JSON.parse(JSON.stringify(signedHeaders)),
+ } as AxiosRequestHeaders;
+
+ config.data = essrBody;
+ return config;
+ },
+ (error) => {
+ return Promise.reject(error);
+ },
+ );
+
+ client.interceptors.response.use(
+ async (response: AxiosResponse) => {
+ const messageId = generateMessageId(
+ ExtensionMessageType.VERIFY_DECRYPT_RESP,
+ );
+ // Will throw if it does not verify.
+ const extMessage = listenForExtensionMessage(
+ ExtensionMessageType.VERIFY_DECRYPT_RESP_RESULT,
+ messageId,
+ );
+
+ sendMessageToExtension({
+ id: messageId,
+ type: ExtensionMessageType.VERIFY_DECRYPT_RESP,
+ data: {
+ url: response.config.baseURL
+ ? `${response.config.baseURL}/${response.config.url}`
+ : response.config.url,
+ method: response.config.method?.toUpperCase(),
+ headers: response.headers,
+ body: response.data,
+ },
+ });
+
+ response.data = await extMessage;
+ return response;
+ },
+ async (error) => {
+ return Promise.reject(error);
+ },
+ );
+
+ return client;
+};
+
+export { createAxiosClient };
diff --git a/demo/ui/src/utils/extensionCommunication.ts b/demo/ui/src/extension/communication.ts
similarity index 55%
rename from demo/ui/src/utils/extensionCommunication.ts
rename to demo/ui/src/extension/communication.ts
index 08e33c6..a7b3edc 100644
--- a/demo/ui/src/utils/extensionCommunication.ts
+++ b/demo/ui/src/extension/communication.ts
@@ -1,17 +1,14 @@
import { v4 as uuidv4 } from "uuid";
-
-export interface ExtensionMessage {
- type: string;
- data: any;
-}
+import { ExtensionMessageInbound, ExtensionMessageOutbound } from "./types";
const generateMessageId = (type: string) => {
return `${type}:${uuidv4()}`;
};
-const sendMessageToExtension = (id: string, type: string, data: any) => {
- const message = { id, type, data };
+
+const sendMessageToExtension = (
+ message: ExtensionMessageOutbound,
+): void => {
window.postMessage(message, "*");
- return message;
};
const listenForExtensionMessage = (
@@ -19,9 +16,18 @@ const listenForExtensionMessage = (
expectedId: string,
): Promise => {
return new Promise((resolve, reject) => {
- const handler = (event: MessageEvent) => {
- if (event.data?.id === expectedId && event.data?.type === type) {
+ const handler = (event: MessageEvent>) => {
+ if (event.data.id === expectedId && event.data.type === type) {
window.removeEventListener("message", handler);
+ if (!event.data.success) {
+ console.error(
+ `Received an unsuccessful error message: ${JSON.stringify(
+ event.data,
+ )}`,
+ );
+ reject(event.data.error);
+ return;
+ }
resolve(event.data.data as T);
}
};
diff --git a/demo/ui/src/extension/types.ts b/demo/ui/src/extension/types.ts
new file mode 100644
index 0000000..372ac68
--- /dev/null
+++ b/demo/ui/src/extension/types.ts
@@ -0,0 +1,31 @@
+enum ExtensionMessageType {
+ SIGN_ENCRYPT_REQ = "SIGN_ENCRYPT_REQ",
+ SIGN_ENCRPYT_REQ_RESULT = "SIGN_ENCRYPT_REQ_RESULT",
+ VERIFY_DECRYPT_RESP = "VERIFY_DECRYPT_RESP",
+ VERIFY_DECRYPT_RESP_RESULT = "VERIFY_DECRYPT_RESP_RESULT",
+ CREATE_SESSION = "CREATE_SESSION",
+ CREATE_SESSION_RESULT = "CREATE_SESSION_RESULT",
+}
+
+interface ExtensionMessageOutbound {
+ id: string;
+ type: ExtensionMessageType;
+ data: T;
+}
+
+type ExtensionMessageInbound = (
+ | { success: true; data: T }
+ | { success: false; error: unknown }
+) & { id: string; type: ExtensionMessageType };
+
+interface SignEncryptResponse {
+ signedHeaders: Headers;
+ essrBody?: any; // We just pass this directly though, so doesn't need strict typing.
+}
+
+export type {
+ ExtensionMessageInbound,
+ ExtensionMessageOutbound,
+ SignEncryptResponse,
+};
+export { ExtensionMessageType };
diff --git a/package-lock.json b/package-lock.json
index fc74651..459b663 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,7 +9,6 @@
"version": "0.1.0",
"license": "MIT",
"dependencies": {
- "json-canonicalize": "^1.0.6",
"lodash": "^4.17.21",
"react": "^18.2.0",
"react-dom": "^18.2.0",
@@ -20,10 +19,12 @@
},
"devDependencies": {
"@crxjs/vite-plugin": "^2.0.0-beta.21",
+ "@types/axios": "^0.14.0",
"@types/chrome": "^0.0.237",
"@types/lodash": "^4.14.197",
"@types/react": "^18.2.39",
"@types/react-dom": "^18.2.17",
+ "@types/uuid": "^9.0.8",
"@typescript-eslint/eslint-plugin": "^5.30.5",
"@typescript-eslint/parser": "^5.30.5",
"@vitejs/plugin-react": "^4.2.1",
@@ -33,7 +34,7 @@
"lint-staged": "^13.0.3",
"prettier": "^2.7.1",
"sass": "^1.53.0",
- "signify-ts": "github:WebOfTrust/signify-ts#8b2080744ffc9da3a43a71164b80db8796ea2284",
+ "signify-ts": "github:cardano-foundation/signify-ts#c47354267b193a18b3f7d2ddc5d1076f36a2e867",
"ts-node": "^10.9.1",
"typescript": "^4.7.4",
"vite": "^4.5.1",
@@ -367,9 +368,9 @@
}
},
"node_modules/@babel/runtime": {
- "version": "7.23.5",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.5.tgz",
- "integrity": "sha512-NdUTHcPe4C99WxPub+K9l9tK5/lV4UXIoaHSYgzco9BCyjKAAwzdBI+wWtYqHt7LJdbo74ZjRPJgzVweq1sz0w==",
+ "version": "7.23.9",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz",
+ "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==",
"dev": true,
"dependencies": {
"regenerator-runtime": "^0.14.0"
@@ -1141,6 +1142,16 @@
"integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
"dev": true
},
+ "node_modules/@types/axios": {
+ "version": "0.14.0",
+ "resolved": "https://registry.npmjs.org/@types/axios/-/axios-0.14.0.tgz",
+ "integrity": "sha512-KqQnQbdYE54D7oa/UmYVMZKq7CO4l8DEENzOKc4aBRwxCXSlJXGz83flFx5L7AWrOQnmuN3kVsRdt+GZPPjiVQ==",
+ "deprecated": "This is a stub types definition for axios (https://github.com/mzabriskie/axios). axios provides its own type definitions, so you don't need @types/axios installed!",
+ "dev": true,
+ "dependencies": {
+ "axios": "*"
+ }
+ },
"node_modules/@types/babel__core": {
"version": "7.20.5",
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
@@ -1270,6 +1281,12 @@
"integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==",
"dev": true
},
+ "node_modules/@types/uuid": {
+ "version": "9.0.8",
+ "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz",
+ "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==",
+ "dev": true
+ },
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "5.30.5",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.30.5.tgz",
@@ -1678,6 +1695,12 @@
"node": ">=8"
}
},
+ "node_modules/asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
+ "dev": true
+ },
"node_modules/available-typed-arrays": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz",
@@ -1690,6 +1713,17 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/axios": {
+ "version": "1.6.7",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz",
+ "integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==",
+ "dev": true,
+ "dependencies": {
+ "follow-redirects": "^1.15.4",
+ "form-data": "^4.0.0",
+ "proxy-from-env": "^1.1.0"
+ }
+ },
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -2186,6 +2220,18 @@
"integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==",
"dev": true
},
+ "node_modules/combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "dev": true,
+ "dependencies": {
+ "delayed-stream": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/commander": {
"version": "9.3.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-9.3.0.tgz",
@@ -2443,6 +2489,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
"node_modules/des.js": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz",
@@ -3179,6 +3234,26 @@
"integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==",
"dev": true
},
+ "node_modules/follow-redirects": {
+ "version": "1.15.5",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz",
+ "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/RubenVerborgh"
+ }
+ ],
+ "engines": {
+ "node": ">=4.0"
+ },
+ "peerDependenciesMeta": {
+ "debug": {
+ "optional": true
+ }
+ }
+ },
"node_modules/for-each": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
@@ -3188,6 +3263,20 @@
"is-callable": "^1.1.3"
}
},
+ "node_modules/form-data": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
+ "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
+ "dev": true,
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/fraction.js": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.4.tgz",
@@ -3851,11 +3940,6 @@
"node": ">=4"
}
},
- "node_modules/json-canonicalize": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/json-canonicalize/-/json-canonicalize-1.0.6.tgz",
- "integrity": "sha512-kP2iYpOS5SZHYhIaR1t9oG80d4uTY3jPoaBj+nimy3njtJk8+sRsVatN8pyJRDRtk9Su3+6XqA2U8k0dByJBUQ=="
- },
"node_modules/json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
@@ -4332,6 +4416,27 @@
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
"dev": true
},
+ "node_modules/mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "dev": true,
+ "dependencies": {
+ "mime-db": "1.52.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/mimic-fn": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
@@ -4925,6 +5030,12 @@
"node": ">= 0.6.0"
}
},
+ "node_modules/proxy-from-env": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
+ "dev": true
+ },
"node_modules/public-encrypt": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz",
@@ -5120,9 +5231,9 @@
}
},
"node_modules/regenerator-runtime": {
- "version": "0.14.0",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz",
- "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==",
+ "version": "0.14.1",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
+ "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
"dev": true
},
"node_modules/regexpp": {
@@ -5392,9 +5503,9 @@
"dev": true
},
"node_modules/signify-ts": {
- "version": "0.1.1",
- "resolved": "git+ssh://git@github.com/WebOfTrust/signify-ts.git#8b2080744ffc9da3a43a71164b80db8796ea2284",
- "integrity": "sha512-Doc2pYdihAVSSpwLhIfAnNJvSt6qBYh6XdkIx1wMELkoY4pyqgslgJcBAOATW+az2q4sdrM18Pe0lKuoS0WOBw==",
+ "version": "0.2.0",
+ "resolved": "git+ssh://git@github.com/cardano-foundation/signify-ts.git#c47354267b193a18b3f7d2ddc5d1076f36a2e867",
+ "integrity": "sha512-+G0HglICQyh+g6JS4DGR0G6QpVhJuYqhcYL7yHUJeLX6Su2grUdVnosGBDDuEfztkTjBd/0ZbR/QGKIptMyt2Q==",
"dev": true,
"license": "Apache-2.0",
"workspaces": [
@@ -6597,9 +6708,9 @@
}
},
"@babel/runtime": {
- "version": "7.23.5",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.5.tgz",
- "integrity": "sha512-NdUTHcPe4C99WxPub+K9l9tK5/lV4UXIoaHSYgzco9BCyjKAAwzdBI+wWtYqHt7LJdbo74ZjRPJgzVweq1sz0w==",
+ "version": "7.23.9",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz",
+ "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==",
"dev": true,
"requires": {
"regenerator-runtime": "^0.14.0"
@@ -7072,6 +7183,15 @@
"integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
"dev": true
},
+ "@types/axios": {
+ "version": "0.14.0",
+ "resolved": "https://registry.npmjs.org/@types/axios/-/axios-0.14.0.tgz",
+ "integrity": "sha512-KqQnQbdYE54D7oa/UmYVMZKq7CO4l8DEENzOKc4aBRwxCXSlJXGz83flFx5L7AWrOQnmuN3kVsRdt+GZPPjiVQ==",
+ "dev": true,
+ "requires": {
+ "axios": "*"
+ }
+ },
"@types/babel__core": {
"version": "7.20.5",
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
@@ -7201,6 +7321,12 @@
"integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==",
"dev": true
},
+ "@types/uuid": {
+ "version": "9.0.8",
+ "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz",
+ "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==",
+ "dev": true
+ },
"@typescript-eslint/eslint-plugin": {
"version": "5.30.5",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.30.5.tgz",
@@ -7469,12 +7595,29 @@
"integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
"dev": true
},
+ "asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
+ "dev": true
+ },
"available-typed-arrays": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz",
"integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==",
"dev": true
},
+ "axios": {
+ "version": "1.6.7",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz",
+ "integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==",
+ "dev": true,
+ "requires": {
+ "follow-redirects": "^1.15.4",
+ "form-data": "^4.0.0",
+ "proxy-from-env": "^1.1.0"
+ }
+ },
"balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -7828,6 +7971,15 @@
"integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==",
"dev": true
},
+ "combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "dev": true,
+ "requires": {
+ "delayed-stream": "~1.0.0"
+ }
+ },
"commander": {
"version": "9.3.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-9.3.0.tgz",
@@ -8044,6 +8196,12 @@
"object-keys": "^1.1.1"
}
},
+ "delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+ "dev": true
+ },
"des.js": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz",
@@ -8615,6 +8773,12 @@
"integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==",
"dev": true
},
+ "follow-redirects": {
+ "version": "1.15.5",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz",
+ "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==",
+ "dev": true
+ },
"for-each": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
@@ -8624,6 +8788,17 @@
"is-callable": "^1.1.3"
}
},
+ "form-data": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
+ "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
+ "dev": true,
+ "requires": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "mime-types": "^2.1.12"
+ }
+ },
"fraction.js": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.4.tgz",
@@ -9069,11 +9244,6 @@
"integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
"dev": true
},
- "json-canonicalize": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/json-canonicalize/-/json-canonicalize-1.0.6.tgz",
- "integrity": "sha512-kP2iYpOS5SZHYhIaR1t9oG80d4uTY3jPoaBj+nimy3njtJk8+sRsVatN8pyJRDRtk9Su3+6XqA2U8k0dByJBUQ=="
- },
"json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
@@ -9446,6 +9616,21 @@
}
}
},
+ "mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "dev": true
+ },
+ "mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "dev": true,
+ "requires": {
+ "mime-db": "1.52.0"
+ }
+ },
"mimic-fn": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
@@ -9859,6 +10044,12 @@
"integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
"dev": true
},
+ "proxy-from-env": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
+ "dev": true
+ },
"public-encrypt": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz",
@@ -9997,9 +10188,9 @@
}
},
"regenerator-runtime": {
- "version": "0.14.0",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz",
- "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==",
+ "version": "0.14.1",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
+ "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
"dev": true
},
"regexpp": {
@@ -10196,10 +10387,10 @@
"dev": true
},
"signify-ts": {
- "version": "git+ssh://git@github.com/WebOfTrust/signify-ts.git#8b2080744ffc9da3a43a71164b80db8796ea2284",
- "integrity": "sha512-Doc2pYdihAVSSpwLhIfAnNJvSt6qBYh6XdkIx1wMELkoY4pyqgslgJcBAOATW+az2q4sdrM18Pe0lKuoS0WOBw==",
+ "version": "git+ssh://git@github.com/cardano-foundation/signify-ts.git#c47354267b193a18b3f7d2ddc5d1076f36a2e867",
+ "integrity": "sha512-+G0HglICQyh+g6JS4DGR0G6QpVhJuYqhcYL7yHUJeLX6Su2grUdVnosGBDDuEfztkTjBd/0ZbR/QGKIptMyt2Q==",
"dev": true,
- "from": "signify-ts@github:WebOfTrust/signify-ts#8b2080744ffc9da3a43a71164b80db8796ea2284",
+ "from": "signify-ts@github:cardano-foundation/signify-ts#c47354267b193a18b3f7d2ddc5d1076f36a2e867",
"requires": {
"@noble/hashes": "^1.3.2",
"buffer": "^6.0.3",
diff --git a/package.json b/package.json
index 5a217dd..6ecdc93 100644
--- a/package.json
+++ b/package.json
@@ -4,7 +4,7 @@
"description": "Project Tunnel",
"scripts": {
"start": "vite",
- "build": "vite build",
+ "build": "tsc --noEmit && vite build",
"lint": "eslint --ext .ts,.js --max-warnings=0 .",
"prettier": "prettier --write ."
},
@@ -12,10 +12,12 @@
"license": "MIT",
"devDependencies": {
"@crxjs/vite-plugin": "^2.0.0-beta.21",
+ "@types/axios": "^0.14.0",
"@types/chrome": "^0.0.237",
"@types/lodash": "^4.14.197",
"@types/react": "^18.2.39",
"@types/react-dom": "^18.2.17",
+ "@types/uuid": "^9.0.8",
"@typescript-eslint/eslint-plugin": "^5.30.5",
"@typescript-eslint/parser": "^5.30.5",
"@vitejs/plugin-react": "^4.2.1",
@@ -25,7 +27,7 @@
"lint-staged": "^13.0.3",
"prettier": "^2.7.1",
"sass": "^1.53.0",
- "signify-ts": "github:WebOfTrust/signify-ts#8b2080744ffc9da3a43a71164b80db8796ea2284",
+ "signify-ts": "github:cardano-foundation/signify-ts#c47354267b193a18b3f7d2ddc5d1076f36a2e867",
"ts-node": "^10.9.1",
"typescript": "^4.7.4",
"vite": "^4.5.1",
diff --git a/public/manifest.json b/public/manifest.json
index 6a893c4..87f71d8 100644
--- a/public/manifest.json
+++ b/public/manifest.json
@@ -19,7 +19,7 @@
"externally_connectable": {
"matches": [""]
},
- "permissions": ["storage", "scripting", "tabs", "runtime"],
+ "permissions": ["storage", "scripting", "tabs"],
"host_permissions": ["*://*/*"],
"options_ui": {
"page": "src/ui/pages/options/index.html",
diff --git a/src/core/background/index.ts b/src/core/background/index.ts
index 8120544..28f1a1e 100644
--- a/src/core/background/index.ts
+++ b/src/core/background/index.ts
@@ -1,249 +1,499 @@
import { uid } from "uid";
+import { Authenticater, b, Cipher, Matter, Cigar, Decrypter } from "signify-ts";
import { SignifyApi } from "@src/core/modules/signifyApi";
-import { convertURLImageToBase64, serializeHeaders } from "@src/utils";
+import {
+ convertURLImageToBase64,
+ failure,
+ failureExt,
+ serializeHeaders,
+ success,
+ successExt,
+} from "@src/utils";
import { Logger } from "@src/utils/logger";
-import { Authenticater } from "signify-ts";
-import { ResponseData } from "@src/core/modules/signifyApi.types";
+import { LEAD_CODES } from "@src/core/modules/signifyApi.types";
+import {
+ EssrBody,
+ ExtensionMessage,
+ ResponseData,
+ ExtensionMessageType,
+} from "@src/core/background/types";
+import { Session } from "@src/ui/pages/popup/sessionList/sessionList";
+import { LOCAL_STORAGE_SESSIONS } from "@src/ui/pages/popup/sessionDetails/sessionDetails";
const SERVER_ENDPOINT = import.meta.env.VITE_SERVER_ENDPOINT;
-const expirationTime = 1800000; // 30 min
const signifyApi: SignifyApi = new SignifyApi();
const logger = new Logger();
-const checkSignify = async (): Promise => {
- if (!signifyApi.started) {
- await signifyApi.start();
+const signEncryptRequest = async (
+ ourAidName: string,
+ otherAidPrefix: string,
+ path: string,
+ method: string,
+ body?: any,
+): Promise<
+ ResponseData<{
+ signedHeaders: Headers;
+ essrBody?: EssrBody;
+ }>
+> => {
+ // @TODO - foconnor: Need a better short-hand way to return the result if it's not successful.
+ const getAidResult = await signifyApi.getIdentifierByName(ourAidName);
+ if (!getAidResult.success) {
+ return getAidResult;
}
-};
-const getCurrentTabDetails = async (): Promise<{
- hostname: string;
- port: string;
- pathname: string;
- favIconUrl: string;
-}> => {
- const queryOptions = { active: true, currentWindow: true };
- const [tab] = await chrome.tabs.query(queryOptions);
- const hostname = new URL(tab.url).hostname;
- const port = new URL(tab.url).port;
- const pathname = new URL(tab.url).pathname;
- const favIconUrl = tab.favIconUrl || "";
-
- return {
- hostname,
- port,
- pathname,
- favIconUrl,
+
+ const ourAid = getAidResult.data;
+ const getKeyManResult = await signifyApi.getKeyManager(ourAid);
+ if (!getKeyManResult.success) {
+ return getKeyManResult;
+ }
+
+ const authenticator = new Authenticater(
+ getKeyManResult.data.signers[0],
+ getKeyManResult.data.signers[0].verfer,
+ );
+
+ // For now we only sign the default Signify headers and not any extras.
+ const headers = new Headers();
+ headers.set("Signify-Resource", ourAid.prefix);
+ await logger.addLog(
+ `✅ Tunnel AID added to headers: ${JSON.stringify({
+ "Signify-Resource": ourAid.prefix,
+ })}`,
+ );
+
+ const datetime = new Date().toISOString().replace("Z", "000+00:00");
+ headers.set("Signify-Timestamp", datetime);
+ await logger.addLog(
+ `✅ Timestamp added to headers: ${JSON.stringify({
+ "Signify-Timestamp": datetime,
+ })}`,
+ );
+
+ let signedHeaders;
+ try {
+ signedHeaders = authenticator.sign(headers, method, path);
+ await logger.addLog(
+ `✍️ Headers signed successfully by tunnel AID: ${ourAid.prefix}`,
+ );
+ } catch (e) {
+ return {
+ success: false,
+ error: `Error while signing [${ourAidName}] headers ${JSON.stringify(
+ headers,
+ )}, method: ${method}, pathname: ${path}. Error: ${e}`,
+ };
+ }
+
+ if (!body) {
+ return success({ signedHeaders });
+ }
+
+ const getEncResult = await signifyApi.getRemoteEncrypter(otherAidPrefix);
+ if (!getEncResult.success) {
+ return getEncResult;
+ }
+
+ const toEncrypt: Uint8Array = Buffer.from(
+ JSON.stringify({
+ src: ourAid.prefix,
+ data: body,
+ }),
+ );
+ const cipher: Cipher = getEncResult.data.encrypt(
+ null,
+ new Matter({ raw: toEncrypt, code: LEAD_CODES.get(toEncrypt.length % 3) }),
+ );
+
+ // src, datetime are both already in the headers, and dest is already known by the receiver for this (src, dest) interaction.
+ const essrBody: EssrBody = {
+ sig: getKeyManResult.data.signers[0].sign(
+ b(
+ JSON.stringify({
+ src: ourAid.prefix,
+ dest: otherAidPrefix,
+ datetime,
+ cipher: cipher.qb64,
+ }),
+ ),
+ ).qb64,
+ cipher: cipher.qb64,
};
+
+ return success({ signedHeaders, essrBody });
};
-const signHeaders = async (
+const verifyDecryptResponse = async (
+ ourAidName: string,
+ otherAidPrefix: string,
path: string,
method: string,
- headersToSign: any,
- aidName: string,
-): Promise> => {
- try {
+ headers: Headers,
+ body?: any,
+): Promise> => {
+ const reqAid = headers.get("Signify-Resource");
+ if (!reqAid) {
+ return failure(new Error("Response missing Signify-Resource header"));
+ }
+ if (reqAid !== otherAidPrefix) {
+ return failure(new Error("Received response with a mismatched server AID"));
+ }
- const ephemeralAID = await signifyApi.getIdentifierByName(aidName);
+ const reqDateTime = headers.get("Signify-Timestamp");
+ if (!reqDateTime) {
+ return failure(new Error("Response missing Signify-Timestamp header"));
+ }
- if (ephemeralAID.success) {
- const signer = (await signifyApi.getSigner(ephemeralAID.data)).data;
+ // For now this isn't full protection - we need to verify that the request is unique.
+ // Follow up story will cover this.
+ if (Date.now() - new Date(reqDateTime).getTime() > 1000) {
+ return failure(new Error("Signify-Timestamp of response is too old"));
+ }
- const authenticator = new Authenticater(
- signer.signers[0],
- signer.signers[0].verfer,
- );
+ const getReqVerferResult = await signifyApi.getRemoveVerfer(reqAid);
+ if (!getReqVerferResult.success) {
+ return getReqVerferResult;
+ }
- const headers = new Headers();
- Object.entries(headersToSign).forEach(([key, value]) => {
- headers.append(key, value);
- });
+ const getAidResult = await signifyApi.getIdentifierByName(ourAidName);
+ if (!getAidResult.success) {
+ return getAidResult;
+ }
+ const getKeyManResult = await signifyApi.getKeyManager(getAidResult.data);
+ if (!getKeyManResult.success) {
+ return getKeyManResult;
+ }
- headers.set("Signify-Resource", ephemeralAID.data.prefix);
- await logger.addLog(
- `✅ Ephemeral AID added to headers: ${JSON.stringify({
- "Signify-Resource": ephemeralAID.data.prefix,
- })}`,
- );
+ const authenticator = new Authenticater(
+ getKeyManResult.data.signers[0], // Not used here, we only need to verify so just inject our own.
+ getReqVerferResult.data,
+ );
- const timestamp = new Date().toISOString().replace("Z", "000+00:00");
- headers.set("Signify-Timestamp", timestamp);
- await logger.addLog(
- `✅ Timestamp added to headers: ${JSON.stringify({
- "Signify-Timestamp": timestamp,
- })}`,
+ try {
+ if (!authenticator.verify(headers, method, path.split("?")[0])) {
+ return failure(new Error("Signify headers not in the correct format"));
+ }
+ } catch (error) {
+ console.warn(error);
+ // @TODO - foconnor: Catch this more specifically just in case.
+ return failure(
+ new Error("Signature header not valid for given Signify-Resource"),
+ );
+ }
+
+ if (body) {
+ if (!body.sig || !body.cipher) {
+ return failure(
+ new Error("Body must contain a valid ESSR ciphertext and signature"),
);
+ }
- try {
- const signedHeaders = authenticator.sign(headers, method, path);
+ const signature = new Cigar({ qb64: body.sig }); // @TODO - foconnor: Will crash if not valid CESR - handle.
+ if (
+ !getReqVerferResult.data.verify(
+ signature.raw,
+ JSON.stringify({
+ src: reqAid,
+ dest: getAidResult.data.prefix,
+ datetime: reqDateTime,
+ cipher: body.cipher,
+ }),
+ )
+ ) {
+ return failure(
+ new Error("Signature of body is not valid for given Signify-Resource"),
+ );
+ }
- await logger.addLog(
- `✍️ Headers signed successfully by ephemeral AID: ${ephemeralAID.data.prefix}`,
- );
+ const cipher = new Cipher({ qb64: body.cipher }); // @TODO - foconnor: Same here.
+ const decrypter: Decrypter = new Decrypter(
+ {},
+ getKeyManResult.data.signers[0].qb64b,
+ );
+ const decrypted = JSON.parse(
+ Buffer.from(decrypter.decrypt(null, cipher).raw).toString(),
+ );
- return {
- success: true,
- data: signedHeaders,
- };
- } catch (e) {
- return {
- success: false,
- error: `Error while signing.. headers: ${aidName}, method: ${method}, pathname: ${path}. Error: ${e}`,
- };
- }
- } else {
- return {
- success: false,
- error: `Error getting ephemeral AID with name: ${aidName}. Error: ${ephemeralAID.error}`,
- };
+ if (!(decrypted.src && decrypted.src === reqAid)) {
+ return failure(
+ new Error("Invalid src identifier in plaintext of cipher"),
+ );
}
- } catch (e) {
- return {
- success: false,
- error: e,
- };
+
+ return success(decrypted.data);
}
+
+ return success(undefined);
};
-const createSession = async (): Promise> => {
- let { hostname, port, favIconUrl } = await getCurrentTabDetails();
- if (port.length) {
- hostname = `${hostname}:${port}`;
- }
- hostname = hostname.replace(":", "-");
- const logo = await convertURLImageToBase64(favIconUrl);
+const createSession = async (): Promise> => {
+ // @TODO - foconnor: SERVER_ENDPOINT shouldn't be hardcoded.
+ const urlF = new URL(SERVER_ENDPOINT);
+ let response;
try {
- let response = await fetch(`${SERVER_ENDPOINT}/oobi`, {
- method: "GET",
- redirect: "follow",
- });
- await logger.addLog(`✅ OOBI URL from ${SERVER_ENDPOINT}/oobi`);
-
- response = await response.json();
- const oobiUrl = response.oobis[0];
- await logger.addLog(`⏳ Resolving OOBI URL...`);
+ response = await fetch(`${SERVER_ENDPOINT}/oobi`);
+ await logger.addLog(`✅ Received OOBI URL from ${SERVER_ENDPOINT}/oobi`);
+ } catch (e) {
+ return failure(
+ new Error(
+ `Error getting OOBI URL from server: ${SERVER_ENDPOINT}/oobi: ${e}`,
+ ),
+ );
+ }
- const resolvedOOBI = await signifyApi.resolveOOBI(oobiUrl);
+ const oobiUrl = (await response.json()).oobis[0];
+ await logger.addLog(`⏳ Resolving OOBI URL...`);
- await logger.addLog(`✅ OOBI resolved successfully`);
+ const resolveOobiResult = await signifyApi.resolveOOBI(oobiUrl);
+ if (!resolveOobiResult.success) {
+ return failure(
+ new Error(
+ `Error resolving OOBI URL ${oobiUrl}: ${resolveOobiResult.error}`,
+ ),
+ );
+ }
+ await logger.addLog(`✅ OOBI resolved successfully`);
+
+ const createIdentifierResult = await signifyApi.createIdentifier(
+ urlF.hostname,
+ );
+ if (!createIdentifierResult.success) {
+ return failure(
+ new Error(
+ `Error trying to create an AID with name ${urlF.hostname}: ${createIdentifierResult.error}`,
+ ),
+ );
+ }
- if (resolvedOOBI.success) {
- try {
- await signifyApi.createIdentifier(hostname);
+ const getOobiResult = await signifyApi.createOOBI(urlF.hostname);
+ if (!getOobiResult.success) {
+ return failure(
+ new Error(
+ `Error getting OOBI for identifier with name ${urlF.hostname}: ${getOobiResult.error}`,
+ ),
+ );
+ }
- await logger.addLog(
- `✅ AID created successfully with name ${hostname}`,
- );
+ await logger.addLog(`✅ AID created successfully with name ${urlF.hostname}`);
- const ephemeralAID = await signifyApi.getIdentifierByName(hostname);
+ try {
+ await fetch(`${SERVER_ENDPOINT}/resolve-oobi`, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ oobiUrl: getOobiResult.data.oobis[0] }),
+ });
+ } catch (e) {
+ return failure(
+ new Error(`Error triggering server to resolve tunnel OOBI: ${e}`),
+ );
+ }
- const newSession = {
- id: uid(24),
- tunnelAid: ephemeralAID.data.prefix,
- expiryDate: "",
- name: hostname,
- logo,
- oobi: resolvedOOBI?.data,
- createdAt: Date.now()
- };
+ await logger.addLog(
+ `✅ Server has resolved our OOBI for identifier ${urlF.hostname}`,
+ );
+
+ const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
+ const newSession: Session = {
+ id: uid(24),
+ tunnelAid: createIdentifierResult.data.serder.ked.i,
+ serverAid: oobiUrl.split("/oobi/")[1].split("/")[0], // todo get from oobiresult
+ expiryDate: "",
+ name: urlF.hostname,
+ logo: tab.favIconUrl ? await convertURLImageToBase64(tab.favIconUrl) : "",
+ oobi: resolveOobiResult.data,
+ createdAt: Date.now(),
+ };
- const { sessions } = await chrome.storage.local.get(["sessions"]);
- const sessionsArray = sessions || [];
- sessionsArray.push(newSession);
+ const { sessions } = await chrome.storage.local.get([LOCAL_STORAGE_SESSIONS]);
+ const sessionsArray = sessions || [];
+ sessionsArray.push(newSession);
+ await chrome.storage.local.set({ sessions: sessionsArray });
- await chrome.storage.local.set({ sessions: sessionsArray });
+ await logger.addLog(
+ `🗃 New session stored in db: ${JSON.stringify(newSession)}`,
+ );
- await logger.addLog(
- `🗃 New session stored in db: ${JSON.stringify(sessionsArray)}`,
- );
- return { success: true };
- } catch (e) {
- return {
- success: false,
- error: `Error trying to create an AID with name: ${hostname}`,
- };
- }
- } else {
- return {
- success: false,
- error: ` Error while resolving the OOBI URL from server: ${SERVER_ENDPOINT}/oobi`,
- };
- }
- } catch (e) {
- await logger.addLog(
- `❌ Error getting OOBI URL from server: ${SERVER_ENDPOINT}/oobi`,
- );
- return { success: false, type: "SESSION_CREATED" };
- }
+ return success(undefined);
};
+
chrome.runtime.onInstalled.addListener(async () => {
await logger.addLog(`✅ Extension successfully installed!`);
- await checkSignify();
+ if (!signifyApi.started) {
+ await signifyApi.start();
+ }
await logger.addLog(`✅ Signify initialized successfully`);
});
-chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
- processMessage(request).then((response) => sendResponse(response));
+chrome.runtime.onMessage.addListener((request, _, sendResponse) => {
+ processMessage(request)
+ .then((response) => response && sendResponse(response))
+ .catch(console.error);
return true;
});
-async function processMessage(message) {
- if (!message) return;
+function getReturnMessageType(
+ inbound: ExtensionMessageType,
+): ExtensionMessageType {
+ switch (inbound) {
+ case ExtensionMessageType.CREATE_SESSION:
+ return ExtensionMessageType.CREATE_SESSION_RESULT;
+ case ExtensionMessageType.SIGN_ENCRYPT_REQ:
+ return ExtensionMessageType.SIGN_ENCRPYT_REQ_RESULT;
+ case ExtensionMessageType.VERIFY_DECRYPT_RESP:
+ return ExtensionMessageType.VERIFY_DECRYPT_RESP_RESULT;
+ default:
+ return ExtensionMessageType.GENERIC_ERROR;
+ }
+}
+async function processMessage(
+ message: any,
+): Promise | undefined> {
+ // @TODO - foconnor: Need better handling of message.data to avoid crashing.
switch (message.type) {
- case "CREATE_SESSION": {
- const session = await createSession();
+ case ExtensionMessageType.CREATE_SESSION: {
+ const { url } = message.data;
+
+ const urlF = new URL(url);
+ const { sessions } = await chrome.storage.local.get([
+ LOCAL_STORAGE_SESSIONS,
+ ]);
+ if (
+ sessions &&
+ sessions.find((session: Session) => session.name === urlF.hostname)
+ ) {
+ return successExt(
+ message.id,
+ getReturnMessageType(message.type),
+ "Session previously created before, ignoring.",
+ );
+ }
- if (session.success) {
+ const createSessionResult = await createSession();
+ if (createSessionResult.success) {
await logger.addLog(`✅ Session created successfully`);
- return { type: "SESSION_CREATED", id: message.id, data: session };
+ return successExt(
+ message.id,
+ getReturnMessageType(message.type),
+ createSessionResult.data,
+ );
} else {
- await logger.addLog(`❌ ${session.error}`);
- return { type: "SESSION_CREATED", id: message.id, data: session };
+ await logger.addLog(`❌ ${createSessionResult.error}`);
+ return failureExt(
+ message.id,
+ getReturnMessageType(message.type),
+ createSessionResult.error,
+ );
}
}
- case "SIGN_HEADERS": {
- const pathname = message.data.path;
- const method = message.data.method;
- const headers = message.data.headers;
-
- let { hostname, port } = await getCurrentTabDetails();
- if (port.length) {
- hostname = `${hostname}:${port}`;
+ case ExtensionMessageType.SIGN_ENCRYPT_REQ: {
+ const { url, method, body } = message.data;
+
+ const urlF = new URL(url);
+ const { sessions } = await chrome.storage.local.get([
+ LOCAL_STORAGE_SESSIONS,
+ ]);
+ if (!sessions) {
+ return failureExt(
+ message.id,
+ ExtensionMessageType.SIGN_ENCRPYT_REQ_RESULT,
+ new Error(`Session not found for host ${urlF.hostname}`),
+ );
+ }
+ const session: Session = sessions.find(
+ (session: Session) => session.name === urlF.hostname,
+ );
+ if (!session) {
+ // @TODO - foconnor: Here we should call connect with that hostname - allows us to call other hosts than the one the UI is hosted on.
+ return failureExt(
+ message.id,
+ ExtensionMessageType.SIGN_ENCRPYT_REQ_RESULT,
+ new Error(`Session not found for host ${urlF.hostname}`),
+ );
}
- hostname = hostname.replace(":", "-");
- const signedHeaders = await signHeaders(
- pathname,
+ // @TODO - foconnor: Using one AID per domain/hostname means a UI can call other domains and expose
+ // the AID you use to talk to those. Ignore for now, especially since:
+ // 1) Tunnel is ephemeral
+ // 2) Identity wallet <-> Tunnel uses a different AID.
+ const encryptSignResult = await signEncryptRequest(
+ urlF.hostname,
+ session.serverAid,
+ urlF.pathname,
method,
- headers,
- hostname,
+ body,
);
- if (signedHeaders.success) {
- await logger.addLog(
- `📤 Signed headers sent to the website. Headers: ${JSON.stringify(
- serializeHeaders(signedHeaders.data),
- )}`,
+ if (!encryptSignResult.success) {
+ return failureExt(
+ message.id,
+ getReturnMessageType(message.type),
+ new Error(
+ `❌ Error while signing. Error: ${encryptSignResult.error}`,
+ ),
);
+ }
- return {
- success: true,
- type: "SIGNED_HEADERS",
- id: message.id,
- data: {
- signedHeaders: serializeHeaders(signedHeaders.data),
- },
- };
- } else {
- await logger.addLog(
- `❌ Error while signing. Error: ${signedHeaders.error}`,
+ await logger.addLog(
+ `📤 Request signed and encrypted. Headers: ${JSON.stringify(
+ serializeHeaders(encryptSignResult.data.signedHeaders),
+ )} // Body: ${JSON.stringify(encryptSignResult.data.essrBody)}`,
+ );
+
+ return successExt(message.id, getReturnMessageType(message.type), {
+ ...encryptSignResult.data,
+ signedHeaders: serializeHeaders(encryptSignResult.data.signedHeaders),
+ });
+ }
+ case ExtensionMessageType.VERIFY_DECRYPT_RESP: {
+ const { url, method, headers, body } = message.data;
+
+ // We don't trust requests for other domains until they show ACDC etc.
+ const urlF = new URL(url);
+ const { sessions } = await chrome.storage.local.get([
+ LOCAL_STORAGE_SESSIONS,
+ ]);
+ if (!sessions) {
+ return failureExt(
+ message.id,
+ getReturnMessageType(message.type),
+ new Error(`Session not found for host ${urlF.hostname}`),
+ );
+ }
+ const session: Session = sessions.find(
+ (session: Session) => session.name === urlF.hostname,
+ );
+ if (!session) {
+ // @TODO - foconnor: Here we should call connect with that hostname - allows us to call other hosts than the one the UI is hosted on.
+ return failureExt(
+ message.id,
+ getReturnMessageType(message.type),
+ new Error(`Session not found for host ${urlF.hostname}`),
+ );
+ }
+
+ const verifyDecryptResult = await verifyDecryptResponse(
+ urlF.hostname,
+ session.serverAid,
+ urlF.pathname,
+ method,
+ new Headers(headers),
+ body,
+ );
+ if (!verifyDecryptResult.success) {
+ return failureExt(
+ message.id,
+ getReturnMessageType(message.type),
+ verifyDecryptResult.error,
);
- return { success: false, type: "SIGNED_HEADERS", id: message.id, };
}
+
+ return successExt(
+ message.id,
+ getReturnMessageType(message.type),
+ verifyDecryptResult.data,
+ );
}
}
}
-
-export { expirationTime };
diff --git a/src/core/background/types.ts b/src/core/background/types.ts
new file mode 100644
index 0000000..281aab3
--- /dev/null
+++ b/src/core/background/types.ts
@@ -0,0 +1,32 @@
+export interface EssrBody {
+ sig: string;
+ cipher: JSONValue;
+}
+
+export type JSONValue = string | number | boolean | JSONObject | JSONArray;
+
+interface JSONObject {
+ [x: string]: JSONValue;
+}
+
+interface JSONArray extends Array {}
+
+export type ResponseData =
+ | { success: true; data: T }
+ | { success: false; error: unknown };
+
+// These should be in a common types package.
+export enum ExtensionMessageType {
+ SIGN_ENCRYPT_REQ = "SIGN_ENCRYPT_REQ",
+ SIGN_ENCRPYT_REQ_RESULT = "SIGN_ENCRYPT_REQ_RESULT",
+ VERIFY_DECRYPT_RESP = "VERIFY_DECRYPT_RESP",
+ VERIFY_DECRYPT_RESP_RESULT = "VERIFY_DECRYPT_RESP_RESULT",
+ CREATE_SESSION = "CREATE_SESSION",
+ CREATE_SESSION_RESULT = "CREATE_SESSION_RESULT",
+ GENERIC_ERROR = "ERROR_STREAM",
+}
+
+export type ExtensionMessage = ResponseData & {
+ id: string;
+ type: ExtensionMessageType;
+};
diff --git a/src/core/modules/signifyApi.ts b/src/core/modules/signifyApi.ts
index 1359a06..f4ce5dd 100644
--- a/src/core/modules/signifyApi.ts
+++ b/src/core/modules/signifyApi.ts
@@ -1,12 +1,16 @@
import {
- Authenticater,
+ Encrypter,
+ Verfer,
+ Operation,
randomPasscode,
ready,
SignifyClient,
Tier,
+ EventResult,
} from "signify-ts";
-import { Aid, ResponseData } from "@src/core/modules/signifyApi.types";
-import { EventResult } from "signify-ts/src/keri/app/aiding";
+import { Aid } from "@src/core/modules/signifyApi.types";
+import { ResponseData } from "@src/core/background/types";
+import { failure, success } from "@src/utils";
class SignifyApi {
private signifyClient!: SignifyClient;
@@ -18,6 +22,7 @@ class SignifyApi {
constructor() {
this.started = false;
}
+
async start(): Promise> {
await ready();
const bran = await this.getBran();
@@ -32,27 +37,19 @@ class SignifyApi {
try {
await this.signifyClient.connect();
this.started = true;
- return {
- success: true,
- };
+ return success(undefined);
} catch (err) {
await this.signifyClient.boot();
try {
await this.signifyClient.connect();
this.started = true;
- return {
- success: true,
- };
+ return success(undefined);
} catch (e) {
- return {
- success: false,
- error: new Error(
- `Init Signify failed with Keria endpoint: ${SignifyApi.KERIA_URL}. Error: ${e}`,
- ),
- };
+ return failure(e);
}
}
}
+
private async getBran(): Promise {
const bran = await chrome.storage.local.get([
SignifyApi.SIGNIFY_BRAN_STORAGE_KEY,
@@ -69,100 +66,101 @@ class SignifyApi {
}
}
- createIdentifier = async (
- name: string,
- ): Promise> => {
+ async createIdentifier(name: string): Promise> {
+ try {
+ const op = await this.signifyClient.identifiers().create(name);
+ await op.op();
+ await (
+ await this.signifyClient
+ .identifiers()
+ .addEndRole(name, "agent", this.signifyClient.agent!.pre)
+ ).op();
+ return success(op);
+ } catch (e) {
+ return failure(e);
+ }
+ }
+
+ async getIdentifierByName(name: string): Promise> {
try {
- const aid = await this.signifyClient.identifiers().create(name);
- return {
- success: true,
- data: aid,
- };
+ return success(await this.signifyClient.identifiers().get(name));
} catch (e) {
- return {
- success: false,
- error: new Error(
- `Error on AID creation with name ${name}. Error: ${e}`,
- ),
- };
+ return failure(e);
}
- };
+ }
- getIdentifierByName = async (name: string): Promise> => {
+ async createOOBI(name: string): Promise> {
try {
- return {
- success: true,
- data: await this.signifyClient.identifiers().get(name),
- };
+ return success(await this.signifyClient.oobis().get(name, "agent"));
} catch (e) {
- return {
- success: false,
- error: e,
- };
+ return failure(e);
}
- };
+ }
- resolveOOBI = async (url: string): Promise> => {
+ async resolveOOBI(url: string): Promise> {
try {
- if (!this.started)
- return {
- success: false,
- error: new Error("Signify not initialized"),
- };
+ if (!this.started) {
+ return failure(new Error("Signify not initialized"));
+ }
const oobiOperation = await this.signifyClient.oobis().resolve(url);
const r = await this.waitAndGetDoneOp(oobiOperation, 15000, 250);
if (r.done) {
- return {
- success: true,
- data: r,
- };
+ return success(r);
} else {
- return {
- success: false,
- error: new Error(
+ return failure(
+ new Error(
`Resolving OOBI failed for URL: ${url}. \nResponse from Keria: ${JSON.stringify(
r,
)}`,
),
- };
+ );
}
} catch (e) {
- return {
- success: false,
- error: new Error(
- `Resolving OOBI failed for URL: ${url}. \nError: ${e}`,
- ),
- };
+ return failure(
+ new Error(`Resolving OOBI failed for URL: ${url}. \nError: ${e}`),
+ );
+ }
+ }
+
+ async getKeyManager(aid: Aid): Promise> {
+ try {
+ return success(await this.signifyClient.manager?.get(aid));
+ } catch (e) {
+ return failure(e);
+ }
+ }
+
+ async getRemoteEncrypter(aid: string): Promise> {
+ try {
+ const pubKey = (await this.signifyClient.keyStates().get(aid))[0].k[0];
+ return success(new Encrypter({}, new Verfer({ qb64: pubKey }).qb64b));
+ } catch (e) {
+ return failure(e);
}
- };
+ }
- getSigner = async (aid: Aid): Promise> => {
+ async getRemoveVerfer(aid: string): Promise> {
try {
- return {
- success: true,
- data: await this.signifyClient.manager?.get(aid),
- };
+ const pubKey = (await this.signifyClient.keyStates().get(aid))[0].k[0];
+ return success(new Verfer({ qb64: pubKey }));
} catch (e) {
- return {
- success: false,
- error: e,
- };
+ return failure(e);
}
- };
+ }
- private waitAndGetDoneOp = async (
- op: any,
+ private async waitAndGetDoneOp(
+ op: Operation,
timeout: number,
interval: number,
- ) => {
+ ): Promise {
const startTime = new Date().getTime();
while (!op.done && new Date().getTime() < startTime + timeout) {
op = await this.signifyClient.operations().get(op.name);
await new Promise((resolve) => setTimeout(resolve, interval));
}
return op;
- };
+ }
}
export { SignifyApi };
diff --git a/src/core/modules/signifyApi.types.ts b/src/core/modules/signifyApi.types.ts
index 818c780..dc12d53 100644
--- a/src/core/modules/signifyApi.types.ts
+++ b/src/core/modules/signifyApi.types.ts
@@ -1,3 +1,5 @@
+import { MtrDex } from "signify-ts";
+
interface Aid {
name: string;
prefix: string;
@@ -30,8 +32,10 @@ interface Aid {
windexes: number[];
}
-type ResponseData =
- | { success: true; data?: T }
- | { success: false; error: unknown };
+const LEAD_CODES = new Map([
+ [0, MtrDex.StrB64_L0],
+ [1, MtrDex.StrB64_L1],
+ [2, MtrDex.StrB64_L2],
+]);
-export { Aid, ResponseData };
+export { Aid, LEAD_CODES };
diff --git a/src/types.d.ts b/src/types.d.ts
index bd36e60..0788e5e 100644
--- a/src/types.d.ts
+++ b/src/types.d.ts
@@ -1,9 +1,9 @@
declare module "*.png" {
const value: string;
- export = value;
+ export { value };
}
declare module "*.svg" {
const content: any;
- export default content;
+ export { content };
}
diff --git a/src/ui/pages/content/index.tsx b/src/ui/pages/content/index.tsx
index 24a9d7a..f6d009d 100644
--- a/src/ui/pages/content/index.tsx
+++ b/src/ui/pages/content/index.tsx
@@ -1,6 +1,6 @@
window.addEventListener("message", (event) => {
chrome.runtime.sendMessage(event.data, (response) => {
- if (response){
+ if (response) {
window.postMessage(response, "*");
}
});
diff --git a/src/ui/pages/options/options.tsx b/src/ui/pages/options/options.tsx
index 96b97f0..3b23eee 100644
--- a/src/ui/pages/options/options.tsx
+++ b/src/ui/pages/options/options.tsx
@@ -16,14 +16,15 @@ const Options = () => {
const updateLogs = async () => {
const logger = new Logger();
-
- try {
- const lgs = (await logger.getLogs()).data;
- const sortedLogs = lgs.sort((a, b) => b.timestamp - a.timestamp);
- setLogs(sortedLogs);
- } catch (error) {
- console.error("Error updating logs:", error);
+ const getLogsResult = await logger.getLogs();
+ if (!getLogsResult.success) {
+ return getLogsResult;
}
+
+ const sortedLogs = getLogsResult.data.sort(
+ (a, b) => b.timestamp - a.timestamp,
+ );
+ setLogs(sortedLogs);
};
useEffect(() => {
diff --git a/src/ui/pages/popup/sessionDetails/sessionDetails.tsx b/src/ui/pages/popup/sessionDetails/sessionDetails.tsx
index d598345..9fc0d19 100644
--- a/src/ui/pages/popup/sessionDetails/sessionDetails.tsx
+++ b/src/ui/pages/popup/sessionDetails/sessionDetails.tsx
@@ -4,6 +4,9 @@ import "./sessionDetails.scss";
import { BackButton } from "@components/backButton";
import MobileConnectIcon from "@assets/mobile-connect-icon.svg";
import { shortenText } from "@src/utils";
+import { Session } from "../sessionList/sessionList";
+
+const LOCAL_STORAGE_SESSIONS = "sessions";
function SessionDetails() {
const navigate = useNavigate();
@@ -18,7 +21,7 @@ function SessionDetails() {
const deleteSession = () => {
chrome.storage.local.get(["sessions"], function (result) {
- const ss = result.sessions.filter((s) => session.id !== s.id);
+ const ss = result.sessions.filter((s: Session) => session.id !== s.id);
chrome.storage.local.set({ sessions: ss }, function () {
navigate(-1);
@@ -50,8 +53,7 @@ function SessionDetails() {
{session.expiryDate}
- Tunnel AID:{" "}
- {shortenText(session.tunnelAid, 24)}
+ Tunnel AID: {shortenText(session.tunnelAid, 24)}
OOBI:
@@ -67,4 +69,4 @@ function SessionDetails() {
);
}
-export { SessionDetails };
+export { SessionDetails, LOCAL_STORAGE_SESSIONS };
diff --git a/src/ui/pages/popup/sessionList/sessionList.tsx b/src/ui/pages/popup/sessionList/sessionList.tsx
index 71e6243..e054681 100644
--- a/src/ui/pages/popup/sessionList/sessionList.tsx
+++ b/src/ui/pages/popup/sessionList/sessionList.tsx
@@ -5,18 +5,23 @@ import "./sessionList.scss";
import MobileConnectIcon from "../../../assets/mobile-connect-icon.svg";
import webLogo from "../../../assets/web.png";
import { isExpired } from "@src/utils";
+import { LOCAL_STORAGE_SESSIONS } from "../sessionDetails/sessionDetails";
interface Session {
id: string;
name: string;
expiryDate: string;
logo: string;
+ tunnelAid: string;
+ serverAid: string;
+ oobi: any;
+ createdAt: number;
}
function SessionList() {
const navigate = useNavigate();
- const [sessions, setSessions] = useState([]);
+ const [sessions, setSessions] = useState([]);
const handleNavigation = (
option: string,
@@ -26,7 +31,7 @@ function SessionList() {
};
useEffect(() => {
- chrome.storage.local.get(["sessions"], function (result) {
+ chrome.storage.local.get([LOCAL_STORAGE_SESSIONS], function (result) {
setSessions(result.sessions);
});
}, []);
@@ -39,9 +44,13 @@ function SessionList() {
handleNavigation(`/${session.id}`, { state: { session } });
};
+ if (!sessions.length) {
+ return No sessions yet
;
+ }
+
return (
);
}
-export { SessionList };
+export { SessionList, Session };
diff --git a/src/utils/index.ts b/src/utils/index.ts
index d1220d9..51d6964 100644
--- a/src/utils/index.ts
+++ b/src/utils/index.ts
@@ -1,3 +1,8 @@
+import {
+ ExtensionMessage,
+ ExtensionMessageType,
+ ResponseData,
+} from "@src/core/background/types";
import { uid } from "uid";
type Header = {
@@ -28,7 +33,7 @@ const generateAID = async (): Promise<{ pubKey: string; privKey: string }> => {
};
};
-const convertURLImageToBase64 = (url: string) => {
+const convertURLImageToBase64 = (url: string): Promise => {
return fetch(url)
.then((response) => {
if (!response.ok) {
@@ -39,6 +44,8 @@ const convertURLImageToBase64 = (url: string) => {
.then((blob) => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
+ // @TODO - foconnor: Better handle typing issues later.
+ // @ts-ignore
reader.onloadend = () => resolve(reader.result);
reader.onerror = reject;
reader.readAsDataURL(blob);
@@ -72,6 +79,47 @@ const parseHeaders = (serializedHeaders: Header) => {
return headers;
};
+const success = (data: T): ResponseData => {
+ return {
+ success: true,
+ data,
+ };
+};
+
+const failure = (error: unknown): ResponseData => {
+ return {
+ success: false,
+ error,
+ };
+};
+
+const successExt = (
+ id: string,
+ type: ExtensionMessageType,
+ data: T,
+): ExtensionMessage => {
+ return {
+ success: true,
+ id,
+ type,
+ data,
+ };
+};
+
+const failureExt = (
+ id: string,
+ type: ExtensionMessageType,
+ error: unknown,
+): ExtensionMessage => {
+ console.error(`Returning error from extension: ${error}`);
+ return {
+ success: false,
+ id,
+ type,
+ error,
+ };
+};
+
export {
isExpired,
getCurrentDate,
@@ -80,4 +128,8 @@ export {
shortenText,
serializeHeaders,
parseHeaders,
+ success,
+ failure,
+ successExt,
+ failureExt,
};
diff --git a/src/utils/logger.ts b/src/utils/logger.ts
index 00c3b68..e11b781 100644
--- a/src/utils/logger.ts
+++ b/src/utils/logger.ts
@@ -1,4 +1,4 @@
-import { ResponseData } from "@src/core/modules/signifyApi.types";
+import { ResponseData } from "@src/core/background/types";
interface LogEntry {
message: string;
diff --git a/tsconfig.json b/tsconfig.json
index 32db90e..7ac24b5 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -19,7 +19,8 @@
"@pages/*": ["src/ui/pages/*"],
"@components/*": ["src/ui/components/*"]
},
- "include": ["src", "vite.config.ts"],
- "exclude": ["node_modules"]
- }
+ "types": ["chrome", "vite/client"]
+ },
+ "include": ["src", "vite.config.ts"],
+ "exclude": ["node_modules"]
}
diff --git a/vite.config.ts b/vite.config.ts
index 781d152..5b0f541 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -1,24 +1,24 @@
-import react from '@vitejs/plugin-react';
-import { resolve } from 'path';
-import { defineConfig, PluginOption } from 'vite';
-import compression from 'vite-plugin-compression';
-import { crx, ManifestV3Export } from '@crxjs/vite-plugin';
-import merge from 'lodash/merge';
-import { nodePolyfills } from 'vite-plugin-node-polyfills';
-import manifest from './public/manifest.json';
-import pkg from './package.json';
+import react from "@vitejs/plugin-react";
+import { resolve } from "path";
+import { defineConfig, PluginOption } from "vite";
+import compression from "vite-plugin-compression";
+import { crx, ManifestV3Export } from "@crxjs/vite-plugin";
+import merge from "lodash/merge";
+import { nodePolyfills } from "vite-plugin-node-polyfills";
+import manifest from "./public/manifest.json";
+import pkg from "./package.json";
// Routes
-const root = resolve(__dirname, 'src');
-const outDir = resolve(__dirname, 'dist');
-const publicDir = resolve(__dirname, 'public');
+const root = resolve(__dirname, "src");
+const outDir = resolve(__dirname, "dist");
+const publicDir = resolve(__dirname, "public");
// Alias
const aliasConfig = {
- '@src': root,
- '@assets': resolve(root, 'ui/assets'),
- '@pages': resolve(root, 'ui/pages'),
- '@components': resolve(root, 'ui/components'),
+ "@src": root,
+ "@assets": resolve(root, "ui/assets"),
+ "@pages": resolve(root, "ui/pages"),
+ "@components": resolve(root, "ui/components"),
};
function loadManifestConfig() {