mirror of
https://github.com/wassname/talk.git
synced 2026-08-12 12:30:39 +08:00
initial oidc support
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"exec": "npm run compile:server:types",
|
||||
"ext": "graphql",
|
||||
"watch": [
|
||||
"./src/core/server/graph"
|
||||
]
|
||||
}
|
||||
Generated
+247
-99
@@ -1413,7 +1413,6 @@
|
||||
"version": "1.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.17.0.tgz",
|
||||
"integrity": "sha512-a2+YeUjPkztKJu5aIF2yArYFQQp8d51wZ7DavSHjFuY1mqVgidGyzEQ41JIVNy82fXj8yPgy2vJmfIywgESW6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/connect": "*",
|
||||
"@types/node": "*"
|
||||
@@ -1448,7 +1447,6 @@
|
||||
"version": "3.4.32",
|
||||
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.32.tgz",
|
||||
"integrity": "sha512-4r8qa0quOvh7lGD0pre62CAb1oni1OO6ecJLGCezTmhQ8Fz50Arx9RUszryR8KlgK6avuSXvviL6yWyViQABOg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
@@ -1471,31 +1469,45 @@
|
||||
"@types/events": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/events/-/events-1.2.0.tgz",
|
||||
"integrity": "sha512-KEIlhXnIutzKwRbQkGWb/I4HFqBuUykAdHgDED6xqwXJfONCjF5VoE0cXEiurh3XauygxzeDzgtXUqvLkxFzzA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-KEIlhXnIutzKwRbQkGWb/I4HFqBuUykAdHgDED6xqwXJfONCjF5VoE0cXEiurh3XauygxzeDzgtXUqvLkxFzzA=="
|
||||
},
|
||||
"@types/express": {
|
||||
"version": "4.16.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.16.0.tgz",
|
||||
"integrity": "sha512-TtPEYumsmSTtTetAPXlJVf3kEqb6wZK0bZojpJQrnD/djV4q1oB6QQ8aKvKqwNPACoe02GNiy5zDzcYivR5Z2w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/body-parser": "*",
|
||||
"@types/express-serve-static-core": "*",
|
||||
"@types/serve-static": "*"
|
||||
}
|
||||
},
|
||||
"@types/express-jwt": {
|
||||
"version": "0.0.34",
|
||||
"resolved": "https://registry.npmjs.org/@types/express-jwt/-/express-jwt-0.0.34.tgz",
|
||||
"integrity": "sha1-/b7kxq9cCiRu8qkz9VGZc8dxfwI=",
|
||||
"requires": {
|
||||
"@types/express": "*",
|
||||
"@types/express-unless": "*"
|
||||
}
|
||||
},
|
||||
"@types/express-serve-static-core": {
|
||||
"version": "4.16.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.16.0.tgz",
|
||||
"integrity": "sha512-lTeoCu5NxJU4OD9moCgm0ESZzweAx0YqsAcab6OB0EB3+As1OaHtKnaGJvcngQxYsi9UNv0abn4/DRavrRxt4w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/events": "*",
|
||||
"@types/node": "*",
|
||||
"@types/range-parser": "*"
|
||||
}
|
||||
},
|
||||
"@types/express-unless": {
|
||||
"version": "0.0.32",
|
||||
"resolved": "https://registry.npmjs.org/@types/express-unless/-/express-unless-0.0.32.tgz",
|
||||
"integrity": "sha512-6YpJyFNlDDnPnRjMOvJCoDYlSDDmG/OEEUsPk7yhNkL4G9hUYtgab6vi1CcWsGSSSM0CsvNlWTG+ywAGnvF03g==",
|
||||
"requires": {
|
||||
"@types/express": "*"
|
||||
}
|
||||
},
|
||||
"@types/graphql": {
|
||||
"version": "0.13.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/graphql/-/graphql-0.13.1.tgz",
|
||||
@@ -1524,6 +1536,15 @@
|
||||
"integrity": "sha512-GXYdIVpwBP5ZBOlHitSYfQdH+vWXVahhkeQwalX0LkoX7Mx0D3L3tg4vXXhr6nYHkEpWlAzWuEjgWEBtcp5NZA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/jsonwebtoken": {
|
||||
"version": "7.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-7.2.7.tgz",
|
||||
"integrity": "sha512-lq9X76APpxGJDUe1VptL1P5GrogqhPCH+SDy94+gaBJw7Hhj6hwrVC6zuxAx2GrgktkBuwydESZBvPfrdBoOEg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/lodash": {
|
||||
"version": "4.14.109",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.109.tgz",
|
||||
@@ -1539,8 +1560,7 @@
|
||||
"@types/mime": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.0.tgz",
|
||||
"integrity": "sha512-A2TAGbTFdBw9azHbpVd+/FkdW2T6msN1uct1O9bH3vTerEHKZhTXJUQXy+hNq1B0RagfU8U+KBdqiZpxjhOUQA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-A2TAGbTFdBw9azHbpVd+/FkdW2T6msN1uct1O9bH3vTerEHKZhTXJUQXy+hNq1B0RagfU8U+KBdqiZpxjhOUQA=="
|
||||
},
|
||||
"@types/mongodb": {
|
||||
"version": "3.0.19",
|
||||
@@ -1556,8 +1576,16 @@
|
||||
"@types/node": {
|
||||
"version": "10.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.3.1.tgz",
|
||||
"integrity": "sha512-IsX9aDHDzJohkm3VCDB8tkzl5RQ34E/PFA29TQk6uDGb7Oc869ZBtmdKVDBzY3+h9GnXB8ssrRXEPVZrlIOPOw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-IsX9aDHDzJohkm3VCDB8tkzl5RQ34E/PFA29TQk6uDGb7Oc869ZBtmdKVDBzY3+h9GnXB8ssrRXEPVZrlIOPOw=="
|
||||
},
|
||||
"@types/oauth": {
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/oauth/-/oauth-0.9.0.tgz",
|
||||
"integrity": "sha512-1oouefxKPGiDkb5m6lNxDkFry3PItCOJ+tlNtEn/gRvWShb2Rb3y0pccOIGwN/AwHUpwsuwlRwSpg7aoCN3bQQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/passport": {
|
||||
"version": "0.4.5",
|
||||
@@ -1568,6 +1596,27 @@
|
||||
"@types/express": "*"
|
||||
}
|
||||
},
|
||||
"@types/passport-oauth2": {
|
||||
"version": "1.4.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/passport-oauth2/-/passport-oauth2-1.4.5.tgz",
|
||||
"integrity": "sha512-q/pT4RKkiHU1W20P2qUAtVmua3bVF1b8Tulag/niDISS+8CGrRthmQxvPhkIVtJb68ssCxn8ck+eagInGuKHDQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/express": "*",
|
||||
"@types/oauth": "*",
|
||||
"@types/passport": "*"
|
||||
}
|
||||
},
|
||||
"@types/passport-strategy": {
|
||||
"version": "0.2.33",
|
||||
"resolved": "https://registry.npmjs.org/@types/passport-strategy/-/passport-strategy-0.2.33.tgz",
|
||||
"integrity": "sha512-tmj//XbNqCWmD+PJ/KnxAouircAmMGLN9IHBO3utH5DXuHHHYN4ZG53DRrQBjlZMiS/1b5IP38U2ay1GfbcQrQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/express": "*",
|
||||
"@types/passport": "*"
|
||||
}
|
||||
},
|
||||
"@types/query-string": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/query-string/-/query-string-6.1.0.tgz",
|
||||
@@ -1577,8 +1626,7 @@
|
||||
"@types/range-parser": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.2.tgz",
|
||||
"integrity": "sha512-HtKGu+qG1NPvYe1z7ezLsyIaXYyi8SoAVqWDZgDQ8dLrsZvSzUNCwZyfX33uhWxL/SU0ZDQZ3nwZ0nimt507Kw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-HtKGu+qG1NPvYe1z7ezLsyIaXYyi8SoAVqWDZgDQ8dLrsZvSzUNCwZyfX33uhWxL/SU0ZDQZ3nwZ0nimt507Kw=="
|
||||
},
|
||||
"@types/react": {
|
||||
"version": "16.4.2",
|
||||
@@ -1627,7 +1675,6 @@
|
||||
"version": "1.13.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.2.tgz",
|
||||
"integrity": "sha512-/BZ4QRLpH/bNYgZgwhKEh+5AsboDBcUdlBYgzoLX0fpj3Y2gp6EApyOlM3bK53wQS/OE1SrdSYBAbux2D1528Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/express-serve-static-core": "*",
|
||||
"@types/mime": "*"
|
||||
@@ -2341,8 +2388,7 @@
|
||||
"asn1": {
|
||||
"version": "0.2.3",
|
||||
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz",
|
||||
"integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=",
|
||||
"dev": true
|
||||
"integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y="
|
||||
},
|
||||
"asn1.js": {
|
||||
"version": "4.10.1",
|
||||
@@ -2384,8 +2430,7 @@
|
||||
"assert-plus": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
|
||||
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
|
||||
"dev": true
|
||||
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
|
||||
},
|
||||
"assign-symbols": {
|
||||
"version": "1.0.0",
|
||||
@@ -2428,8 +2473,7 @@
|
||||
"asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
|
||||
"dev": true
|
||||
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
|
||||
},
|
||||
"atob": {
|
||||
"version": "2.1.1",
|
||||
@@ -2454,14 +2498,12 @@
|
||||
"aws-sign2": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
|
||||
"integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=",
|
||||
"dev": true
|
||||
"integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
|
||||
},
|
||||
"aws4": {
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz",
|
||||
"integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w==",
|
||||
"dev": true
|
||||
"integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w=="
|
||||
},
|
||||
"b3b": {
|
||||
"version": "0.0.1",
|
||||
@@ -4305,7 +4347,6 @@
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz",
|
||||
"integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"tweetnacl": "^0.14.3"
|
||||
@@ -4649,6 +4690,11 @@
|
||||
"isarray": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"buffer-equal-constant-time": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
|
||||
"integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk="
|
||||
},
|
||||
"buffer-from": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.0.tgz",
|
||||
@@ -4855,8 +4901,7 @@
|
||||
"caseless": {
|
||||
"version": "0.12.0",
|
||||
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
|
||||
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
|
||||
"dev": true
|
||||
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
|
||||
},
|
||||
"ccount": {
|
||||
"version": "1.0.3",
|
||||
@@ -5210,8 +5255,7 @@
|
||||
"co": {
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
|
||||
"integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=",
|
||||
"dev": true
|
||||
"integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ="
|
||||
},
|
||||
"coa": {
|
||||
"version": "1.0.4",
|
||||
@@ -5300,7 +5344,6 @@
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz",
|
||||
"integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"delayed-stream": "~1.0.0"
|
||||
}
|
||||
@@ -5543,8 +5586,7 @@
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
||||
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
|
||||
"dev": true
|
||||
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
|
||||
},
|
||||
"cosmiconfig": {
|
||||
"version": "3.1.0",
|
||||
@@ -6231,7 +6273,6 @@
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
|
||||
"integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"assert-plus": "^1.0.0"
|
||||
}
|
||||
@@ -6440,8 +6481,7 @@
|
||||
"delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
|
||||
"dev": true
|
||||
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
|
||||
},
|
||||
"delegate": {
|
||||
"version": "3.2.0",
|
||||
@@ -7102,12 +7142,19 @@
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz",
|
||||
"integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"jsbn": "~0.1.0"
|
||||
}
|
||||
},
|
||||
"ecdsa-sig-formatter": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.10.tgz",
|
||||
"integrity": "sha1-HFlQAPBKiJffuFAAiSoPTDOvhsM=",
|
||||
"requires": {
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"ee-first": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||
@@ -7639,8 +7686,7 @@
|
||||
"extend": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz",
|
||||
"integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=",
|
||||
"dev": true
|
||||
"integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ="
|
||||
},
|
||||
"extend-shallow": {
|
||||
"version": "3.0.2",
|
||||
@@ -7754,8 +7800,7 @@
|
||||
"extsprintf": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
|
||||
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
|
||||
"dev": true
|
||||
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
|
||||
},
|
||||
"fast-deep-equal": {
|
||||
"version": "2.0.1",
|
||||
@@ -8105,14 +8150,12 @@
|
||||
"forever-agent": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
|
||||
"integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
|
||||
"dev": true
|
||||
"integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
|
||||
},
|
||||
"form-data": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz",
|
||||
"integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "1.0.6",
|
||||
@@ -8255,14 +8298,12 @@
|
||||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
@@ -8277,20 +8318,17 @@
|
||||
"code-point-at": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"console-control-strings": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
@@ -8407,8 +8445,7 @@
|
||||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.5",
|
||||
@@ -8420,7 +8457,6 @@
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"number-is-nan": "^1.0.0"
|
||||
}
|
||||
@@ -8435,7 +8471,6 @@
|
||||
"version": "3.0.4",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
@@ -8443,14 +8478,12 @@
|
||||
"minimist": {
|
||||
"version": "0.0.8",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"minipass": {
|
||||
"version": "2.2.4",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"safe-buffer": "^5.1.1",
|
||||
"yallist": "^3.0.0"
|
||||
@@ -8469,7 +8502,6 @@
|
||||
"version": "0.5.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"minimist": "0.0.8"
|
||||
}
|
||||
@@ -8550,8 +8582,7 @@
|
||||
"number-is-nan": {
|
||||
"version": "1.0.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
@@ -8563,7 +8594,6 @@
|
||||
"version": "1.4.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
@@ -8685,7 +8715,6 @@
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"code-point-at": "^1.0.0",
|
||||
"is-fullwidth-code-point": "^1.0.0",
|
||||
@@ -8797,7 +8826,6 @@
|
||||
"version": "0.1.7",
|
||||
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
|
||||
"integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"assert-plus": "^1.0.0"
|
||||
}
|
||||
@@ -9301,14 +9329,12 @@
|
||||
"har-schema": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
|
||||
"integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=",
|
||||
"dev": true
|
||||
"integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
|
||||
},
|
||||
"har-validator": {
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz",
|
||||
"integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ajv": "^5.1.0",
|
||||
"har-schema": "^2.0.0"
|
||||
@@ -9318,7 +9344,6 @@
|
||||
"version": "5.5.2",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
|
||||
"integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"co": "^4.6.0",
|
||||
"fast-deep-equal": "^1.0.0",
|
||||
@@ -9329,14 +9354,12 @@
|
||||
"fast-deep-equal": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz",
|
||||
"integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=",
|
||||
"dev": true
|
||||
"integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ="
|
||||
},
|
||||
"json-schema-traverse": {
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
|
||||
"integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=",
|
||||
"dev": true
|
||||
"integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A="
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -9707,7 +9730,6 @@
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
|
||||
"integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"assert-plus": "^1.0.0",
|
||||
"jsprim": "^1.2.2",
|
||||
@@ -10534,8 +10556,7 @@
|
||||
"is-typedarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
|
||||
"integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
|
||||
"dev": true
|
||||
"integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
|
||||
},
|
||||
"is-utf8": {
|
||||
"version": "0.2.1",
|
||||
@@ -10630,8 +10651,7 @@
|
||||
"isstream": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
|
||||
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
|
||||
"dev": true
|
||||
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
|
||||
},
|
||||
"istanbul-api": {
|
||||
"version": "1.3.1",
|
||||
@@ -11265,7 +11285,6 @@
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
|
||||
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"jsdom": {
|
||||
@@ -11329,8 +11348,7 @@
|
||||
"json-schema": {
|
||||
"version": "0.2.3",
|
||||
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
|
||||
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=",
|
||||
"dev": true
|
||||
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
|
||||
},
|
||||
"json-schema-traverse": {
|
||||
"version": "0.4.1",
|
||||
@@ -11341,8 +11359,7 @@
|
||||
"json-stringify-safe": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
|
||||
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
|
||||
"dev": true
|
||||
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
|
||||
},
|
||||
"json3": {
|
||||
"version": "3.3.2",
|
||||
@@ -11372,11 +11389,33 @@
|
||||
"integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=",
|
||||
"dev": true
|
||||
},
|
||||
"jsonwebtoken": {
|
||||
"version": "8.3.0",
|
||||
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.3.0.tgz",
|
||||
"integrity": "sha512-oge/hvlmeJCH+iIz1DwcO7vKPkNGJHhgkspk8OH3VKlw+mbi42WtD4ig1+VXRln765vxptAv+xT26Fd3cteqag==",
|
||||
"requires": {
|
||||
"jws": "^3.1.5",
|
||||
"lodash.includes": "^4.3.0",
|
||||
"lodash.isboolean": "^3.0.3",
|
||||
"lodash.isinteger": "^4.0.4",
|
||||
"lodash.isnumber": "^3.0.3",
|
||||
"lodash.isplainobject": "^4.0.6",
|
||||
"lodash.isstring": "^4.0.1",
|
||||
"lodash.once": "^4.0.0",
|
||||
"ms": "^2.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"ms": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
|
||||
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"jsprim": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
|
||||
"integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"assert-plus": "1.0.0",
|
||||
"extsprintf": "1.3.0",
|
||||
@@ -11384,6 +11423,38 @@
|
||||
"verror": "1.10.0"
|
||||
}
|
||||
},
|
||||
"jwa": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.1.6.tgz",
|
||||
"integrity": "sha512-tBO/cf++BUsJkYql/kBbJroKOgHWEigTKBAjjBEmrMGYd1QMBC74Hr4Wo2zCZw6ZrVhlJPvoMrkcOnlWR/DJfw==",
|
||||
"requires": {
|
||||
"buffer-equal-constant-time": "1.0.1",
|
||||
"ecdsa-sig-formatter": "1.0.10",
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"jwks-rsa": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-1.3.0.tgz",
|
||||
"integrity": "sha512-9q+d5VffK/FvFAjuXoddrq7zQybFSINV4mcwJJExGKXGyjWWpTt3vsn/aX33aB0heY02LK0qSyicdtRK0gVTig==",
|
||||
"requires": {
|
||||
"@types/express-jwt": "0.0.34",
|
||||
"debug": "^2.2.0",
|
||||
"limiter": "^1.1.0",
|
||||
"lru-memoizer": "^1.6.0",
|
||||
"ms": "^2.0.0",
|
||||
"request": "^2.73.0"
|
||||
}
|
||||
},
|
||||
"jws": {
|
||||
"version": "3.1.5",
|
||||
"resolved": "https://registry.npmjs.org/jws/-/jws-3.1.5.tgz",
|
||||
"integrity": "sha512-GsCSexFADNQUr8T5HPJvayTjvPIfoyJPtLQBwn5a4WZQchcrPMPMAWcC1AzJVRDKyD6ZPROPAxgv6rfHViO4uQ==",
|
||||
"requires": {
|
||||
"jwa": "^1.1.5",
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"keygrip": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.0.2.tgz",
|
||||
@@ -11643,6 +11714,11 @@
|
||||
"type-check": "~0.3.2"
|
||||
}
|
||||
},
|
||||
"limiter": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.3.tgz",
|
||||
"integrity": "sha512-zrycnIMsLw/3ZxTbW7HCez56rcFGecWTx5OZNplzcXUUmJLmoYArC6qdJzmAN5BWiNXGcpjhF9RQ1HSv5zebEw=="
|
||||
},
|
||||
"load-cfg": {
|
||||
"version": "0.2.8",
|
||||
"resolved": "https://registry.npmjs.org/load-cfg/-/load-cfg-0.2.8.tgz",
|
||||
@@ -11768,6 +11844,11 @@
|
||||
"path-exists": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"lock": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/lock/-/lock-0.1.4.tgz",
|
||||
"integrity": "sha1-/sfervF+fDoKVeHaBCgD4l2RdF0="
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.10",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
|
||||
@@ -11843,16 +11924,41 @@
|
||||
"integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash.includes": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
|
||||
"integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8="
|
||||
},
|
||||
"lodash.isboolean": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
|
||||
"integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY="
|
||||
},
|
||||
"lodash.isempty": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isempty/-/lodash.isempty-4.4.0.tgz",
|
||||
"integrity": "sha1-b4bL7di+TsmHvpqvM8loTbGzHn4="
|
||||
},
|
||||
"lodash.isinteger": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
|
||||
"integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M="
|
||||
},
|
||||
"lodash.isnumber": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
|
||||
"integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w="
|
||||
},
|
||||
"lodash.isobject": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-3.0.2.tgz",
|
||||
"integrity": "sha1-PI+41bW/S/kK4G4U8qUwpO2TXh0="
|
||||
},
|
||||
"lodash.isplainobject": {
|
||||
"version": "4.0.6",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
|
||||
"integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs="
|
||||
},
|
||||
"lodash.isstring": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
|
||||
@@ -11880,6 +11986,11 @@
|
||||
"resolved": "https://registry.npmjs.org/lodash.noop/-/lodash.noop-3.0.1.tgz",
|
||||
"integrity": "sha1-OBiPTWUKOkdCWEObluxFsyYXEzw="
|
||||
},
|
||||
"lodash.once": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
|
||||
"integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w="
|
||||
},
|
||||
"lodash.partial": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash.partial/-/lodash.partial-4.2.1.tgz",
|
||||
@@ -12031,6 +12142,28 @@
|
||||
"yallist": "^2.1.2"
|
||||
}
|
||||
},
|
||||
"lru-memoizer": {
|
||||
"version": "1.12.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-memoizer/-/lru-memoizer-1.12.0.tgz",
|
||||
"integrity": "sha1-7+ZXBsyKnMZT+A8NWm6jitlQ41I=",
|
||||
"requires": {
|
||||
"lock": "~0.1.2",
|
||||
"lodash": "^4.17.4",
|
||||
"lru-cache": "~4.0.0",
|
||||
"very-fast-args": "^1.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"lru-cache": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.2.tgz",
|
||||
"integrity": "sha1-HRdnnAac2l0ECZGgnbwsDbN35V4=",
|
||||
"requires": {
|
||||
"pseudomap": "^1.0.1",
|
||||
"yallist": "^2.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"luxon": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/luxon/-/luxon-1.2.1.tgz",
|
||||
@@ -12918,11 +13051,15 @@
|
||||
"integrity": "sha512-Zt6HRR6RcJkuj5/N9zeE7FN6YitRW//hK2wTOwX274IBphbY3Zf5+yn5mZ9v/SzAOTMjQNxZf9KkmPLWn0cV4g==",
|
||||
"dev": true
|
||||
},
|
||||
"oauth": {
|
||||
"version": "0.9.15",
|
||||
"resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz",
|
||||
"integrity": "sha1-vR/vr2hslrdUda7VGWQS/2DPucE="
|
||||
},
|
||||
"oauth-sign": {
|
||||
"version": "0.8.2",
|
||||
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz",
|
||||
"integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=",
|
||||
"dev": true
|
||||
"integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM="
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
@@ -13316,6 +13453,17 @@
|
||||
"pause": "0.0.1"
|
||||
}
|
||||
},
|
||||
"passport-oauth2": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/passport-oauth2/-/passport-oauth2-1.4.0.tgz",
|
||||
"integrity": "sha1-9i+BWDy+EmCb585vFguTlaJ7hq0=",
|
||||
"requires": {
|
||||
"oauth": "0.9.x",
|
||||
"passport-strategy": "1.x.x",
|
||||
"uid2": "0.0.x",
|
||||
"utils-merge": "1.x.x"
|
||||
}
|
||||
},
|
||||
"passport-strategy": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz",
|
||||
@@ -15874,8 +16022,7 @@
|
||||
"pseudomap": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
|
||||
"integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=",
|
||||
"dev": true
|
||||
"integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM="
|
||||
},
|
||||
"psl": {
|
||||
"version": "1.1.28",
|
||||
@@ -17215,7 +17362,6 @@
|
||||
"version": "2.87.0",
|
||||
"resolved": "https://registry.npmjs.org/request/-/request-2.87.0.tgz",
|
||||
"integrity": "sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"aws-sign2": "~0.7.0",
|
||||
"aws4": "^1.6.0",
|
||||
@@ -17242,14 +17388,12 @@
|
||||
"punycode": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
|
||||
"integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
|
||||
"dev": true
|
||||
"integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
|
||||
},
|
||||
"tough-cookie": {
|
||||
"version": "2.3.4",
|
||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz",
|
||||
"integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"punycode": "^1.4.1"
|
||||
}
|
||||
@@ -17495,8 +17639,7 @@
|
||||
"safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||
},
|
||||
"sane": {
|
||||
"version": "2.5.2",
|
||||
@@ -18067,7 +18210,6 @@
|
||||
"version": "1.14.2",
|
||||
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz",
|
||||
"integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"asn1": "~0.2.3",
|
||||
"assert-plus": "^1.0.0",
|
||||
@@ -19325,7 +19467,6 @@
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
|
||||
"integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
@@ -19334,7 +19475,6 @@
|
||||
"version": "0.14.5",
|
||||
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
|
||||
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"type-check": {
|
||||
@@ -19619,6 +19759,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"uid2": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.3.tgz",
|
||||
"integrity": "sha1-SDEm4Rd03y9xuLY53NeZw3YWK4I="
|
||||
},
|
||||
"ulid": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ulid/-/ulid-2.3.0.tgz",
|
||||
@@ -20152,13 +20297,17 @@
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
|
||||
"integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"assert-plus": "^1.0.0",
|
||||
"core-util-is": "1.0.2",
|
||||
"extsprintf": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"very-fast-args": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/very-fast-args/-/very-fast-args-1.1.0.tgz",
|
||||
"integrity": "sha1-4W0dH6+KbllqJGQh/ZCneWPQs5Y="
|
||||
},
|
||||
"vfile": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/vfile/-/vfile-2.3.0.tgz",
|
||||
@@ -20961,8 +21110,7 @@
|
||||
"yallist": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
|
||||
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=",
|
||||
"dev": true
|
||||
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI="
|
||||
},
|
||||
"yargs": {
|
||||
"version": "11.0.0",
|
||||
|
||||
+10
-1
@@ -13,8 +13,10 @@
|
||||
"watch:css-types": "tcm src/core/client/ --watch",
|
||||
"watch:relay-stream": "nodemon --config ./config/nodemon/relay-stream.json",
|
||||
"watch:server": "nodemon --config ./config/nodemon/server.json",
|
||||
"watch:types": "nodemon --config ./config/nodemon/types.json",
|
||||
"compile:css-types": "tcm src/core/client/",
|
||||
"compile:relay-stream": "relay-compiler --src ./src/core/client/stream --schema ./src/core/server/graph/tenant/schema/schema.graphql --language typescript --artifactDirectory ./src/core/client/stream/__generated__ --no-watchman",
|
||||
"compile:server:types": "node ./scripts/types.js",
|
||||
"start:development": "NODE_ENV=development ts-node -r tsconfig-paths/register src/index.ts",
|
||||
"lint-fix": "npm run lint:server -- --fix && npm run lint:client -- --fix && npm run lint:scripts -- --fix",
|
||||
"lint": "npm-run-all --parallel lint:*",
|
||||
@@ -43,10 +45,14 @@
|
||||
"graphql-tools": "^3.0.2",
|
||||
"ioredis": "^3.2.2",
|
||||
"joi": "^13.4.0",
|
||||
"jsonwebtoken": "^8.3.0",
|
||||
"jwks-rsa": "^1.3.0",
|
||||
"lodash": "^4.17.10",
|
||||
"luxon": "^1.2.1",
|
||||
"mongodb": "^3.0.10",
|
||||
"passport": "^0.4.0",
|
||||
"passport-oauth2": "^1.4.0",
|
||||
"passport-strategy": "^1.0.0",
|
||||
"performance-now": "^2.1.0",
|
||||
"subscriptions-transport-ws": "^0.9.11",
|
||||
"uuid": "^3.2.1"
|
||||
@@ -66,11 +72,14 @@
|
||||
"@types/ioredis": "^3.2.8",
|
||||
"@types/jest": "^23.1.1",
|
||||
"@types/joi": "^13.0.8",
|
||||
"@types/jsonwebtoken": "^7.2.7",
|
||||
"@types/lodash": "^4.14.109",
|
||||
"@types/luxon": "^0.5.3",
|
||||
"@types/mongodb": "^3.0.19",
|
||||
"@types/node": "^10.3.1",
|
||||
"@types/passport": "^0.4.5",
|
||||
"@types/passport-oauth2": "^1.4.5",
|
||||
"@types/passport-strategy": "^0.2.33",
|
||||
"@types/query-string": "^6.1.0",
|
||||
"@types/react-dom": "^16.0.6",
|
||||
"@types/react-relay": "^1.3.6",
|
||||
@@ -140,4 +149,4 @@
|
||||
"webpack-hot-client": "^4.0.3",
|
||||
"webpack-manifest-plugin": "^2.0.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import http from "http";
|
||||
import { Redis } from "ioredis";
|
||||
import { Db } from "mongodb";
|
||||
|
||||
import { createPassport } from "talk-server/app/middleware/passport";
|
||||
import { Config } from "talk-server/config";
|
||||
import { handleSubscriptions } from "talk-server/graph/common/subscriptions/middleware";
|
||||
import { Schemas } from "talk-server/graph/schemas";
|
||||
@@ -35,8 +36,11 @@ export async function createApp(options: AppOptions): Promise<Express> {
|
||||
// Static Files
|
||||
parent.use(serveStatic);
|
||||
|
||||
// Create some services for the router.
|
||||
const passport = createPassport({ db: options.mongo });
|
||||
|
||||
// Mount the router.
|
||||
parent.use(await createRouter(options));
|
||||
parent.use(await createRouter(options, { passport }));
|
||||
|
||||
// Error Handling
|
||||
parent.use(errorLogger);
|
||||
|
||||
@@ -1,13 +1,89 @@
|
||||
import { Db } from "mongodb";
|
||||
import passport, { Authenticator } from "passport";
|
||||
|
||||
import { NextFunction, Response } from "express";
|
||||
import OIDCStrategy, {
|
||||
Token,
|
||||
VerifyCallback,
|
||||
} from "talk-server/app/middleware/passport/oidc";
|
||||
import { GQLUSER_ROLE } from "talk-server/graph/tenant/schema/__generated__/types";
|
||||
import { Tenant } from "talk-server/models/tenant";
|
||||
import { create, retrieveWithProfile, User } from "talk-server/models/user";
|
||||
import { Request } from "talk-server/types/express";
|
||||
|
||||
export interface PassportOptions {
|
||||
db: Db;
|
||||
}
|
||||
|
||||
export function createPassport(opts: PassportOptions): passport.Authenticator {
|
||||
async function verifyOIDC(
|
||||
db: Db,
|
||||
tenant: Tenant,
|
||||
{ iss, sub, email, email_verified }: Token,
|
||||
done: VerifyCallback
|
||||
) {
|
||||
try {
|
||||
// Construct the profile that will be used to query for the user.
|
||||
const profile = {
|
||||
type: "oidc",
|
||||
provider: iss,
|
||||
id: sub,
|
||||
};
|
||||
|
||||
// Try to lookup user given their id provided in the `sub` claim.
|
||||
let user = await retrieveWithProfile(db, tenant.id, profile);
|
||||
if (!user) {
|
||||
// FIXME: implement rules.
|
||||
|
||||
// Create the new user, as one didn't exist before!
|
||||
user = await create(db, tenant.id, {
|
||||
username: null,
|
||||
role: GQLUSER_ROLE.COMMENTER,
|
||||
email,
|
||||
email_verified,
|
||||
profiles: [profile],
|
||||
});
|
||||
}
|
||||
|
||||
return done(null, user);
|
||||
} catch (err) {
|
||||
return done(err);
|
||||
}
|
||||
}
|
||||
|
||||
export function createPassport({
|
||||
db,
|
||||
}: PassportOptions): passport.Authenticator {
|
||||
// Create the authenticator.
|
||||
const auth = new Authenticator();
|
||||
|
||||
// Process the OIDC Strategy.
|
||||
auth.use(new OIDCStrategy({ db }, verifyOIDC.bind(null, db)));
|
||||
|
||||
return auth;
|
||||
}
|
||||
|
||||
export const authenticate = (
|
||||
authenticator: passport.Authenticator,
|
||||
name: string
|
||||
) => (req: Request, res: Response, next: NextFunction) =>
|
||||
authenticator.authenticate(
|
||||
name,
|
||||
{ session: false },
|
||||
(err: Error | null, user: User | null) => {
|
||||
if (err) {
|
||||
// TODO: wrap error?
|
||||
return next(err);
|
||||
}
|
||||
|
||||
// Set the cache control headers.
|
||||
res.header(
|
||||
"Cache-Control",
|
||||
"private, no-cache, no-store, must-revalidate"
|
||||
);
|
||||
res.header("Expires", "-1");
|
||||
res.header("Pragma", "no-cache");
|
||||
|
||||
// Send back the details!
|
||||
res.json({ user });
|
||||
}
|
||||
)(req, res, next);
|
||||
|
||||
@@ -0,0 +1,223 @@
|
||||
import jwt from "jsonwebtoken";
|
||||
import jwks, { JwksClient } from "jwks-rsa";
|
||||
import { Strategy as OAuth2Strategy } from "passport-oauth2";
|
||||
import { Strategy } from "passport-strategy";
|
||||
|
||||
import { reconstructURL } from "talk-server/app/url";
|
||||
import { OIDCAuthIntegration, Tenant } from "talk-server/models/tenant";
|
||||
import { User } from "talk-server/models/user";
|
||||
import { Request } from "talk-server/types/express";
|
||||
|
||||
export type OIDCStrategyOptions = any;
|
||||
|
||||
export interface Params {
|
||||
id_token?: string;
|
||||
}
|
||||
|
||||
export type VerifyCallback = (
|
||||
err?: Error | null,
|
||||
user?: User | null,
|
||||
info?: object
|
||||
) => void;
|
||||
|
||||
export interface Token {
|
||||
iss: string;
|
||||
sub: string;
|
||||
email: string;
|
||||
email_verified?: boolean;
|
||||
}
|
||||
|
||||
export type OIDCStrategyCallback = (
|
||||
tenant: Tenant,
|
||||
token: Token,
|
||||
done: VerifyCallback
|
||||
) => void;
|
||||
|
||||
export interface StrategyItem {
|
||||
strategy: OAuth2Strategy;
|
||||
jwksClient?: JwksClient;
|
||||
}
|
||||
|
||||
// FIXME: attach strategy to cache updates of the tenants
|
||||
|
||||
export default class OIDCStrategy extends Strategy {
|
||||
public name: string;
|
||||
|
||||
private verify: OIDCStrategyCallback;
|
||||
private cache: Map<string, StrategyItem>;
|
||||
|
||||
constructor(options: OIDCStrategyOptions, verify: OIDCStrategyCallback) {
|
||||
super();
|
||||
|
||||
this.name = "oidc";
|
||||
this.cache = new Map();
|
||||
this.verify = verify;
|
||||
}
|
||||
|
||||
private lookupJWKSClient(
|
||||
req: Request,
|
||||
tenantID: string,
|
||||
oidc: OIDCAuthIntegration
|
||||
) {
|
||||
let entry = this.cache.get(tenantID);
|
||||
if (!entry) {
|
||||
const strategy = this.createStrategy(req, oidc);
|
||||
|
||||
// Create the entry.
|
||||
entry = {
|
||||
strategy,
|
||||
};
|
||||
|
||||
// We don't reset the entry in the cache here because if we just created
|
||||
// it, we'll be creating the jwksClient anyways, so we'll update it there.
|
||||
}
|
||||
|
||||
if (!entry.jwksClient) {
|
||||
// Create the new JWKS client.
|
||||
const jwksClient = jwks({
|
||||
jwksUri: oidc.jwksURI,
|
||||
});
|
||||
|
||||
// Set the jwksClient on the entry.
|
||||
entry.jwksClient = jwksClient;
|
||||
|
||||
// Update the cached entry.
|
||||
this.cache.set(tenantID, entry);
|
||||
}
|
||||
|
||||
return entry.jwksClient;
|
||||
}
|
||||
|
||||
private verifyCallback(
|
||||
req: Request,
|
||||
accessToken: string,
|
||||
refreshToken: string,
|
||||
params: Params,
|
||||
profile: any,
|
||||
done: VerifyCallback
|
||||
) {
|
||||
// Try to lookup user given their id provided in the `sub` claim of the
|
||||
// `id_token`.
|
||||
const { id_token } = params;
|
||||
if (!id_token) {
|
||||
// TODO: return better error.
|
||||
return done(new Error("no id_token in params"));
|
||||
}
|
||||
|
||||
// Grab the tenant out of the request, as we need some more details.
|
||||
const { tenant } = req;
|
||||
|
||||
// Grab the JWKSClient.
|
||||
const client = this.lookupJWKSClient(req, tenant!.id, tenant!.auth.oidc!);
|
||||
|
||||
// Verify that the id_token is valid or not.
|
||||
jwt.verify(
|
||||
id_token,
|
||||
({ kid }, callback) => {
|
||||
if (!kid) {
|
||||
// TODO: return better error.
|
||||
return callback(new Error("no kid in id_token"));
|
||||
}
|
||||
|
||||
// Get the signing key from the jwks provider.
|
||||
client.getSigningKey(kid, (err, key) => {
|
||||
if (err) {
|
||||
// TODO: wrap error?
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
const signingKey = key.publicKey || key.rsaPublicKey;
|
||||
callback(null, signingKey);
|
||||
});
|
||||
},
|
||||
{
|
||||
issuer: tenant!.auth.oidc!.issuer,
|
||||
},
|
||||
(err, decoded) => {
|
||||
if (err) {
|
||||
// TODO: wrap error?
|
||||
return done(err);
|
||||
}
|
||||
|
||||
this.verify(tenant!, decoded as Token, done);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private createStrategy(
|
||||
req: Request,
|
||||
integration: OIDCAuthIntegration
|
||||
): OAuth2Strategy {
|
||||
const { clientID, clientSecret, authorizationURL, tokenURL } = integration;
|
||||
|
||||
// Construct the callbackURL from the request.
|
||||
const callbackURL = reconstructURL(req, "/api/tenant/auth/oidc/callback");
|
||||
|
||||
// Create a new OAuth2Strategy, where we pass the verify callback bound to
|
||||
// this OIDCStrategy instance.
|
||||
return new OAuth2Strategy(
|
||||
{
|
||||
passReqToCallback: true,
|
||||
clientID,
|
||||
clientSecret,
|
||||
authorizationURL,
|
||||
tokenURL,
|
||||
callbackURL,
|
||||
},
|
||||
this.verifyCallback.bind(this)
|
||||
);
|
||||
}
|
||||
|
||||
private async lookupStrategy(req: Request) {
|
||||
const { tenant } = req;
|
||||
if (!tenant) {
|
||||
// TODO: return a better error.
|
||||
throw new Error("tenant not found");
|
||||
}
|
||||
|
||||
// Get the integration from the tenant. If needed, it will be used to create
|
||||
// a new strategy.
|
||||
const integration = tenant.auth.oidc;
|
||||
if (!integration) {
|
||||
// TODO: return a better error.
|
||||
throw new Error("integration not found");
|
||||
}
|
||||
|
||||
// Try to get the Tenant's cached integrations.
|
||||
let entry = this.cache.get(tenant.id);
|
||||
if (!entry) {
|
||||
// Create the strategy.
|
||||
const strategy = this.createStrategy(req, integration);
|
||||
|
||||
// Reset the entry.
|
||||
entry = {
|
||||
strategy,
|
||||
};
|
||||
|
||||
// Update the cached integrations value.
|
||||
this.cache.set(tenant.id, entry);
|
||||
}
|
||||
|
||||
return entry.strategy;
|
||||
}
|
||||
|
||||
public async authenticate(req: Request) {
|
||||
// Lookup the strategy.
|
||||
const strategy = await this.lookupStrategy(req);
|
||||
if (!strategy) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Augment the strategy with the request method bindings.
|
||||
strategy.error = this.error.bind(this);
|
||||
strategy.fail = this.fail.bind(this);
|
||||
strategy.pass = this.pass.bind(this);
|
||||
strategy.redirect = this.redirect.bind(this);
|
||||
strategy.success = this.success.bind(this);
|
||||
|
||||
// Authenticate with the strategy, binding the current context to the method
|
||||
// to provide it with the augmented passport handlers. We also request the
|
||||
// 'openid' scope so we can get an id_token back.
|
||||
strategy.authenticate(req, { scope: "openid email", session: false });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { Strategy } from "passport-strategy";
|
||||
|
||||
import { Request } from "talk-server/types/express";
|
||||
|
||||
export default class SSOStrategy extends Strategy {
|
||||
public async authenticate(req: Request) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,15 @@
|
||||
import express from "express";
|
||||
import passport from "passport";
|
||||
|
||||
import tenantMiddleware from "talk-server/app/middleware/tenant";
|
||||
import managementGraphMiddleware from "talk-server/graph/management/middleware";
|
||||
import tenantGraphMiddleware from "talk-server/graph/tenant/middleware";
|
||||
|
||||
import { authenticate } from "talk-server/app/middleware/passport";
|
||||
import { AppOptions } from "./index";
|
||||
import playground from "./middleware/playground";
|
||||
|
||||
async function createManagementRouter(opts: AppOptions) {
|
||||
async function createManagementRouter(app: AppOptions, options: RouterOptions) {
|
||||
const router = express.Router();
|
||||
|
||||
// Management API
|
||||
@@ -15,51 +17,63 @@ async function createManagementRouter(opts: AppOptions) {
|
||||
"/graphql",
|
||||
express.json(),
|
||||
await managementGraphMiddleware(
|
||||
opts.schemas.management,
|
||||
opts.config,
|
||||
opts.mongo
|
||||
app.schemas.management,
|
||||
app.config,
|
||||
app.mongo
|
||||
)
|
||||
);
|
||||
|
||||
return router;
|
||||
}
|
||||
|
||||
async function createTenantRouter(opts: AppOptions) {
|
||||
async function createTenantRouter(app: AppOptions, options: RouterOptions) {
|
||||
const router = express.Router();
|
||||
|
||||
// Tenant identification middleware.
|
||||
router.use(tenantMiddleware({ db: opts.mongo }));
|
||||
router.use(tenantMiddleware({ db: app.mongo }));
|
||||
|
||||
router.use(options.passport.initialize());
|
||||
router.use("/auth/oidc", authenticate(options.passport, "oidc"));
|
||||
router.use("/auth/oidc/callback", authenticate(options.passport, "oidc"));
|
||||
// router.use("/auth/google", options.passport.authenticate("google"));
|
||||
// router.use("/auth/google/callback", options.passport.authenticate("google"));
|
||||
// router.use("/auth/facebook", options.passport.authenticate("facebook"));
|
||||
// router.use("/auth/facebook/callback", options.passport.authenticate("facebook"));
|
||||
|
||||
// Tenant API
|
||||
router.use(
|
||||
"/graphql",
|
||||
express.json(),
|
||||
await tenantGraphMiddleware(opts.schemas.tenant, opts.config, opts.mongo)
|
||||
await tenantGraphMiddleware(app.schemas.tenant, app.config, app.mongo)
|
||||
);
|
||||
|
||||
return router;
|
||||
}
|
||||
|
||||
async function createAPIRouter(opts: AppOptions) {
|
||||
async function createAPIRouter(app: AppOptions, options: RouterOptions) {
|
||||
// Create a router.
|
||||
const router = express.Router();
|
||||
|
||||
// Configure the tenant routes.
|
||||
router.use("/tenant", await createTenantRouter(opts));
|
||||
router.use("/tenant", await createTenantRouter(app, options));
|
||||
|
||||
// Configure the management routes.
|
||||
router.use("/management", await createManagementRouter(opts));
|
||||
router.use("/management", await createManagementRouter(app, options));
|
||||
|
||||
return router;
|
||||
}
|
||||
|
||||
export async function createRouter(opts: AppOptions) {
|
||||
export interface RouterOptions {
|
||||
passport: passport.Authenticator;
|
||||
}
|
||||
|
||||
export async function createRouter(app: AppOptions, options: RouterOptions) {
|
||||
// Create a router.
|
||||
const router = express.Router();
|
||||
|
||||
router.use("/api", await createAPIRouter(opts));
|
||||
router.use("/api", await createAPIRouter(app, options));
|
||||
|
||||
if (opts.config.get("env") === "development") {
|
||||
if (app.config.get("env") === "development") {
|
||||
// Tenant GraphiQL
|
||||
router.get(
|
||||
"/tenant/graphiql",
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import { Request } from "talk-server/types/express";
|
||||
import { URL } from "url";
|
||||
|
||||
export function reconstructURL(req: Request, input?: string): string {
|
||||
const scheme = req.secure ? "https" : "http";
|
||||
const host = req.get("host");
|
||||
const base = `${scheme}://${host}`;
|
||||
const path = input || req.originalUrl;
|
||||
|
||||
const url = new URL(path, base);
|
||||
|
||||
return url.href;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import { DirectiveResolverFn } from "graphql-tools";
|
||||
|
||||
const auth: DirectiveResolverFn = (next, src, args, context) => {
|
||||
return next().then(str => {
|
||||
if (typeof str === "string") {
|
||||
return str.toUpperCase();
|
||||
}
|
||||
return str;
|
||||
});
|
||||
};
|
||||
|
||||
export default auth;
|
||||
@@ -0,0 +1,14 @@
|
||||
import { GQLAuthSettingsTypeResolver } from "talk-server/graph/tenant/schema/__generated__/types";
|
||||
import { Auth, AuthIntegration } from "talk-server/models/tenant";
|
||||
|
||||
const disabled: AuthIntegration = { enabled: false };
|
||||
|
||||
const AuthSettings: GQLAuthSettingsTypeResolver<Auth> = {
|
||||
local: auth => auth.local || disabled,
|
||||
sso: auth => auth.sso || disabled,
|
||||
oidc: auth => auth.oidc || disabled,
|
||||
google: auth => auth.google || disabled,
|
||||
facebook: auth => auth.facebook || disabled,
|
||||
};
|
||||
|
||||
export default AuthSettings;
|
||||
@@ -0,0 +1,10 @@
|
||||
import { GQLFacebookAuthIntegrationTypeResolver } from "talk-server/graph/tenant/schema/__generated__/types";
|
||||
import { FacebookAuthIntegration } from "talk-server/models/tenant";
|
||||
|
||||
const FacebookAuthIntegration: GQLFacebookAuthIntegrationTypeResolver<
|
||||
FacebookAuthIntegration
|
||||
> = {
|
||||
config: auth => auth,
|
||||
};
|
||||
|
||||
export default FacebookAuthIntegration;
|
||||
@@ -0,0 +1,10 @@
|
||||
import { GQLGoogleAuthIntegrationTypeResolver } from "talk-server/graph/tenant/schema/__generated__/types";
|
||||
import { GoogleAuthIntegration } from "talk-server/models/tenant";
|
||||
|
||||
const GoogleAuthIntegration: GQLGoogleAuthIntegrationTypeResolver<
|
||||
GoogleAuthIntegration
|
||||
> = {
|
||||
config: auth => auth,
|
||||
};
|
||||
|
||||
export default GoogleAuthIntegration;
|
||||
@@ -0,0 +1,8 @@
|
||||
import { GQLLocalAuthIntegrationTypeResolver } from "talk-server/graph/tenant/schema/__generated__/types";
|
||||
import { LocalAuthIntegration } from "talk-server/models/tenant";
|
||||
|
||||
const LocalAuthIntegration: GQLLocalAuthIntegrationTypeResolver<
|
||||
LocalAuthIntegration
|
||||
> = {};
|
||||
|
||||
export default LocalAuthIntegration;
|
||||
@@ -0,0 +1,10 @@
|
||||
import { GQLOIDCAuthIntegrationTypeResolver } from "talk-server/graph/tenant/schema/__generated__/types";
|
||||
import { OIDCAuthIntegration } from "talk-server/models/tenant";
|
||||
|
||||
const OIDCAuthIntegration: GQLOIDCAuthIntegrationTypeResolver<
|
||||
OIDCAuthIntegration
|
||||
> = {
|
||||
config: auth => auth,
|
||||
};
|
||||
|
||||
export default OIDCAuthIntegration;
|
||||
@@ -0,0 +1,10 @@
|
||||
import { GQLSSOAuthIntegrationTypeResolver } from "talk-server/graph/tenant/schema/__generated__/types";
|
||||
import { SSOAuthIntegration } from "talk-server/models/tenant";
|
||||
|
||||
const SSOAuthIntegration: GQLSSOAuthIntegrationTypeResolver<
|
||||
SSOAuthIntegration
|
||||
> = {
|
||||
config: auth => auth,
|
||||
};
|
||||
|
||||
export default SSOAuthIntegration;
|
||||
@@ -1,8 +1,14 @@
|
||||
import { IResolvers } from "graphql-tools";
|
||||
import { attachDirectiveResolvers, IResolvers } from "graphql-tools";
|
||||
|
||||
import auth from "talk-server/graph/common/directives/auth";
|
||||
import loadSchema from "talk-server/graph/common/schema";
|
||||
import resolvers from "talk-server/graph/tenant/resolvers";
|
||||
|
||||
export default function getTenantSchema() {
|
||||
return loadSchema("tenant", resolvers as IResolvers);
|
||||
const schema = loadSchema("tenant", resolvers as IResolvers);
|
||||
|
||||
// Attach the directive resolvers.
|
||||
attachDirectiveResolvers(schema, { auth });
|
||||
|
||||
return schema;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
################################################################################
|
||||
## Custom Directives
|
||||
################################################################################
|
||||
|
||||
directive @auth(roles: [USER_ROLE!]!) on FIELD_DEFINITION
|
||||
|
||||
################################################################################
|
||||
## Custom Scalar Types
|
||||
################################################################################
|
||||
@@ -45,7 +51,90 @@ type WordlistSettings {
|
||||
suspect: [String!]!
|
||||
}
|
||||
|
||||
# Settings stores the global settings for a given installation.
|
||||
################################################################################
|
||||
## AuthSettings
|
||||
################################################################################
|
||||
|
||||
##########################
|
||||
## LocalAuthIntegration
|
||||
##########################
|
||||
|
||||
type LocalAuthIntegration {
|
||||
enabled: Boolean!
|
||||
}
|
||||
|
||||
##########################
|
||||
## SSOAuthIntegration
|
||||
##########################
|
||||
|
||||
type SSOAuthIntegrationConfig {
|
||||
key: String!
|
||||
}
|
||||
|
||||
type SSOAuthIntegration {
|
||||
enabled: Boolean!
|
||||
config: SSOAuthIntegrationConfig @auth(roles: [ADMIN])
|
||||
}
|
||||
|
||||
##########################
|
||||
## OIDCAuthIntegration
|
||||
##########################
|
||||
|
||||
type OIDCAuthIntegrationConfig {
|
||||
clientID: String!
|
||||
clientSecret: String!
|
||||
authorizationURL: String!
|
||||
tokenURL: String!
|
||||
}
|
||||
|
||||
type OIDCAuthIntegrationOptions {
|
||||
name: String!
|
||||
}
|
||||
|
||||
type OIDCAuthIntegration {
|
||||
enabled: Boolean!
|
||||
options: OIDCAuthIntegrationOptions
|
||||
config: SSOAuthIntegrationConfig @auth(roles: [ADMIN])
|
||||
}
|
||||
|
||||
##########################
|
||||
## GoogleAuthIntegration
|
||||
##########################
|
||||
|
||||
type GoogleAuthIntegrationConfig {
|
||||
clientID: String!
|
||||
clientSecret: String!
|
||||
}
|
||||
|
||||
type GoogleAuthIntegration {
|
||||
enabled: Boolean!
|
||||
config: GoogleAuthIntegrationConfig @auth(roles: [ADMIN])
|
||||
}
|
||||
|
||||
##########################
|
||||
## FacebookAuthIntegration
|
||||
##########################
|
||||
|
||||
type FacebookAuthIntegrationConfig {
|
||||
clientID: String!
|
||||
clientSecret: String!
|
||||
}
|
||||
|
||||
type FacebookAuthIntegration {
|
||||
enabled: Boolean!
|
||||
config: FacebookAuthIntegrationConfig @auth(roles: [ADMIN])
|
||||
}
|
||||
|
||||
"""
|
||||
AuthSettings contains all the settings related to authentication and authorization.
|
||||
"""
|
||||
type AuthSettings {
|
||||
local: LocalAuthIntegration!
|
||||
sso: SSOAuthIntegration!
|
||||
oidc: OIDCAuthIntegration!
|
||||
google: GoogleAuthIntegration!
|
||||
facebook: FacebookAuthIntegration!
|
||||
}
|
||||
|
||||
################################################################################
|
||||
## Settings
|
||||
@@ -58,12 +147,12 @@ type Settings {
|
||||
"""
|
||||
domain is the domain that is associated with this Tenant.
|
||||
"""
|
||||
domain: String!
|
||||
domain: String @auth(roles: [ADMIN])
|
||||
|
||||
"""
|
||||
moderation is the moderation mode for all Asset's on the site.
|
||||
"""
|
||||
moderation: MODERATION_MODE!
|
||||
moderation: MODERATION_MODE @auth(roles: [ADMIN])
|
||||
|
||||
"""
|
||||
Enables a requirement for email confirmation before a user can login.
|
||||
@@ -100,7 +189,7 @@ type Settings {
|
||||
"""
|
||||
premodLinksEnable will put all comments that contain links into premod.
|
||||
"""
|
||||
premodLinksEnable: Boolean!
|
||||
premodLinksEnable: Boolean @auth(roles: [ADMIN])
|
||||
|
||||
"""
|
||||
autoCloseStream when true will auto close the stream when the `closeTimeout`
|
||||
@@ -165,18 +254,29 @@ type Settings {
|
||||
"""
|
||||
wordlist will return a given list of words.
|
||||
"""
|
||||
wordlist: WordlistSettings!
|
||||
wordlist: WordlistSettings @auth(roles: [ADMIN])
|
||||
|
||||
"""
|
||||
domains will return a given list of whitelisted domains.
|
||||
"""
|
||||
domains: [String!]!
|
||||
domains: [String!] @auth(roles: [ADMIN])
|
||||
|
||||
"""
|
||||
auth contains all the settings related to authentication and authorization.
|
||||
"""
|
||||
auth: AuthSettings!
|
||||
}
|
||||
|
||||
################################################################################
|
||||
## User
|
||||
################################################################################
|
||||
|
||||
enum USER_ROLE {
|
||||
COMMENTER
|
||||
MODERATOR
|
||||
ADMIN
|
||||
}
|
||||
|
||||
"""
|
||||
User is someone that leaves Comments, and logs in.
|
||||
"""
|
||||
@@ -190,6 +290,11 @@ type User {
|
||||
username is the name of the User visible to other Users.
|
||||
"""
|
||||
username: String!
|
||||
|
||||
"""
|
||||
role is the current role of the User.
|
||||
"""
|
||||
role: USER_ROLE!
|
||||
}
|
||||
|
||||
################################################################################
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import dotize from "dotize";
|
||||
import { merge } from "lodash";
|
||||
import { Db } from "mongodb";
|
||||
import { Sub } from "talk-common/types";
|
||||
import uuid from "uuid";
|
||||
|
||||
import { Sub } from "talk-common/types";
|
||||
import { GQLUSER_ROLE } from "talk-server/graph/tenant/schema/__generated__/types";
|
||||
|
||||
function collection(db: Db) {
|
||||
return db.collection<Readonly<Tenant>>("tenants");
|
||||
}
|
||||
@@ -22,6 +24,92 @@ export enum Moderation {
|
||||
POST = "POST",
|
||||
}
|
||||
|
||||
// AuthIntegrations.
|
||||
|
||||
export interface EmailDomainRuleCondition {
|
||||
// emailDomain is the domain name component of the email addresses that should
|
||||
// match for this condition.
|
||||
emailDomain: string;
|
||||
|
||||
// emailVerifiedRequired stipulates that this rule only applies when the user
|
||||
// account has been marked as having their email address already verified.
|
||||
emailVerifiedRequired: boolean;
|
||||
}
|
||||
|
||||
// RoleRule describes the role assignment for when a user logs into Talk, how
|
||||
// they can have their account automatically upgraded to a specific role when
|
||||
// the domain for their email matches the one provided.
|
||||
export interface RoleRule extends Partial<EmailDomainRuleCondition> {
|
||||
// role is the specific GQLUSER_ROLE that should be assigned to the newly created
|
||||
// user depending on their email address.
|
||||
role: GQLUSER_ROLE;
|
||||
}
|
||||
|
||||
export interface AuthRules {
|
||||
// roles allow the configuration of automatic role assignment based on the
|
||||
// user's email address.
|
||||
roles?: RoleRule[];
|
||||
|
||||
// restrictTo when populated, will restrict which users can login using this
|
||||
// integration. If a user successfully logs in using the OIDCStrategy, but
|
||||
// does not match the following rules, the user will not be created.
|
||||
restrictTo?: EmailDomainRuleCondition[];
|
||||
}
|
||||
|
||||
export interface AuthIntegration {
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
// SSOAuthIntegration is an AuthIntegration that provides a secret to the admins
|
||||
// of a tenant, where they can sign a SSO payload with it to provide to the
|
||||
// embed to allow single sign on.
|
||||
export interface SSOAuthIntegration extends AuthIntegration {
|
||||
key: string;
|
||||
}
|
||||
|
||||
// OIDCAuthIntegration provides a way to store Open ID Connect credentials. This
|
||||
// will be used in the admin to provide staff logins for users.
|
||||
export interface OIDCAuthIntegration extends AuthIntegration {
|
||||
clientID: string;
|
||||
clientSecret: string;
|
||||
issuer: string;
|
||||
authorizationURL: string;
|
||||
jwksURI: string;
|
||||
tokenURL: string;
|
||||
}
|
||||
|
||||
export interface FacebookAuthIntegration extends AuthIntegration {
|
||||
clientID: string;
|
||||
clientSecret: string;
|
||||
}
|
||||
|
||||
export interface GoogleAuthIntegration extends AuthIntegration {
|
||||
clientID: string;
|
||||
clientSecret: string;
|
||||
}
|
||||
|
||||
export type LocalAuthIntegration = AuthIntegration;
|
||||
|
||||
// Auth describes all of the possible auth integration configurations.
|
||||
export interface Auth {
|
||||
// local is the auth integration for the local auth.
|
||||
local: LocalAuthIntegration;
|
||||
|
||||
// sso is the external auth integration for the single sign on auth.
|
||||
sso?: SSOAuthIntegration;
|
||||
|
||||
// sso is the external auth integration for the OpenID Connect auth.
|
||||
oidc?: OIDCAuthIntegration;
|
||||
|
||||
// sso is the external auth integration for the Google auth.
|
||||
google?: GoogleAuthIntegration;
|
||||
|
||||
// sso is the external auth integration for the Facebook auth.
|
||||
facebook?: FacebookAuthIntegration;
|
||||
}
|
||||
|
||||
// Tenant definition.
|
||||
|
||||
export interface Tenant {
|
||||
readonly id: string;
|
||||
|
||||
@@ -57,6 +145,9 @@ export interface Tenant {
|
||||
|
||||
// domains is the set of whitelisted domains.
|
||||
domains: string[];
|
||||
|
||||
// Set of configured authentication integrations.
|
||||
auth: Auth;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -99,6 +190,11 @@ export async function createTenant(db: Db, input: CreateTenantInput) {
|
||||
suspect: [],
|
||||
banned: [],
|
||||
},
|
||||
auth: {
|
||||
local: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Create the new Tenant by merging it together with the defaults.
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { merge } from "lodash";
|
||||
import { Db } from "mongodb";
|
||||
import uuid from "uuid";
|
||||
|
||||
import { Omit, Sub } from "talk-common/types";
|
||||
import { GQLUSER_ROLE } from "talk-server/graph/tenant/schema/__generated__/types";
|
||||
import { ActionCounts } from "talk-server/models/actions";
|
||||
import { TenantResource } from "talk-server/models/tenant";
|
||||
import uuid from "uuid";
|
||||
|
||||
function collection(db: Db) {
|
||||
return db.collection<Readonly<User>>("users");
|
||||
@@ -11,6 +13,7 @@ function collection(db: Db) {
|
||||
|
||||
export interface Profile {
|
||||
readonly id: string;
|
||||
readonly type: string;
|
||||
provider: string;
|
||||
}
|
||||
|
||||
@@ -45,13 +48,6 @@ export enum UserUsernameStatus {
|
||||
CHANGED = "CHANGED",
|
||||
}
|
||||
|
||||
export enum UserRole {
|
||||
ADMIN = "ADMIN",
|
||||
MODERATOR = "MODERATOR",
|
||||
STAFF = "STAFF",
|
||||
COMMENTER = "COMMENTER",
|
||||
}
|
||||
|
||||
export interface UserStatusHistory<T> {
|
||||
status: T; // TODO: migrate field
|
||||
assigned_by?: string;
|
||||
@@ -72,11 +68,13 @@ export interface UserStatus {
|
||||
|
||||
export interface User extends TenantResource {
|
||||
readonly id: string;
|
||||
username: string;
|
||||
username: string | null;
|
||||
password?: string;
|
||||
email?: string;
|
||||
email_verified?: boolean;
|
||||
profiles: Profile[];
|
||||
tokens: Token[];
|
||||
role: UserRole;
|
||||
role: GQLUSER_ROLE;
|
||||
status: UserStatus;
|
||||
action_counts: ActionCounts;
|
||||
ignored_users: string[]; // TODO: migrate field
|
||||
@@ -89,7 +87,6 @@ export type CreateUserInput = Omit<
|
||||
| "tenant_id"
|
||||
| "tokens"
|
||||
| "status"
|
||||
| "role"
|
||||
| "action_counts"
|
||||
| "ignored_users"
|
||||
| "created_at"
|
||||
@@ -98,15 +95,11 @@ export type CreateUserInput = Omit<
|
||||
export async function create(db: Db, tenantID: string, input: CreateUserInput) {
|
||||
const now = new Date();
|
||||
|
||||
// // Pull out some useful properties from the input.
|
||||
// const { body, status } = input;
|
||||
|
||||
// default are the properties set by the application when a new user is
|
||||
// created.
|
||||
const defaults: Sub<User, CreateUserInput> = {
|
||||
id: uuid.v4(),
|
||||
tenant_id: tenantID,
|
||||
role: UserRole.COMMENTER,
|
||||
tokens: [],
|
||||
action_counts: {},
|
||||
ignored_users: [],
|
||||
@@ -120,7 +113,9 @@ export async function create(db: Db, tenantID: string, input: CreateUserInput) {
|
||||
history: [],
|
||||
},
|
||||
username: {
|
||||
status: UserUsernameStatus.SET,
|
||||
status: input.username
|
||||
? UserUsernameStatus.SET
|
||||
: UserUsernameStatus.UNSET,
|
||||
history: [],
|
||||
},
|
||||
},
|
||||
@@ -153,11 +148,24 @@ export async function retrieveMany(db: Db, tenantID: string, ids: string[]) {
|
||||
return ids.map(id => users.find(comment => comment.id === id) || null);
|
||||
}
|
||||
|
||||
export async function retrieveWithProfile(
|
||||
db: Db,
|
||||
tenantID: string,
|
||||
profile: Profile
|
||||
) {
|
||||
return collection(db).findOne({
|
||||
tenant_id: tenantID,
|
||||
profiles: {
|
||||
$elemMatch: profile,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export async function updateRole(
|
||||
db: Db,
|
||||
tenantID: string,
|
||||
id: string,
|
||||
role: UserRole
|
||||
role: GQLUSER_ROLE
|
||||
) {
|
||||
const result = await collection(db).findOneAndUpdate(
|
||||
{ id, tenant_id: tenantID },
|
||||
|
||||
Vendored
+19
@@ -0,0 +1,19 @@
|
||||
import { VerifyOptions, VerifyCallback } from "jsonwebtoken";
|
||||
|
||||
declare module "jsonwebtoken" {
|
||||
export type KeyFunctionCallback = (
|
||||
err: Error | null,
|
||||
secretOrPublicKey?: string | Buffer
|
||||
) => void;
|
||||
export type KeyFunction = (
|
||||
headers: { kid?: string },
|
||||
callback: KeyFunctionCallback
|
||||
) => void;
|
||||
|
||||
export function verify(
|
||||
token: string,
|
||||
secretOrPublicKey: string | Buffer | KeyFunction,
|
||||
options?: VerifyOptions,
|
||||
callback?: VerifyCallback
|
||||
): void;
|
||||
}
|
||||
Vendored
+16
@@ -0,0 +1,16 @@
|
||||
declare module "webfinger" {
|
||||
export interface WebfingerOptions {
|
||||
webfingerOnly?: boolean;
|
||||
}
|
||||
|
||||
export interface WebfingerCallback {
|
||||
(err: Error, jrd: { [key: string]: any }): void;
|
||||
}
|
||||
|
||||
export function webfinger(
|
||||
resource: string,
|
||||
res: string,
|
||||
options: WebfingerOptions,
|
||||
callback: WebfingerCallback
|
||||
): void;
|
||||
}
|
||||
Reference in New Issue
Block a user