rearrange stuff
This commit is contained in:
parent
9e68698ddc
commit
bb86a25ad4
225
package-lock.json
generated
225
package-lock.json
generated
@ -9,7 +9,7 @@
|
|||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"license": "UNLICENSED",
|
"license": "UNLICENSED",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@icynet/oauth2-provider": "git+ssh://git@gitlab.icynet.eu:IcyNetwork/oauth2-provider.git",
|
"@icynet/oauth2-provider": "git+https://gitlab.icynet.eu/IcyNetwork/oauth2-provider.git",
|
||||||
"@nestjs/common": "^9.0.11",
|
"@nestjs/common": "^9.0.11",
|
||||||
"@nestjs/core": "^9.0.11",
|
"@nestjs/core": "^9.0.11",
|
||||||
"@nestjs/platform-express": "^9.0.11",
|
"@nestjs/platform-express": "^9.0.11",
|
||||||
@ -34,7 +34,7 @@
|
|||||||
"otplib": "^12.0.1",
|
"otplib": "^12.0.1",
|
||||||
"pug": "^3.0.2",
|
"pug": "^3.0.2",
|
||||||
"qrcode": "^1.5.1",
|
"qrcode": "^1.5.1",
|
||||||
"redis": "^3.1.2",
|
"redis": "^4.3.0",
|
||||||
"reflect-metadata": "^0.1.13",
|
"reflect-metadata": "^0.1.13",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"rxjs": "^7.5.6",
|
"rxjs": "^7.5.6",
|
||||||
@ -2135,7 +2135,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/@icynet/oauth2-provider": {
|
"node_modules/@icynet/oauth2-provider": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "git+ssh://git@gitlab.icynet.eu:IcyNetwork/oauth2-provider.git#a440d1f4ac53ccb6989dd25221797490611e240a",
|
"resolved": "git+https://gitlab.icynet.eu/IcyNetwork/oauth2-provider.git#a440d1f4ac53ccb6989dd25221797490611e240a",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"express": "^4.17.3",
|
"express": "^4.17.3",
|
||||||
@ -3147,6 +3147,59 @@
|
|||||||
"@otplib/plugin-thirty-two": "^12.0.1"
|
"@otplib/plugin-thirty-two": "^12.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@redis/bloom": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-EBw7Ag1hPgFzdznK2PBblc1kdlj5B5Cw3XwI9/oG7tSn85/HKy3X9xHy/8tm/eNXJYHLXHJL/pkwBpFMVVefkw==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@redis/client": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@redis/client": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@redis/client/-/client-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-XCFV60nloXAefDsPnYMjHGtvbtHR8fV5Om8cQ0JYqTNbWcQo/4AryzJ2luRj4blveWazRK/j40gES8M7Cp6cfQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"cluster-key-slot": "1.1.0",
|
||||||
|
"generic-pool": "3.8.2",
|
||||||
|
"yallist": "4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@redis/graph": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-oDE4myMCJOCVKYMygEMWuriBgqlS5FqdWerikMoJxzmmTUErnTRRgmIDa2VcgytACZMFqpAOWDzops4DOlnkfQ==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@redis/client": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@redis/json": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-4X0Qv0BzD9Zlb0edkUoau5c1bInWSICqXAGrpwEltkncUwcxJIGEcVryZhLgb0p/3PkKaLIWkjhHRtLe9yiA7Q==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@redis/client": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@redis/search": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-NyFZEVnxIJEybpy+YskjgOJRNsfTYqaPbK/Buv6W2kmFNaRk85JiqjJZA5QkRmWvGbyQYwoO5QfDi2wHskKrQQ==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@redis/client": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@redis/time-series": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-OFp0q4SGrTH0Mruf6oFsHGea58u8vS/iI5+NpYdicaM+7BgqBZH8FFvNZ8rYYLrUO/QRqMq72NpXmxLVNcdmjA==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@redis/client": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@sinclair/typebox": {
|
"node_modules/@sinclair/typebox": {
|
||||||
"version": "0.24.28",
|
"version": "0.24.28",
|
||||||
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.28.tgz",
|
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.28.tgz",
|
||||||
@ -4997,6 +5050,14 @@
|
|||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/cluster-key-slot": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/co": {
|
"node_modules/co": {
|
||||||
"version": "4.6.0",
|
"version": "4.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
|
||||||
@ -6713,6 +6774,14 @@
|
|||||||
"is-property": "^1.0.2"
|
"is-property": "^1.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/generic-pool": {
|
||||||
|
"version": "3.8.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.8.2.tgz",
|
||||||
|
"integrity": "sha512-nGToKy6p3PAbYQ7p1UlWl6vSPwfwU6TMSWK7TTu+WUY4ZjyZQGniGGt2oNVvyNSpyZYSB43zMXVLcBm08MTMkg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/gensync": {
|
"node_modules/gensync": {
|
||||||
"version": "1.0.0-beta.2",
|
"version": "1.0.0-beta.2",
|
||||||
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
|
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
|
||||||
@ -10122,53 +10191,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/redis": {
|
"node_modules/redis": {
|
||||||
"version": "3.1.2",
|
"version": "4.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/redis/-/redis-3.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/redis/-/redis-4.3.0.tgz",
|
||||||
"integrity": "sha512-grn5KoZLr/qrRQVwoSkmzdbw6pwF+/rwODtrOr6vuBRiR/f3rjSTGupbF90Zpqm2oenix8Do6RV7pYEkGwlKkw==",
|
"integrity": "sha512-RXRUor0iU1vizu4viHoUyLpe1ZO/RngZp0V9DyXBHTI+7tC7rEz6Wzn4Sv9v0tTJeqGAzdJ+q5YVbNKKQ5hX9A==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"denque": "^1.5.0",
|
"@redis/bloom": "1.0.2",
|
||||||
"redis-commands": "^1.7.0",
|
"@redis/client": "1.3.0",
|
||||||
"redis-errors": "^1.2.0",
|
"@redis/graph": "1.0.1",
|
||||||
"redis-parser": "^3.0.0"
|
"@redis/json": "1.0.3",
|
||||||
},
|
"@redis/search": "1.1.0",
|
||||||
"engines": {
|
"@redis/time-series": "1.0.3"
|
||||||
"node": ">=10"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/node-redis"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/redis-commands": {
|
|
||||||
"version": "1.7.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.7.0.tgz",
|
|
||||||
"integrity": "sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ=="
|
|
||||||
},
|
|
||||||
"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/redis/node_modules/denque": {
|
|
||||||
"version": "1.5.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz",
|
|
||||||
"integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.10"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/reflect-metadata": {
|
"node_modules/reflect-metadata": {
|
||||||
@ -13918,8 +13950,8 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@icynet/oauth2-provider": {
|
"@icynet/oauth2-provider": {
|
||||||
"version": "git+ssh://git@gitlab.icynet.eu:IcyNetwork/oauth2-provider.git#a440d1f4ac53ccb6989dd25221797490611e240a",
|
"version": "git+https://gitlab.icynet.eu/IcyNetwork/oauth2-provider.git#a440d1f4ac53ccb6989dd25221797490611e240a",
|
||||||
"from": "@icynet/oauth2-provider@git+ssh://git@gitlab.icynet.eu:IcyNetwork/oauth2-provider.git",
|
"from": "@icynet/oauth2-provider@git+https://gitlab.icynet.eu/IcyNetwork/oauth2-provider.git",
|
||||||
"requires": {
|
"requires": {
|
||||||
"express": "^4.17.3",
|
"express": "^4.17.3",
|
||||||
"express-session": "^1.17.2"
|
"express-session": "^1.17.2"
|
||||||
@ -14682,6 +14714,46 @@
|
|||||||
"@otplib/plugin-thirty-two": "^12.0.1"
|
"@otplib/plugin-thirty-two": "^12.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@redis/bloom": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-EBw7Ag1hPgFzdznK2PBblc1kdlj5B5Cw3XwI9/oG7tSn85/HKy3X9xHy/8tm/eNXJYHLXHJL/pkwBpFMVVefkw==",
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
|
"@redis/client": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@redis/client/-/client-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-XCFV60nloXAefDsPnYMjHGtvbtHR8fV5Om8cQ0JYqTNbWcQo/4AryzJ2luRj4blveWazRK/j40gES8M7Cp6cfQ==",
|
||||||
|
"requires": {
|
||||||
|
"cluster-key-slot": "1.1.0",
|
||||||
|
"generic-pool": "3.8.2",
|
||||||
|
"yallist": "4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@redis/graph": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-oDE4myMCJOCVKYMygEMWuriBgqlS5FqdWerikMoJxzmmTUErnTRRgmIDa2VcgytACZMFqpAOWDzops4DOlnkfQ==",
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
|
"@redis/json": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-4X0Qv0BzD9Zlb0edkUoau5c1bInWSICqXAGrpwEltkncUwcxJIGEcVryZhLgb0p/3PkKaLIWkjhHRtLe9yiA7Q==",
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
|
"@redis/search": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-NyFZEVnxIJEybpy+YskjgOJRNsfTYqaPbK/Buv6W2kmFNaRk85JiqjJZA5QkRmWvGbyQYwoO5QfDi2wHskKrQQ==",
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
|
"@redis/time-series": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-OFp0q4SGrTH0Mruf6oFsHGea58u8vS/iI5+NpYdicaM+7BgqBZH8FFvNZ8rYYLrUO/QRqMq72NpXmxLVNcdmjA==",
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
"@sinclair/typebox": {
|
"@sinclair/typebox": {
|
||||||
"version": "0.24.28",
|
"version": "0.24.28",
|
||||||
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.28.tgz",
|
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.28.tgz",
|
||||||
@ -16157,6 +16229,11 @@
|
|||||||
"shallow-clone": "^3.0.0"
|
"shallow-clone": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"cluster-key-slot": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw=="
|
||||||
|
},
|
||||||
"co": {
|
"co": {
|
||||||
"version": "4.6.0",
|
"version": "4.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
|
||||||
@ -17475,6 +17552,11 @@
|
|||||||
"is-property": "^1.0.2"
|
"is-property": "^1.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"generic-pool": {
|
||||||
|
"version": "3.8.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.8.2.tgz",
|
||||||
|
"integrity": "sha512-nGToKy6p3PAbYQ7p1UlWl6vSPwfwU6TMSWK7TTu+WUY4ZjyZQGniGGt2oNVvyNSpyZYSB43zMXVLcBm08MTMkg=="
|
||||||
|
},
|
||||||
"gensync": {
|
"gensync": {
|
||||||
"version": "1.0.0-beta.2",
|
"version": "1.0.0-beta.2",
|
||||||
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
|
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
|
||||||
@ -20051,39 +20133,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"redis": {
|
"redis": {
|
||||||
"version": "3.1.2",
|
"version": "4.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/redis/-/redis-3.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/redis/-/redis-4.3.0.tgz",
|
||||||
"integrity": "sha512-grn5KoZLr/qrRQVwoSkmzdbw6pwF+/rwODtrOr6vuBRiR/f3rjSTGupbF90Zpqm2oenix8Do6RV7pYEkGwlKkw==",
|
"integrity": "sha512-RXRUor0iU1vizu4viHoUyLpe1ZO/RngZp0V9DyXBHTI+7tC7rEz6Wzn4Sv9v0tTJeqGAzdJ+q5YVbNKKQ5hX9A==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"denque": "^1.5.0",
|
"@redis/bloom": "1.0.2",
|
||||||
"redis-commands": "^1.7.0",
|
"@redis/client": "1.3.0",
|
||||||
"redis-errors": "^1.2.0",
|
"@redis/graph": "1.0.1",
|
||||||
"redis-parser": "^3.0.0"
|
"@redis/json": "1.0.3",
|
||||||
},
|
"@redis/search": "1.1.0",
|
||||||
"dependencies": {
|
"@redis/time-series": "1.0.3"
|
||||||
"denque": {
|
|
||||||
"version": "1.5.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz",
|
|
||||||
"integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw=="
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"redis-commands": {
|
|
||||||
"version": "1.7.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.7.0.tgz",
|
|
||||||
"integrity": "sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ=="
|
|
||||||
},
|
|
||||||
"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=="
|
|
||||||
},
|
|
||||||
"redis-parser": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz",
|
|
||||||
"integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==",
|
|
||||||
"requires": {
|
|
||||||
"redis-errors": "^1.0.0"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"reflect-metadata": {
|
"reflect-metadata": {
|
||||||
|
@ -49,7 +49,7 @@
|
|||||||
"otplib": "^12.0.1",
|
"otplib": "^12.0.1",
|
||||||
"pug": "^3.0.2",
|
"pug": "^3.0.2",
|
||||||
"qrcode": "^1.5.1",
|
"qrcode": "^1.5.1",
|
||||||
"redis": "^3.1.2",
|
"redis": "^4.3.0",
|
||||||
"reflect-metadata": "^0.1.13",
|
"reflect-metadata": "^0.1.13",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"rxjs": "^7.5.6",
|
"rxjs": "^7.5.6",
|
||||||
|
@ -1,30 +1,15 @@
|
|||||||
import {
|
import { Module } from '@nestjs/common';
|
||||||
MiddlewareConsumer,
|
|
||||||
Module,
|
|
||||||
NestModule,
|
|
||||||
RequestMethod,
|
|
||||||
} from '@nestjs/common';
|
|
||||||
import { ServeStaticModule } from '@nestjs/serve-static';
|
import { ServeStaticModule } from '@nestjs/serve-static';
|
||||||
import { ThrottlerModule } from '@nestjs/throttler';
|
import { ThrottlerModule } from '@nestjs/throttler';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import { AppController } from './app.controller';
|
import { AppController } from './app.controller';
|
||||||
import { AppService } from './app.service';
|
import { AppService } from './app.service';
|
||||||
import { CSRFMiddleware } from './middleware/csrf.middleware';
|
import { CSRFMiddleware } from './middleware/csrf.middleware';
|
||||||
import { UserMiddleware } from './middleware/user.middleware';
|
import { ApiModule } from './modules/api/api.module';
|
||||||
import { ConfigurationModule } from './modules/config/config.module';
|
import { ConfigurationModule } from './modules/config/config.module';
|
||||||
import { LoginModule } from './modules/features/login/login.module';
|
|
||||||
import { OAuth2Module } from './modules/features/oauth2/oauth2.module';
|
|
||||||
import { RegisterModule } from './modules/features/register/register.module';
|
|
||||||
import { SettingsModule } from './modules/features/settings/settings.module';
|
|
||||||
import { TwoFactorModule } from './modules/features/two-factor/two-factor.module';
|
|
||||||
import { JWTModule } from './modules/jwt/jwt.module';
|
import { JWTModule } from './modules/jwt/jwt.module';
|
||||||
import { DatabaseModule } from './modules/objects/database/database.module';
|
import { StaticFrontEndModule } from './modules/static-front-end/static-front-end.module';
|
||||||
import { EmailModule } from './modules/objects/email/email.module';
|
|
||||||
import { OAuth2ClientModule } from './modules/objects/oauth2-client/oauth2-client.module';
|
|
||||||
import { OAuth2TokenModule } from './modules/objects/oauth2-token/oauth2-token.module';
|
|
||||||
import { PrivilegeModule } from './modules/objects/privilege/privilege.module';
|
|
||||||
import { UploadModule } from './modules/objects/upload/upload.module';
|
|
||||||
import { UserModule } from './modules/objects/user/user.module';
|
|
||||||
import { UtilityModule } from './modules/utility/utility.module';
|
import { UtilityModule } from './modules/utility/utility.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
@ -39,31 +24,11 @@ import { UtilityModule } from './modules/utility/utility.module';
|
|||||||
}),
|
}),
|
||||||
ConfigurationModule,
|
ConfigurationModule,
|
||||||
UtilityModule,
|
UtilityModule,
|
||||||
DatabaseModule,
|
|
||||||
EmailModule,
|
|
||||||
UserModule,
|
|
||||||
UploadModule,
|
|
||||||
OAuth2ClientModule,
|
|
||||||
OAuth2TokenModule,
|
|
||||||
LoginModule,
|
|
||||||
RegisterModule,
|
|
||||||
OAuth2Module,
|
|
||||||
JWTModule,
|
JWTModule,
|
||||||
TwoFactorModule,
|
StaticFrontEndModule,
|
||||||
SettingsModule,
|
ApiModule,
|
||||||
PrivilegeModule,
|
|
||||||
],
|
],
|
||||||
controllers: [AppController],
|
controllers: [AppController],
|
||||||
providers: [AppService, CSRFMiddleware],
|
providers: [AppService, CSRFMiddleware],
|
||||||
})
|
})
|
||||||
export class AppModule implements NestModule {
|
export class AppModule {}
|
||||||
configure(consumer: MiddlewareConsumer) {
|
|
||||||
consumer
|
|
||||||
.apply(CSRFMiddleware, UserMiddleware)
|
|
||||||
.exclude(
|
|
||||||
{ path: 'uploads*', method: RequestMethod.ALL },
|
|
||||||
{ path: 'public*', method: RequestMethod.ALL },
|
|
||||||
)
|
|
||||||
.forRoutes('*');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
13
src/decorators/bearer.decorator.ts
Normal file
13
src/decorators/bearer.decorator.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { OAuth2AccessToken } from '@icynet/oauth2-provider';
|
||||||
|
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the OAuth2 bearer token from the response.
|
||||||
|
* Requires the OAuth2 guard or bearer middleware!
|
||||||
|
*/
|
||||||
|
export const Bearer = createParamDecorator(
|
||||||
|
(data: unknown, ctx: ExecutionContext) => {
|
||||||
|
const response = ctx.switchToHttp().getResponse();
|
||||||
|
return response.locals.accessToken as OAuth2AccessToken;
|
||||||
|
},
|
||||||
|
);
|
8
src/decorators/privileges.decorator.ts
Normal file
8
src/decorators/privileges.decorator.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { SetMetadata } from '@nestjs/common';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restrict this route to only these privileges. AND logic!
|
||||||
|
* @param privileges List of privileges for this route
|
||||||
|
*/
|
||||||
|
export const Privileges = (...privileges: string[]) =>
|
||||||
|
SetMetadata('privileges', privileges);
|
14
src/decorators/scope.decorator.ts
Normal file
14
src/decorators/scope.decorator.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { OAuth2AccessToken } from '@icynet/oauth2-provider';
|
||||||
|
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the OAuth2 access token scope from the response.
|
||||||
|
* Requires the OAuth2 guard or bearer middleware!
|
||||||
|
*/
|
||||||
|
export const Scope = createParamDecorator(
|
||||||
|
(data: unknown, ctx: ExecutionContext) => {
|
||||||
|
const response = ctx.switchToHttp().getResponse();
|
||||||
|
const token = response.locals.accessToken as OAuth2AccessToken;
|
||||||
|
return token.scope;
|
||||||
|
},
|
||||||
|
);
|
7
src/decorators/scopes.decorator.ts
Normal file
7
src/decorators/scopes.decorator.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { SetMetadata } from '@nestjs/common';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restrict this route to only these OAuth2 scopes. AND logic!
|
||||||
|
* @param scopes List of scopes for this route
|
||||||
|
*/
|
||||||
|
export const Scopes = (...scopes: string[]) => SetMetadata('scopes', scopes);
|
11
src/decorators/user.decorator.ts
Normal file
11
src/decorators/user.decorator.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the User from the current request. Requires a guard or middleware to inject the user.
|
||||||
|
*/
|
||||||
|
export const CurrentUser = createParamDecorator(
|
||||||
|
(data: unknown, ctx: ExecutionContext) => {
|
||||||
|
const request = ctx.switchToHttp().getRequest();
|
||||||
|
return request.user;
|
||||||
|
},
|
||||||
|
);
|
43
src/guards/oauth2.guard.ts
Normal file
43
src/guards/oauth2.guard.ts
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { OAuth2Service } from 'src/modules/oauth2/oauth2.service';
|
||||||
|
import { UserService } from 'src/modules/objects/user/user.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injects and validates OAuth2 bearer tokens.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class OAuth2Guard implements CanActivate {
|
||||||
|
constructor(private _oauth2: OAuth2Service, private _user: UserService) {}
|
||||||
|
|
||||||
|
canActivate(
|
||||||
|
context: ExecutionContext,
|
||||||
|
): boolean | Promise<boolean> | Observable<boolean> {
|
||||||
|
const http = context.switchToHttp();
|
||||||
|
const request = http.getRequest();
|
||||||
|
const response = http.getResponse();
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
try {
|
||||||
|
this._oauth2.oauth.bearer(request, response, (content) => {
|
||||||
|
if (content instanceof Error) {
|
||||||
|
return reject(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._user
|
||||||
|
.getById(response.locals.accessToken.user_id, [
|
||||||
|
'picture',
|
||||||
|
'privileges',
|
||||||
|
])
|
||||||
|
.then((user) => {
|
||||||
|
request.user = user;
|
||||||
|
resolve(true);
|
||||||
|
})
|
||||||
|
.catch(reject);
|
||||||
|
});
|
||||||
|
} catch (e: any) {
|
||||||
|
reject(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
28
src/guards/privileges.guard.ts
Normal file
28
src/guards/privileges.guard.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
|
||||||
|
import { Reflector } from '@nestjs/core';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates privileges.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class PrivilegesGuard implements CanActivate {
|
||||||
|
constructor(private reflector: Reflector) {}
|
||||||
|
|
||||||
|
canActivate(context: ExecutionContext): boolean {
|
||||||
|
const privileges = this.reflector.get<string[]>(
|
||||||
|
'privileges',
|
||||||
|
context.getHandler(),
|
||||||
|
);
|
||||||
|
if (!privileges) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const request = context.switchToHttp().getRequest();
|
||||||
|
const user = request.user;
|
||||||
|
return (
|
||||||
|
user.privileges.includes('*') ||
|
||||||
|
privileges.every((item) =>
|
||||||
|
user.privileges.find(({ name }) => name === item),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
26
src/guards/scopes.guard.ts
Normal file
26
src/guards/scopes.guard.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { OAuth2AccessToken } from '@icynet/oauth2-provider';
|
||||||
|
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
|
||||||
|
import { Reflector } from '@nestjs/core';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates OAuth2 scopes.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class ScopesGuard implements CanActivate {
|
||||||
|
constructor(private reflector: Reflector) {}
|
||||||
|
|
||||||
|
canActivate(context: ExecutionContext): boolean {
|
||||||
|
const scopes = this.reflector.get<string[]>('scopes', context.getHandler());
|
||||||
|
if (!scopes) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = context.switchToHttp().getResponse();
|
||||||
|
const accessToken = response.locals.accessToken as OAuth2AccessToken;
|
||||||
|
if (!accessToken) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return scopes.every((scope) => accessToken.scope.includes(scope));
|
||||||
|
}
|
||||||
|
}
|
@ -15,9 +15,10 @@ async function bootstrap() {
|
|||||||
|
|
||||||
const RedisStore = connectRedis(session);
|
const RedisStore = connectRedis(session);
|
||||||
const redisClient = redis.createClient({
|
const redisClient = redis.createClient({
|
||||||
host: 'localhost',
|
url: process.env.REDIS_URL || 'redis://localhost:6379',
|
||||||
port: 6379,
|
legacyMode: true,
|
||||||
});
|
});
|
||||||
|
redisClient.connect();
|
||||||
|
|
||||||
// app.use(express.urlencoded());
|
// app.use(express.urlencoded());
|
||||||
app.use(cookieParser());
|
app.use(cookieParser());
|
||||||
|
4
src/modules/api/admin/admin.module.ts
Normal file
4
src/modules/api/admin/admin.module.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
|
||||||
|
@Module({})
|
||||||
|
export class AdminApiModule {}
|
15
src/modules/api/api.controller.ts
Normal file
15
src/modules/api/api.controller.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { Controller, Get, UseGuards } from '@nestjs/common';
|
||||||
|
import { CurrentUser } from 'src/decorators/user.decorator';
|
||||||
|
import { OAuth2Guard } from 'src/guards/oauth2.guard';
|
||||||
|
import { User } from '../objects/user/user.entity';
|
||||||
|
|
||||||
|
@Controller({
|
||||||
|
path: '/api',
|
||||||
|
})
|
||||||
|
export class ApiController {
|
||||||
|
@Get('/')
|
||||||
|
@UseGuards(OAuth2Guard)
|
||||||
|
index(@CurrentUser() user: User) {
|
||||||
|
return { hello: true, user: user.username };
|
||||||
|
}
|
||||||
|
}
|
26
src/modules/api/api.module.ts
Normal file
26
src/modules/api/api.module.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
|
||||||
|
import { ConfigurationModule } from '../config/config.module';
|
||||||
|
import { JWTModule } from '../jwt/jwt.module';
|
||||||
|
import { OAuth2Module } from '../oauth2/oauth2.module';
|
||||||
|
import { OAuth2Service } from '../oauth2/oauth2.service';
|
||||||
|
import { ObjectsModule } from '../objects/objects.module';
|
||||||
|
import { AdminApiModule } from './admin/admin.module';
|
||||||
|
import { ApiController } from './api.controller';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
controllers: [ApiController],
|
||||||
|
imports: [
|
||||||
|
ConfigurationModule,
|
||||||
|
JWTModule,
|
||||||
|
ObjectsModule,
|
||||||
|
AdminApiModule,
|
||||||
|
OAuth2Module,
|
||||||
|
],
|
||||||
|
})
|
||||||
|
export class ApiModule implements NestModule {
|
||||||
|
constructor(private _service: OAuth2Service) {}
|
||||||
|
|
||||||
|
configure(consumer: MiddlewareConsumer) {
|
||||||
|
consumer.apply(this._service.oauth.express()).forRoutes('/api*');
|
||||||
|
}
|
||||||
|
}
|
@ -1,27 +0,0 @@
|
|||||||
import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
|
|
||||||
import { AuthMiddleware } from 'src/middleware/auth.middleware';
|
|
||||||
import { ValidateCSRFMiddleware } from 'src/middleware/validate-csrf.middleware';
|
|
||||||
import { OAuth2ClientModule } from 'src/modules/objects/oauth2-client/oauth2-client.module';
|
|
||||||
import { OAuth2TokenModule } from 'src/modules/objects/oauth2-token/oauth2-token.module';
|
|
||||||
import { UploadModule } from 'src/modules/objects/upload/upload.module';
|
|
||||||
import { UserModule } from 'src/modules/objects/user/user.module';
|
|
||||||
import { OAuth2Controller } from './oauth2.controller';
|
|
||||||
import { OAuth2Service } from './oauth2.service';
|
|
||||||
|
|
||||||
@Module({
|
|
||||||
imports: [UserModule, UploadModule, OAuth2ClientModule, OAuth2TokenModule],
|
|
||||||
controllers: [OAuth2Controller],
|
|
||||||
providers: [OAuth2Service],
|
|
||||||
exports: [OAuth2Service],
|
|
||||||
})
|
|
||||||
export class OAuth2Module implements NestModule {
|
|
||||||
constructor(private _service: OAuth2Service) {}
|
|
||||||
|
|
||||||
configure(consumer: MiddlewareConsumer) {
|
|
||||||
consumer.apply(this._service.oauth.express()).forRoutes('oauth2/*');
|
|
||||||
consumer.apply(this._service.oauth.bearer).forRoutes('oauth2/user');
|
|
||||||
consumer
|
|
||||||
.apply(AuthMiddleware, ValidateCSRFMiddleware)
|
|
||||||
.forRoutes('oauth2/authorize');
|
|
||||||
}
|
|
||||||
}
|
|
13
src/modules/oauth2/oauth2.module.ts
Normal file
13
src/modules/oauth2/oauth2.module.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { OAuth2ClientModule } from 'src/modules/objects/oauth2-client/oauth2-client.module';
|
||||||
|
import { OAuth2TokenModule } from 'src/modules/objects/oauth2-token/oauth2-token.module';
|
||||||
|
import { UploadModule } from 'src/modules/objects/upload/upload.module';
|
||||||
|
import { UserModule } from 'src/modules/objects/user/user.module';
|
||||||
|
import { OAuth2Service } from './oauth2.service';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [UserModule, UploadModule, OAuth2ClientModule, OAuth2TokenModule],
|
||||||
|
providers: [OAuth2Service],
|
||||||
|
exports: [OAuth2Service],
|
||||||
|
})
|
||||||
|
export class OAuth2Module {}
|
@ -1,5 +1,5 @@
|
|||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { DeleteResult, Repository } from 'typeorm';
|
import { Repository } from 'typeorm';
|
||||||
import { User } from '../user/user.entity';
|
import { User } from '../user/user.entity';
|
||||||
import { OAuth2ClientAuthorization } from './oauth2-client-authorization.entity';
|
import { OAuth2ClientAuthorization } from './oauth2-client-authorization.entity';
|
||||||
import {
|
import {
|
||||||
@ -56,8 +56,8 @@ export class OAuth2ClientService {
|
|||||||
): Promise<OAuth2ClientAuthorization> {
|
): Promise<OAuth2ClientAuthorization> {
|
||||||
const existing = await this.clientAuthRepository.findOne({
|
const existing = await this.clientAuthRepository.findOne({
|
||||||
where: {
|
where: {
|
||||||
user,
|
user: { id: user.id },
|
||||||
client,
|
client: { id: client.id },
|
||||||
},
|
},
|
||||||
relations: ['user', 'client'],
|
relations: ['user', 'client'],
|
||||||
});
|
});
|
||||||
@ -87,7 +87,7 @@ export class OAuth2ClientService {
|
|||||||
): Promise<OAuth2ClientAuthorization[]> {
|
): Promise<OAuth2ClientAuthorization[]> {
|
||||||
return this.clientAuthRepository.find({
|
return this.clientAuthRepository.find({
|
||||||
relations: ['user', 'client', 'client.urls'],
|
relations: ['user', 'client', 'client.urls'],
|
||||||
where: { user },
|
where: { user: { id: user.id } },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,7 +104,7 @@ export class OAuth2ClientService {
|
|||||||
): Promise<OAuth2ClientAuthorization> {
|
): Promise<OAuth2ClientAuthorization> {
|
||||||
return this.clientAuthRepository.findOne({
|
return this.clientAuthRepository.findOne({
|
||||||
where: {
|
where: {
|
||||||
user,
|
user: { id: user.id },
|
||||||
id: authId,
|
id: authId,
|
||||||
},
|
},
|
||||||
relations: ['user'],
|
relations: ['user'],
|
||||||
|
36
src/modules/objects/objects.module.ts
Normal file
36
src/modules/objects/objects.module.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { ConfigurationModule } from '../config/config.module';
|
||||||
|
|
||||||
|
import { DatabaseModule } from './database/database.module';
|
||||||
|
import { DocumentModule } from './document/document.module';
|
||||||
|
import { EmailModule } from './email/email.module';
|
||||||
|
import { OAuth2ClientModule } from './oauth2-client/oauth2-client.module';
|
||||||
|
import { OAuth2TokenModule } from './oauth2-token/oauth2-token.module';
|
||||||
|
import { PrivilegeModule } from './privilege/privilege.module';
|
||||||
|
import { UploadModule } from './upload/upload.module';
|
||||||
|
import { UserModule } from './user/user.module';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [
|
||||||
|
ConfigurationModule,
|
||||||
|
DatabaseModule,
|
||||||
|
EmailModule,
|
||||||
|
OAuth2ClientModule,
|
||||||
|
OAuth2TokenModule,
|
||||||
|
PrivilegeModule,
|
||||||
|
UploadModule,
|
||||||
|
UserModule,
|
||||||
|
DocumentModule,
|
||||||
|
],
|
||||||
|
exports: [
|
||||||
|
DatabaseModule,
|
||||||
|
EmailModule,
|
||||||
|
OAuth2ClientModule,
|
||||||
|
OAuth2TokenModule,
|
||||||
|
PrivilegeModule,
|
||||||
|
UploadModule,
|
||||||
|
UserModule,
|
||||||
|
DocumentModule,
|
||||||
|
],
|
||||||
|
})
|
||||||
|
export class ObjectsModule {}
|
@ -33,7 +33,7 @@ export class UserTOTPService {
|
|||||||
*/
|
*/
|
||||||
public async getUserTOTP(user: User): Promise<UserToken> {
|
public async getUserTOTP(user: User): Promise<UserToken> {
|
||||||
return this.userTokenRepository.findOne({
|
return this.userTokenRepository.findOne({
|
||||||
where: { user, type: UserTokenType.TOTP },
|
where: { user: { id: user.id }, type: UserTokenType.TOTP },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,9 +76,11 @@ export class LoginController {
|
|||||||
|
|
||||||
if (await this.totpService.userHasTOTP(user)) {
|
if (await this.totpService.userHasTOTP(user)) {
|
||||||
const challenge = { type: 'verify', user: user.uuid, remember };
|
const challenge = { type: 'verify', user: user.uuid, remember };
|
||||||
req.session.challenge = await this.token.encryptChallenge(challenge);
|
const encrypted = await this.token.encryptChallenge(challenge);
|
||||||
res.redirect(
|
res.redirect(
|
||||||
'/login/verify' + (redirectTo ? '?redirectTo=' + redirectTo : ''),
|
`login/verify?challenge=${encrypted}${
|
||||||
|
redirectTo ? '&redirectTo=' + redirectTo : ''
|
||||||
|
}`,
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -96,18 +98,19 @@ export class LoginController {
|
|||||||
|
|
||||||
@Get('verify')
|
@Get('verify')
|
||||||
public verifyUserTokenView(
|
public verifyUserTokenView(
|
||||||
@Session() session: SessionData,
|
|
||||||
@Req() req: Request,
|
@Req() req: Request,
|
||||||
@Res() res: Response,
|
@Res() res: Response,
|
||||||
@Query('redirectTo') redirectTo?: string,
|
@Query() query: { redirectTo: string; challenge: string },
|
||||||
) {
|
) {
|
||||||
if (!session.challenge) {
|
if (!query.challenge) {
|
||||||
req.flash('message', {
|
req.flash('message', {
|
||||||
error: true,
|
error: true,
|
||||||
text: 'An unexpected error occured, please log in again.',
|
text: 'An unexpected error occured, please log in again.',
|
||||||
});
|
});
|
||||||
|
|
||||||
res.redirect('/login' + (redirectTo ? '?redirectTo=' + redirectTo : ''));
|
res.redirect(
|
||||||
|
'/login' + (query.redirectTo ? '?redirectTo=' + query.redirectTo : ''),
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,34 +123,36 @@ export class LoginController {
|
|||||||
@Body() body: { totp: string },
|
@Body() body: { totp: string },
|
||||||
@Req() req: Request,
|
@Req() req: Request,
|
||||||
@Res() res: Response,
|
@Res() res: Response,
|
||||||
@Query('redirectTo') redirectTo?: string,
|
@Query() query: { redirectTo: string; challenge: string },
|
||||||
) {
|
) {
|
||||||
let user: User;
|
let user: User;
|
||||||
let remember = false;
|
let remember = false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!session.challenge) {
|
if (!query.challenge) {
|
||||||
throw new Error('No challenge');
|
throw new Error('No challenge');
|
||||||
}
|
}
|
||||||
|
|
||||||
const challenge = await this.token.decryptChallenge(session.challenge);
|
const decrypted = await this.token.decryptChallenge(query.challenge);
|
||||||
if (!challenge || challenge.type !== 'verify' || !challenge.user) {
|
if (!decrypted || decrypted.type !== 'verify' || !decrypted.user) {
|
||||||
throw new Error('Bad challenge');
|
throw new Error('Bad challenge');
|
||||||
}
|
}
|
||||||
|
|
||||||
user = await this.userService.getByUUID(challenge.user);
|
user = await this.userService.getByUUID(decrypted.user);
|
||||||
if (!user) {
|
if (!user) {
|
||||||
throw new Error('Bad challenge');
|
throw new Error('Bad challenge');
|
||||||
}
|
}
|
||||||
|
|
||||||
remember = challenge.remember;
|
remember = decrypted.remember;
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
req.flash('message', {
|
req.flash('message', {
|
||||||
error: true,
|
error: true,
|
||||||
text: 'An unexpected error occured, please log in again.',
|
text: 'An unexpected error occured, please log in again.',
|
||||||
});
|
});
|
||||||
|
|
||||||
res.redirect('/login' + (redirectTo ? '?redirectTo=' + redirectTo : ''));
|
res.redirect(
|
||||||
|
'/login' + (query.redirectTo ? '?redirectTo=' + query.redirectTo : ''),
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,9 +177,8 @@ export class LoginController {
|
|||||||
req.session.cookie.maxAge = month;
|
req.session.cookie.maxAge = month;
|
||||||
}
|
}
|
||||||
|
|
||||||
session.challenge = null;
|
|
||||||
session.user = user.uuid;
|
session.user = user.uuid;
|
||||||
res.redirect(redirectTo ? decodeURIComponent(redirectTo) : '/');
|
res.redirect(query.redirectTo ? decodeURIComponent(query.redirectTo) : '/');
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get('activate')
|
@Get('activate')
|
||||||
@ -231,7 +235,6 @@ export class LoginController {
|
|||||||
public async recoverView(
|
public async recoverView(
|
||||||
@Req() req: Request,
|
@Req() req: Request,
|
||||||
@Res() res: Response,
|
@Res() res: Response,
|
||||||
@Session() session: SessionData,
|
|
||||||
@Query() query: { token: string },
|
@Query() query: { token: string },
|
||||||
) {
|
) {
|
||||||
if (query.token) {
|
if (query.token) {
|
@ -1,4 +1,3 @@
|
|||||||
import { OAuth2AccessToken } from '@icynet/oauth2-provider';
|
|
||||||
import {
|
import {
|
||||||
Controller,
|
Controller,
|
||||||
Get,
|
Get,
|
||||||
@ -7,10 +6,15 @@ import {
|
|||||||
Post,
|
Post,
|
||||||
Req,
|
Req,
|
||||||
Res,
|
Res,
|
||||||
|
UseGuards,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { NextFunction, Request, Response } from 'express';
|
import { NextFunction, Request, Response } from 'express';
|
||||||
|
import { Scope } from 'src/decorators/scope.decorator';
|
||||||
|
import { CurrentUser } from 'src/decorators/user.decorator';
|
||||||
|
import { OAuth2Guard } from 'src/guards/oauth2.guard';
|
||||||
import { ConfigurationService } from 'src/modules/config/config.service';
|
import { ConfigurationService } from 'src/modules/config/config.service';
|
||||||
import { OAuth2Service } from './oauth2.service';
|
import { User } from 'src/modules/objects/user/user.entity';
|
||||||
|
import { OAuth2Service } from '../../oauth2/oauth2.service';
|
||||||
|
|
||||||
@Controller('oauth2')
|
@Controller('oauth2')
|
||||||
export class OAuth2Controller {
|
export class OAuth2Controller {
|
||||||
@ -61,15 +65,11 @@ export class OAuth2Controller {
|
|||||||
// TODO: Move to API
|
// TODO: Move to API
|
||||||
|
|
||||||
@Get('user')
|
@Get('user')
|
||||||
|
@UseGuards(OAuth2Guard)
|
||||||
public async userInfo(
|
public async userInfo(
|
||||||
@Res({ passthrough: true }) res: Response,
|
@CurrentUser() user: User,
|
||||||
|
@Scope() scope: string,
|
||||||
): Promise<Record<string, any>> {
|
): Promise<Record<string, any>> {
|
||||||
const token = res.locals.accessToken as OAuth2AccessToken;
|
|
||||||
const user = await this._service.userService.getById(
|
|
||||||
token.user_id as number,
|
|
||||||
['picture', 'privileges'],
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
throw new NotFoundException('No such user');
|
throw new NotFoundException('No such user');
|
||||||
}
|
}
|
||||||
@ -86,13 +86,13 @@ export class OAuth2Controller {
|
|||||||
nickname: user.display_name,
|
nickname: user.display_name,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (token.scope.includes('email') || token.scope.includes('user:email')) {
|
if (scope.includes('email') || scope.includes('user:email')) {
|
||||||
userData.email = user.email;
|
userData.email = user.email;
|
||||||
userData.email_verified = true;
|
userData.email_verified = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(token.scope.includes('image') || token.scope.includes('user:image')) &&
|
(scope.includes('image') || scope.includes('user:image')) &&
|
||||||
user.picture
|
user.picture
|
||||||
) {
|
) {
|
||||||
userData.image = `${this._config.get('app.base_url')}/uploads/${
|
userData.image = `${this._config.get('app.base_url')}/uploads/${
|
||||||
@ -102,10 +102,10 @@ export class OAuth2Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
token.scope.includes('privileges') ||
|
scope.includes('privileges') ||
|
||||||
(token.scope.includes('user:privileges') && user.privileges?.length)
|
(scope.includes('user:privileges') && user.privileges?.length)
|
||||||
) {
|
) {
|
||||||
userData.privileges = user.privileges;
|
userData.privileges = user.privileges.map(({ name }) => name);
|
||||||
}
|
}
|
||||||
|
|
||||||
return userData;
|
return userData;
|
@ -0,0 +1,22 @@
|
|||||||
|
import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
|
||||||
|
import { AuthMiddleware } from 'src/middleware/auth.middleware';
|
||||||
|
import { ValidateCSRFMiddleware } from 'src/middleware/validate-csrf.middleware';
|
||||||
|
import { OAuth2Module } from 'src/modules/oauth2/oauth2.module';
|
||||||
|
import { OAuth2Service } from 'src/modules/oauth2/oauth2.service';
|
||||||
|
import { UserModule } from 'src/modules/objects/user/user.module';
|
||||||
|
import { OAuth2Controller } from './oauth2-router.controller';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
controllers: [OAuth2Controller],
|
||||||
|
imports: [OAuth2Module, UserModule],
|
||||||
|
})
|
||||||
|
export class OAuth2RouterModule implements NestModule {
|
||||||
|
constructor(private _service: OAuth2Service) {}
|
||||||
|
|
||||||
|
configure(consumer: MiddlewareConsumer) {
|
||||||
|
consumer.apply(this._service.oauth.express()).forRoutes('oauth2/*');
|
||||||
|
consumer
|
||||||
|
.apply(AuthMiddleware, ValidateCSRFMiddleware)
|
||||||
|
.forRoutes('oauth2/authorize');
|
||||||
|
}
|
||||||
|
}
|
@ -15,7 +15,7 @@ import { ConfigurationModule } from 'src/modules/config/config.module';
|
|||||||
import { ConfigurationService } from 'src/modules/config/config.service';
|
import { ConfigurationService } from 'src/modules/config/config.service';
|
||||||
import { UploadModule } from 'src/modules/objects/upload/upload.module';
|
import { UploadModule } from 'src/modules/objects/upload/upload.module';
|
||||||
import { UserModule } from 'src/modules/objects/user/user.module';
|
import { UserModule } from 'src/modules/objects/user/user.module';
|
||||||
import { OAuth2Module } from '../oauth2/oauth2.module';
|
import { OAuth2Module } from '../../oauth2/oauth2.module';
|
||||||
import { SettingsController } from './settings.controller';
|
import { SettingsController } from './settings.controller';
|
||||||
import { SettingsService } from './settings.service';
|
import { SettingsService } from './settings.service';
|
||||||
import { OAuth2ClientModule } from 'src/modules/objects/oauth2-client/oauth2-client.module';
|
import { OAuth2ClientModule } from 'src/modules/objects/oauth2-client/oauth2-client.module';
|
@ -1,6 +1,6 @@
|
|||||||
import { ConfigurationService } from 'src/modules/config/config.service';
|
import { ConfigurationService } from 'src/modules/config/config.service';
|
||||||
import { UserService } from 'src/modules/objects/user/user.service';
|
import { UserService } from 'src/modules/objects/user/user.service';
|
||||||
import { OAuth2Service } from '../oauth2/oauth2.service';
|
import { OAuth2Service } from '../../oauth2/oauth2.service';
|
||||||
|
|
||||||
export class SettingsService {
|
export class SettingsService {
|
||||||
constructor(
|
constructor(
|
46
src/modules/static-front-end/static-front-end.module.ts
Normal file
46
src/modules/static-front-end/static-front-end.module.ts
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import {
|
||||||
|
MiddlewareConsumer,
|
||||||
|
Module,
|
||||||
|
NestModule,
|
||||||
|
RequestMethod,
|
||||||
|
} from '@nestjs/common';
|
||||||
|
import { CSRFMiddleware } from 'src/middleware/csrf.middleware';
|
||||||
|
import { UserMiddleware } from 'src/middleware/user.middleware';
|
||||||
|
import { ConfigurationModule } from '../config/config.module';
|
||||||
|
import { JWTModule } from '../jwt/jwt.module';
|
||||||
|
import { ObjectsModule } from '../objects/objects.module';
|
||||||
|
|
||||||
|
import { LoginModule } from './login/login.module';
|
||||||
|
import { OAuth2RouterModule } from './oauth2-router/oauth2-router.module';
|
||||||
|
import { RegisterModule } from './register/register.module';
|
||||||
|
import { SettingsModule } from './settings/settings.module';
|
||||||
|
import { TwoFactorModule } from './two-factor/two-factor.module';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [
|
||||||
|
ConfigurationModule,
|
||||||
|
JWTModule,
|
||||||
|
|
||||||
|
ObjectsModule,
|
||||||
|
|
||||||
|
LoginModule,
|
||||||
|
OAuth2RouterModule,
|
||||||
|
RegisterModule,
|
||||||
|
SettingsModule,
|
||||||
|
TwoFactorModule,
|
||||||
|
],
|
||||||
|
providers: [],
|
||||||
|
exports: [],
|
||||||
|
})
|
||||||
|
export class StaticFrontEndModule implements NestModule {
|
||||||
|
configure(consumer: MiddlewareConsumer) {
|
||||||
|
consumer
|
||||||
|
.apply(CSRFMiddleware, UserMiddleware)
|
||||||
|
.exclude(
|
||||||
|
{ path: 'uploads*', method: RequestMethod.ALL },
|
||||||
|
{ path: 'public*', method: RequestMethod.ALL },
|
||||||
|
{ path: 'api*', method: RequestMethod.ALL },
|
||||||
|
)
|
||||||
|
.forRoutes('*');
|
||||||
|
}
|
||||||
|
}
|
@ -16,9 +16,9 @@ block body
|
|||||||
.alert.alert-success
|
.alert.alert-success
|
||||||
span #{message.text}
|
span #{message.text}
|
||||||
|
|
||||||
form(method="post")
|
form(method="post", autocomplete="off")
|
||||||
div.form-container
|
div.form-container
|
||||||
input#csrf(type="hidden", name="_csrf", value=csrf)
|
input#csrf(type="hidden", name="_csrf", value=csrf)
|
||||||
label.form-label(for="totp") Code
|
label.form-label(for="totp") Code
|
||||||
input.form-control#totp(type="text", name="totp", autofocus, placeholder="xxxxxx")
|
input.form-control#totp(type="text", autocomplete="off", name="totp", autofocus, placeholder="xxxxxx")
|
||||||
button.btn.btn-primary(type="submit") Log in
|
button.btn.btn-primary(type="submit") Log in
|
||||||
|
Reference in New Issue
Block a user