store express sessions in redis, delete only aliases from preferred domain #3
@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"trailingComma": "es5",
|
"trailingComma": "es5",
|
||||||
"tabWidth": 4,
|
"tabWidth": 4,
|
||||||
"semi": true,
|
"semi": true,
|
||||||
"singleQuote": true,
|
"singleQuote": true,
|
||||||
"printWidth": 120,
|
"printWidth": 120,
|
||||||
"quoteProps": "as-needed",
|
"quoteProps": "as-needed",
|
||||||
"arrowParens": "avoid"
|
"arrowParens": "avoid"
|
||||||
}
|
}
|
@ -14,5 +14,8 @@
|
|||||||
"token": "aaaaa",
|
"token": "aaaaa",
|
||||||
"domain": "test-codemowers.eu",
|
"domain": "test-codemowers.eu",
|
||||||
"preferredDomain": "k-space.ee"
|
"preferredDomain": "k-space.ee"
|
||||||
|
},
|
||||||
|
"redis": {
|
||||||
|
"url": "redis://localhost:6379"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -10,5 +10,8 @@ module.exports = {
|
|||||||
url: process.env.WILDDUCK_URL,
|
url: process.env.WILDDUCK_URL,
|
||||||
token: process.env.WILDDUCK_TOKEN,
|
token: process.env.WILDDUCK_TOKEN,
|
||||||
domain: process.env.WILDDUCK_DOMAIN
|
domain: process.env.WILDDUCK_DOMAIN
|
||||||
|
},
|
||||||
|
redis: {
|
||||||
|
url: process.env.REDIS_URL
|
||||||
}
|
}
|
||||||
};
|
};
|
@ -98,6 +98,8 @@ spec:
|
|||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: walias-secrets
|
name: walias-secrets
|
||||||
key: WILDDUCK_DOMAIN
|
key: WILDDUCK_DOMAIN
|
||||||
|
- name: REDIS_URL
|
||||||
|
value: walias-cache
|
||||||
envFrom:
|
envFrom:
|
||||||
- secretRef:
|
- secretRef:
|
||||||
name: oidc-client-walias-owner-secrets
|
name: oidc-client-walias-owner-secrets
|
||||||
|
205
package-lock.json
generated
205
package-lock.json
generated
@ -22,8 +22,10 @@
|
|||||||
"axios": "^1.4.0",
|
"axios": "^1.4.0",
|
||||||
"compression": "^1.7.4",
|
"compression": "^1.7.4",
|
||||||
"config": "^3.3.9",
|
"config": "^3.3.9",
|
||||||
|
"connect-redis": "^7.1.0",
|
||||||
"cookie-parser": "^1.4.6",
|
"cookie-parser": "^1.4.6",
|
||||||
"express-session": "^1.17.3",
|
"express-session": "^1.17.3",
|
||||||
|
"ioredis": "^5.3.2",
|
||||||
"openid-client": "^5.4.3",
|
"openid-client": "^5.4.3",
|
||||||
"winston": "^3.10.0"
|
"winston": "^3.10.0"
|
||||||
},
|
},
|
||||||
@ -34,6 +36,7 @@
|
|||||||
"@types/express-session": "^1.17.7",
|
"@types/express-session": "^1.17.7",
|
||||||
"@types/mocha": "^10.0.1",
|
"@types/mocha": "^10.0.1",
|
||||||
"@types/node": "^20.4.5",
|
"@types/node": "^20.4.5",
|
||||||
|
"@types/redis": "^4.0.11",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"husky": "^8.0.3",
|
"husky": "^8.0.3",
|
||||||
"lint-staged": "^13.2.3",
|
"lint-staged": "^13.2.3",
|
||||||
@ -413,6 +416,11 @@
|
|||||||
"url": "https://github.com/sponsors/daffl"
|
"url": "https://github.com/sponsors/daffl"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@ioredis/commands": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg=="
|
||||||
|
},
|
||||||
"node_modules/@jridgewell/resolve-uri": {
|
"node_modules/@jridgewell/resolve-uri": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz",
|
||||||
@ -438,6 +446,65 @@
|
|||||||
"@jridgewell/sourcemap-codec": "^1.4.10"
|
"@jridgewell/sourcemap-codec": "^1.4.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@redis/bloom": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==",
|
||||||
|
"dev": true,
|
||||||
|
"peerDependencies": {
|
||||||
|
"@redis/client": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@redis/client": {
|
||||||
|
"version": "1.5.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/@redis/client/-/client-1.5.8.tgz",
|
||||||
|
"integrity": "sha512-xzElwHIO6rBAqzPeVnCzgvrnBEcFL1P0w8P65VNLRkdVW8rOE58f52hdj0BDgmsdOm4f1EoXPZtH4Fh7M/qUpw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"cluster-key-slot": "1.1.2",
|
||||||
|
"generic-pool": "3.9.0",
|
||||||
|
"yallist": "4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@redis/graph": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-16yZWngxyXPd+MJxeSr0dqh2AIOi8j9yXKcKCwVaKDbH3HTuETpDVPcLujhFYVPtYrngSco31BUcSa9TH31Gqg==",
|
||||||
|
"dev": true,
|
||||||
|
"peerDependencies": {
|
||||||
|
"@redis/client": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@redis/json": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-LUZE2Gdrhg0Rx7AN+cZkb1e6HjoSKaeeW8rYnt89Tly13GBI5eP4CwDVr+MY8BAYfCg4/N15OUrtLoona9uSgw==",
|
||||||
|
"dev": true,
|
||||||
|
"peerDependencies": {
|
||||||
|
"@redis/client": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@redis/search": {
|
||||||
|
"version": "1.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.3.tgz",
|
||||||
|
"integrity": "sha512-4Dg1JjvCevdiCBTZqjhKkGoC5/BcB7k9j99kdMnaXFXg8x4eyOIVg9487CMv7/BUVkFLZCaIh8ead9mU15DNng==",
|
||||||
|
"dev": true,
|
||||||
|
"peerDependencies": {
|
||||||
|
"@redis/client": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@redis/time-series": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-ThUIgo2U/g7cCuZavucQTQzA9g9JbDDY2f64u3AbAoz/8vE2lt2U37LamDUVChhaDA3IRT9R6VvJwqnUfTJzng==",
|
||||||
|
"dev": true,
|
||||||
|
"peerDependencies": {
|
||||||
|
"@redis/client": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@socket.io/component-emitter": {
|
"node_modules/@socket.io/component-emitter": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
|
||||||
@ -610,6 +677,16 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz",
|
||||||
"integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw=="
|
"integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw=="
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/redis": {
|
||||||
|
"version": "4.0.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/redis/-/redis-4.0.11.tgz",
|
||||||
|
"integrity": "sha512-bI+gth8La8Wg/QCR1+V1fhrL9+LZUSWfcqpOj2Kc80ZQ4ffbdL173vQd5wovmoV9i071FU9oP2g6etLuEwb6Rg==",
|
||||||
|
"deprecated": "This is a stub types definition. redis provides its own type definitions, so you do not need this installed.",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"redis": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/send": {
|
"node_modules/@types/send": {
|
||||||
"version": "0.17.1",
|
"version": "0.17.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.1.tgz",
|
||||||
@ -1229,6 +1306,14 @@
|
|||||||
"node": ">=0.8"
|
"node": ">=0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/cluster-key-slot": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/color": {
|
"node_modules/color": {
|
||||||
"version": "3.2.1",
|
"version": "3.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz",
|
||||||
@ -1340,6 +1425,17 @@
|
|||||||
"node": ">= 10.0.0"
|
"node": ">= 10.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/connect-redis": {
|
||||||
|
"version": "7.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/connect-redis/-/connect-redis-7.1.0.tgz",
|
||||||
|
"integrity": "sha512-UaqO1EirWjON2ENsyau7N5lbkrdYBpS6mYlXSeff/OYXsd6EGZ+SXSmNPoljL2PSua8fgjAEaldSA73PMZQ9Eg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"express-session": ">=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/content-disposition": {
|
"node_modules/content-disposition": {
|
||||||
"version": "0.5.4",
|
"version": "0.5.4",
|
||||||
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
|
||||||
@ -1501,6 +1597,14 @@
|
|||||||
"node": ">=0.4.0"
|
"node": ">=0.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/denque": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/depd": {
|
"node_modules/depd": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
||||||
@ -1999,6 +2103,15 @@
|
|||||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||||
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
|
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
|
||||||
},
|
},
|
||||||
|
"node_modules/generic-pool": {
|
||||||
|
"version": "3.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz",
|
||||||
|
"integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/get-caller-file": {
|
"node_modules/get-caller-file": {
|
||||||
"version": "2.0.5",
|
"version": "2.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||||
@ -2274,6 +2387,50 @@
|
|||||||
"node": ">= 0.10"
|
"node": ">= 0.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ioredis": {
|
||||||
|
"version": "5.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.3.2.tgz",
|
||||||
|
"integrity": "sha512-1DKMMzlIHM02eBBVOFQ1+AolGjs6+xEcM4PDL7NqOS6szq7H9jSaEkIUH6/a5Hl241LzW6JLSiAbNvTQjUupUA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@ioredis/commands": "^1.1.1",
|
||||||
|
"cluster-key-slot": "^1.1.0",
|
||||||
|
"debug": "^4.3.4",
|
||||||
|
"denque": "^2.1.0",
|
||||||
|
"lodash.defaults": "^4.2.0",
|
||||||
|
"lodash.isarguments": "^3.1.0",
|
||||||
|
"redis-errors": "^1.2.0",
|
||||||
|
"redis-parser": "^3.0.0",
|
||||||
|
"standard-as-callback": "^2.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.22.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/ioredis"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ioredis/node_modules/debug": {
|
||||||
|
"version": "4.3.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||||
|
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"ms": "2.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"supports-color": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ioredis/node_modules/ms": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||||
|
},
|
||||||
"node_modules/ipaddr.js": {
|
"node_modules/ipaddr.js": {
|
||||||
"version": "1.9.1",
|
"version": "1.9.1",
|
||||||
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
|
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
|
||||||
@ -2650,6 +2807,16 @@
|
|||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||||
},
|
},
|
||||||
|
"node_modules/lodash.defaults": {
|
||||||
|
"version": "4.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
|
||||||
|
"integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ=="
|
||||||
|
},
|
||||||
|
"node_modules/lodash.isarguments": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg=="
|
||||||
|
},
|
||||||
"node_modules/log-symbols": {
|
"node_modules/log-symbols": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
|
||||||
@ -3536,6 +3703,39 @@
|
|||||||
"node": ">= 0.10"
|
"node": ">= 0.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/redis": {
|
||||||
|
"version": "4.6.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/redis/-/redis-4.6.7.tgz",
|
||||||
|
"integrity": "sha512-KrkuNJNpCwRm5vFJh0tteMxW8SaUzkm5fBH7eL5hd/D0fAkzvapxbfGPP/r+4JAXdQuX7nebsBkBqA2RHB7Usw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@redis/bloom": "1.2.0",
|
||||||
|
"@redis/client": "1.5.8",
|
||||||
|
"@redis/graph": "1.1.0",
|
||||||
|
"@redis/json": "1.0.4",
|
||||||
|
"@redis/search": "1.1.3",
|
||||||
|
"@redis/time-series": "1.0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/redis-errors": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/redis-parser": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==",
|
||||||
|
"dependencies": {
|
||||||
|
"redis-errors": "^1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/regenerator-runtime": {
|
"node_modules/regenerator-runtime": {
|
||||||
"version": "0.13.11",
|
"version": "0.13.11",
|
||||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
|
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
|
||||||
@ -3920,6 +4120,11 @@
|
|||||||
"node": "*"
|
"node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/standard-as-callback": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A=="
|
||||||
|
},
|
||||||
"node_modules/statuses": {
|
"node_modules/statuses": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
||||||
|
@ -55,8 +55,10 @@
|
|||||||
"axios": "^1.4.0",
|
"axios": "^1.4.0",
|
||||||
"compression": "^1.7.4",
|
"compression": "^1.7.4",
|
||||||
"config": "^3.3.9",
|
"config": "^3.3.9",
|
||||||
|
"connect-redis": "^7.1.0",
|
||||||
"cookie-parser": "^1.4.6",
|
"cookie-parser": "^1.4.6",
|
||||||
"express-session": "^1.17.3",
|
"express-session": "^1.17.3",
|
||||||
|
"ioredis": "^5.3.2",
|
||||||
"openid-client": "^5.4.3",
|
"openid-client": "^5.4.3",
|
||||||
"winston": "^3.10.0"
|
"winston": "^3.10.0"
|
||||||
},
|
},
|
||||||
@ -67,6 +69,7 @@
|
|||||||
"@types/express-session": "^1.17.7",
|
"@types/express-session": "^1.17.7",
|
||||||
"@types/mocha": "^10.0.1",
|
"@types/mocha": "^10.0.1",
|
||||||
"@types/node": "^20.4.5",
|
"@types/node": "^20.4.5",
|
||||||
|
"@types/redis": "^4.0.11",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"husky": "^8.0.3",
|
"husky": "^8.0.3",
|
||||||
"lint-staged": "^13.2.3",
|
"lint-staged": "^13.2.3",
|
||||||
|
@ -31,29 +31,17 @@ function renderAliases(aliases) {
|
|||||||
const tdCreated = document.createElement('td')
|
const tdCreated = document.createElement('td')
|
||||||
tdCreated.innerText = alias.created
|
tdCreated.innerText = alias.created
|
||||||
const tdActions = document.createElement('td')
|
const tdActions = document.createElement('td')
|
||||||
const aDelete = document.createElement('a')
|
|
||||||
|
|
||||||
aDelete.addEventListener('click', async () => {
|
const deleteButton = createDeleteButton(alias)
|
||||||
const res = await fetch(`/aliases/${alias.id}`, {
|
|
||||||
method: 'DELETE'
|
|
||||||
})
|
|
||||||
|
|
||||||
if (res.ok) {
|
tdActions.appendChild(deleteButton)
|
||||||
const data = await res.json()
|
|
||||||
renderAliases(data)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
aDelete.classList.add('btn', 'btn-danger')
|
|
||||||
aDelete.innerText = 'Delete'
|
|
||||||
tdActions.appendChild(aDelete)
|
|
||||||
|
|
||||||
tr.appendChild(tdAddress)
|
tr.appendChild(tdAddress)
|
||||||
tr.appendChild(tdCreated)
|
tr.appendChild(tdCreated)
|
||||||
tr.appendChild(tdActions)
|
tr.appendChild(tdActions)
|
||||||
tbody.appendChild(tr)
|
tbody.appendChild(tr)
|
||||||
})
|
})
|
||||||
|
|
||||||
table.appendChild(tbody)
|
table.appendChild(tbody)
|
||||||
|
|
||||||
dataContainer.innerHTML = ''
|
dataContainer.innerHTML = ''
|
||||||
@ -62,6 +50,32 @@ function renderAliases(aliases) {
|
|||||||
renderCreateButton();
|
renderCreateButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createDeleteButton(alias) {
|
||||||
|
const deleteButton = document.createElement('a')
|
||||||
|
deleteButton.classList.add('btn', 'btn-danger')
|
||||||
|
|
||||||
|
if (!alias.id) {
|
||||||
|
deleteButton.classList.add('disabled')
|
||||||
|
} else {
|
||||||
|
|
||||||
|
deleteButton.addEventListener('click', async () => {
|
||||||
|
const res = await fetch(`/aliases/${alias.id}`, {
|
||||||
|
method: 'DELETE'
|
||||||
|
})
|
||||||
|
|
||||||
|
if (res.ok) {
|
||||||
|
const data = await res.json()
|
||||||
|
renderAliases(data)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteButton.innerText = 'Delete'
|
||||||
|
|
||||||
|
return deleteButton
|
||||||
|
}
|
||||||
|
|
||||||
function renderCreateButton() {
|
function renderCreateButton() {
|
||||||
const dataContainer = document.getElementById('container')
|
const dataContainer = document.getElementById('container')
|
||||||
const button = document.createElement('a')
|
const button = document.createElement('a')
|
||||||
|
15
readme.md
15
readme.md
@ -7,12 +7,13 @@
|
|||||||
This project was build for [K-Space Hackathon2023](https://wiki.k-space.ee/en/hackathon/2023)
|
This project was build for [K-Space Hackathon2023](https://wiki.k-space.ee/en/hackathon/2023)
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
* auth with oidc
|
|
||||||
* headless only, no DB
|
- auth with oidc
|
||||||
* develop/debug with skaffold on k8s cluster
|
- headless only, no DB
|
||||||
|
- develop/debug with skaffold on k8s cluster
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
* remove TS-related hacks
|
|
||||||
* add tests
|
- remove TS-related hacks
|
||||||
* make nicer UI
|
- add tests
|
||||||
* implement persistent sessions for multi-docker deployment (redis, db, etc)
|
- make nicer UI
|
||||||
|
22
src/app.ts
22
src/app.ts
@ -1,17 +1,19 @@
|
|||||||
|
import { randomUUID } from 'crypto';
|
||||||
import { feathers } from '@feathersjs/feathers';
|
import { feathers } from '@feathersjs/feathers';
|
||||||
import express, { rest, json, urlencoded, cors, serveStatic, notFound, errorHandler } from '@feathersjs/express';
|
import express, { rest, json, urlencoded, cors, serveStatic, notFound, errorHandler } from '@feathersjs/express';
|
||||||
import configuration from '@feathersjs/configuration';
|
import configuration from '@feathersjs/configuration';
|
||||||
import socketio from '@feathersjs/socketio';
|
import socketio from '@feathersjs/socketio';
|
||||||
import session from 'express-session';
|
import session from 'express-session';
|
||||||
import cookieParser from 'cookie-parser';
|
import cookieParser from 'cookie-parser';
|
||||||
|
import RedisStore from 'connect-redis';
|
||||||
|
import { createClient } from 'redis';
|
||||||
|
import config from 'config';
|
||||||
import type { Application } from './declarations';
|
import type { Application } from './declarations';
|
||||||
|
|
||||||
import { logger } from './logger';
|
import { logger } from './logger';
|
||||||
import { logError } from './hooks/log-error';
|
import { logError } from './hooks/log-error';
|
||||||
import { services } from './services/index';
|
import { services } from './services/index';
|
||||||
import { channels } from './channels';
|
import { channels } from './channels';
|
||||||
import { randomUUID } from 'crypto';
|
import { Env, getEnv } from './helpers/get-env';
|
||||||
|
|
||||||
const app: Application = express(feathers());
|
const app: Application = express(feathers());
|
||||||
|
|
||||||
@ -25,11 +27,23 @@ app.use(
|
|||||||
);
|
);
|
||||||
|
|
||||||
app.use(cookieParser());
|
app.use(cookieParser());
|
||||||
|
|
||||||
|
const sessionStore =
|
||||||
|
getEnv() === Env.prod
|
||||||
|
? new RedisStore({
|
||||||
|
prefix: 'walias:',
|
||||||
|
client: createClient({
|
||||||
|
url: config.get('redis.url'),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
: undefined;
|
||||||
|
|
||||||
app.use(
|
app.use(
|
||||||
session({
|
session({
|
||||||
|
store: sessionStore,
|
||||||
secret: randomUUID(),
|
secret: randomUUID(),
|
||||||
resave: false,
|
resave: false,
|
||||||
saveUninitialized: true,
|
saveUninitialized: false,
|
||||||
cookie: { secure: false },
|
cookie: { secure: false },
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
16
src/helpers/get-env.ts
Normal file
16
src/helpers/get-env.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
export enum Env {
|
||||||
|
dev = 'dev',
|
||||||
|
prod = 'prod',
|
||||||
|
test = 'test',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getEnv = (): Env => {
|
||||||
|
const env = process.env.NODE_ENV;
|
||||||
|
if (env === 'prod') {
|
||||||
|
return Env.prod;
|
||||||
|
} else if (env === 'test') {
|
||||||
|
return Env.test;
|
||||||
|
} else {
|
||||||
|
return Env.dev;
|
||||||
|
}
|
||||||
|
};
|
@ -2,11 +2,11 @@ import type { NullableId, Params, ServiceInterface } from '@feathersjs/feathers'
|
|||||||
|
|
||||||
import type { Application } from '../../declarations';
|
import type { Application } from '../../declarations';
|
||||||
import wildDuckClient from '../../clients/wildduck.client';
|
import wildDuckClient from '../../clients/wildduck.client';
|
||||||
import { faker } from '@faker-js/faker';
|
import { faker, th } from '@faker-js/faker';
|
||||||
import { BadRequest } from '@feathersjs/errors';
|
import { BadRequest } from '@feathersjs/errors';
|
||||||
import config from 'config';
|
import config from 'config';
|
||||||
|
|
||||||
interface Alias {
|
interface WildDuckAddress {
|
||||||
success: boolean;
|
success: boolean;
|
||||||
id: string;
|
id: string;
|
||||||
address: string;
|
address: string;
|
||||||
@ -16,12 +16,19 @@ interface Alias {
|
|||||||
created: string;
|
created: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface GetAddressInfoResponse {
|
interface GetWildDuckAddressInfoResponse {
|
||||||
success: boolean;
|
success: boolean;
|
||||||
results: Alias[];
|
results: WildDuckAddress[];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CreateAddressResponse {
|
interface AliasApiResponse {
|
||||||
|
id: string | null;
|
||||||
|
address: string;
|
||||||
|
tags: string[];
|
||||||
|
created: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CreateWildDuckAddressResponse {
|
||||||
success: boolean;
|
success: boolean;
|
||||||
id: string;
|
id: string;
|
||||||
}
|
}
|
||||||
@ -30,7 +37,7 @@ type AliasesData = any;
|
|||||||
type AliasesPatch = any;
|
type AliasesPatch = any;
|
||||||
type AliasesQuery = any;
|
type AliasesQuery = any;
|
||||||
|
|
||||||
export type { Alias as Aliases, AliasesData, AliasesPatch, AliasesQuery };
|
export type { WildDuckAddress as Aliases, AliasesData, AliasesPatch, AliasesQuery };
|
||||||
|
|
||||||
export interface AliasesServiceOptions {
|
export interface AliasesServiceOptions {
|
||||||
app: Application;
|
app: Application;
|
||||||
@ -41,18 +48,18 @@ export interface AliasesParams extends Params<AliasesQuery> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class AliasesService<ServiceParams extends AliasesParams = AliasesParams>
|
export class AliasesService<ServiceParams extends AliasesParams = AliasesParams>
|
||||||
implements ServiceInterface<Alias, AliasesData, ServiceParams, AliasesPatch>
|
implements ServiceInterface<AliasApiResponse, AliasesData, ServiceParams, AliasesPatch>
|
||||||
{
|
{
|
||||||
constructor(public options: AliasesServiceOptions) {}
|
constructor(public options: AliasesServiceOptions) {}
|
||||||
|
|
||||||
async find(params: ServiceParams): Promise<Alias[]> {
|
async find(params: ServiceParams): Promise<AliasApiResponse[]> {
|
||||||
const userId = await this.getUserIdByEmailAddress(params);
|
const userId = await this.getUserIdByEmailAddress(params);
|
||||||
|
|
||||||
return this.getUserAddresses(userId);
|
return this.getUserAddresses(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
async create(data: AliasesData, params: ServiceParams): Promise<Alias>;
|
async create(data: AliasesData, params: ServiceParams): Promise<AliasApiResponse>;
|
||||||
async create(data: AliasesData, params: ServiceParams): Promise<Alias | Alias[]> {
|
async create(data: AliasesData, params: ServiceParams): Promise<AliasApiResponse | AliasApiResponse[]> {
|
||||||
const userId = await this.getUserIdByEmailAddress(params);
|
const userId = await this.getUserIdByEmailAddress(params);
|
||||||
|
|
||||||
const randomString = faker.git.commitSha({ length: 4 });
|
const randomString = faker.git.commitSha({ length: 4 });
|
||||||
@ -65,7 +72,7 @@ export class AliasesService<ServiceParams extends AliasesParams = AliasesParams>
|
|||||||
|
|
||||||
const emailDomain = config.get('wildDuck.domain');
|
const emailDomain = config.get('wildDuck.domain');
|
||||||
|
|
||||||
const createResult = await wildDuckClient.post<CreateAddressResponse>(`/users/${userId}/addresses`, {
|
const createResult = await wildDuckClient.post<CreateWildDuckAddressResponse>(`/users/${userId}/addresses`, {
|
||||||
address: `${alias}@${emailDomain}`,
|
address: `${alias}@${emailDomain}`,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -79,25 +86,31 @@ export class AliasesService<ServiceParams extends AliasesParams = AliasesParams>
|
|||||||
private async getUserIdByEmailAddress(params: ServiceParams): Promise<string> {
|
private async getUserIdByEmailAddress(params: ServiceParams): Promise<string> {
|
||||||
const emails = params.session?.user?.emails;
|
const emails = params.session?.user?.emails;
|
||||||
|
|
||||||
|
const preferredDomain = config.get('wildDuck.preferredDomain');
|
||||||
|
|
||||||
|
if (!emails.length || !preferredDomain) {
|
||||||
|
throw new BadRequest('Unable to find user');
|
||||||
|
}
|
||||||
|
|
||||||
const addressInfoResponse = await Promise.any(
|
const addressInfoResponse = await Promise.any(
|
||||||
emails
|
emails
|
||||||
.filter((email: string) => email.endsWith(config.get('wildDuck.preferredDomain')))
|
.filter((email: string) => email.endsWith(config.get('wildDuck.preferredDomain')))
|
||||||
.map((email: string) => wildDuckClient.get<Alias>(`addresses/resolve/${email}`))
|
.map((email: string) => wildDuckClient.get<WildDuckAddress>(`addresses/resolve/${email}`))
|
||||||
);
|
);
|
||||||
|
|
||||||
return addressInfoResponse.data.user;
|
return addressInfoResponse.data.user;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getUserAddresses(userId: string): Promise<Alias[]> {
|
private async getUserAddresses(userId: string): Promise<AliasApiResponse[]> {
|
||||||
const { data: userAddressesResponse } = await wildDuckClient.get<GetAddressInfoResponse>(
|
const { data: userAddressesResponse } = await wildDuckClient.get<GetWildDuckAddressInfoResponse>(
|
||||||
`/users/${userId}/addresses`
|
`/users/${userId}/addresses`
|
||||||
);
|
);
|
||||||
|
|
||||||
return userAddressesResponse.results;
|
return userAddressesResponse.results.map(this.sanitizeAliasResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
async remove(id: NullableId, params: ServiceParams): Promise<Alias[]> {
|
async remove(id: NullableId, params: ServiceParams): Promise<AliasApiResponse[]> {
|
||||||
const { data: addressInfoResponse } = await wildDuckClient.get<Alias>(`addresses/resolve/${id}`);
|
const { data: addressInfoResponse } = await wildDuckClient.get<WildDuckAddress>(`addresses/resolve/${id}`);
|
||||||
const allowedDomain: string = config.get('wildDuck.domain');
|
const allowedDomain: string = config.get('wildDuck.domain');
|
||||||
|
|
||||||
// If address does not match the allowed domain, throw an error
|
// If address does not match the allowed domain, throw an error
|
||||||
@ -106,10 +119,22 @@ export class AliasesService<ServiceParams extends AliasesParams = AliasesParams>
|
|||||||
}
|
}
|
||||||
const userId = await this.getUserIdByEmailAddress(params);
|
const userId = await this.getUserIdByEmailAddress(params);
|
||||||
|
|
||||||
await wildDuckClient.delete<Alias>(`users/${userId}/addresses/${id}`);
|
await wildDuckClient.delete<WildDuckAddress>(`users/${userId}/addresses/${id}`);
|
||||||
|
|
||||||
return this.getUserAddresses(userId);
|
return this.getUserAddresses(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sanitizeAliasResponse(alias: WildDuckAddress): AliasApiResponse {
|
||||||
|
// Hide the id if the alias is not removable
|
||||||
|
const isRemovable = alias.main || !alias.address.endsWith(config.get('wildDuck.preferredDomain'));
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: isRemovable ? null : alias.id,
|
||||||
|
address: alias.address,
|
||||||
|
tags: alias.tags,
|
||||||
|
created: alias.created,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getOptions = (app: Application) => {
|
export const getOptions = (app: Application) => {
|
||||||
|
Loading…
Reference in New Issue
Block a user