@beiguancyc/parse-server 9.9.0-ruixiang.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (251) hide show
  1. package/LICENSE +176 -0
  2. package/NOTICE +10 -0
  3. package/README.md +1311 -0
  4. package/bin/parse-live-query-server +3 -0
  5. package/bin/parse-server +3 -0
  6. package/lib/AccountLockout.js +149 -0
  7. package/lib/Adapters/AdapterLoader.js +60 -0
  8. package/lib/Adapters/Analytics/AnalyticsAdapter.js +32 -0
  9. package/lib/Adapters/Auth/AuthAdapter.js +132 -0
  10. package/lib/Adapters/Auth/BaseCodeAuthAdapter.js +119 -0
  11. package/lib/Adapters/Auth/OAuth1Client.js +204 -0
  12. package/lib/Adapters/Auth/apple.js +125 -0
  13. package/lib/Adapters/Auth/facebook.js +187 -0
  14. package/lib/Adapters/Auth/gcenter.js +217 -0
  15. package/lib/Adapters/Auth/github.js +125 -0
  16. package/lib/Adapters/Auth/google.js +122 -0
  17. package/lib/Adapters/Auth/gpgames.js +125 -0
  18. package/lib/Adapters/Auth/httpsRequest.js +41 -0
  19. package/lib/Adapters/Auth/index.js +248 -0
  20. package/lib/Adapters/Auth/instagram.js +118 -0
  21. package/lib/Adapters/Auth/janraincapture.js +85 -0
  22. package/lib/Adapters/Auth/janrainengage.js +57 -0
  23. package/lib/Adapters/Auth/keycloak.js +168 -0
  24. package/lib/Adapters/Auth/ldap.js +193 -0
  25. package/lib/Adapters/Auth/line.js +125 -0
  26. package/lib/Adapters/Auth/linkedin.js +117 -0
  27. package/lib/Adapters/Auth/meetup.js +44 -0
  28. package/lib/Adapters/Auth/mfa.js +334 -0
  29. package/lib/Adapters/Auth/microsoft.js +111 -0
  30. package/lib/Adapters/Auth/oauth2.js +115 -0
  31. package/lib/Adapters/Auth/phantauth.js +53 -0
  32. package/lib/Adapters/Auth/qq.js +113 -0
  33. package/lib/Adapters/Auth/spotify.js +115 -0
  34. package/lib/Adapters/Auth/twitter.js +197 -0
  35. package/lib/Adapters/Auth/utils.js +28 -0
  36. package/lib/Adapters/Auth/vkontakte.js +55 -0
  37. package/lib/Adapters/Auth/wechat.js +110 -0
  38. package/lib/Adapters/Auth/weibo.js +141 -0
  39. package/lib/Adapters/Cache/CacheAdapter.js +40 -0
  40. package/lib/Adapters/Cache/InMemoryCache.js +61 -0
  41. package/lib/Adapters/Cache/InMemoryCacheAdapter.js +34 -0
  42. package/lib/Adapters/Cache/LRUCache.js +35 -0
  43. package/lib/Adapters/Cache/NullCacheAdapter.js +26 -0
  44. package/lib/Adapters/Cache/RedisCacheAdapter.js +109 -0
  45. package/lib/Adapters/Cache/SchemaCache.js +25 -0
  46. package/lib/Adapters/Email/MailAdapter.js +32 -0
  47. package/lib/Adapters/Files/FilesAdapter.js +129 -0
  48. package/lib/Adapters/Files/GridFSBucketAdapter.js +280 -0
  49. package/lib/Adapters/Files/GridStoreAdapter.js +5 -0
  50. package/lib/Adapters/Logger/LoggerAdapter.js +27 -0
  51. package/lib/Adapters/Logger/WinstonLogger.js +107 -0
  52. package/lib/Adapters/Logger/WinstonLoggerAdapter.js +63 -0
  53. package/lib/Adapters/MessageQueue/EventEmitterMQ.js +55 -0
  54. package/lib/Adapters/PubSub/EventEmitterPubSub.js +53 -0
  55. package/lib/Adapters/PubSub/PubSubAdapter.js +34 -0
  56. package/lib/Adapters/PubSub/RedisPubSub.js +49 -0
  57. package/lib/Adapters/Push/PushAdapter.js +40 -0
  58. package/lib/Adapters/Storage/Mongo/MongoCollection.js +212 -0
  59. package/lib/Adapters/Storage/Mongo/MongoSchemaCollection.js +334 -0
  60. package/lib/Adapters/Storage/Mongo/MongoStorageAdapter.js +1047 -0
  61. package/lib/Adapters/Storage/Mongo/MongoTransform.js +1397 -0
  62. package/lib/Adapters/Storage/Postgres/PostgresClient.js +38 -0
  63. package/lib/Adapters/Storage/Postgres/PostgresConfigParser.js +73 -0
  64. package/lib/Adapters/Storage/Postgres/PostgresStorageAdapter.js +2409 -0
  65. package/lib/Adapters/Storage/Postgres/sql/array/add-unique.sql +11 -0
  66. package/lib/Adapters/Storage/Postgres/sql/array/add.sql +11 -0
  67. package/lib/Adapters/Storage/Postgres/sql/array/contains-all-regex.sql +14 -0
  68. package/lib/Adapters/Storage/Postgres/sql/array/contains-all.sql +14 -0
  69. package/lib/Adapters/Storage/Postgres/sql/array/contains.sql +11 -0
  70. package/lib/Adapters/Storage/Postgres/sql/array/remove.sql +11 -0
  71. package/lib/Adapters/Storage/Postgres/sql/index.js +32 -0
  72. package/lib/Adapters/Storage/Postgres/sql/misc/json-object-set-keys.sql +19 -0
  73. package/lib/Adapters/Storage/StorageAdapter.js +2 -0
  74. package/lib/Adapters/WebSocketServer/WSAdapter.js +35 -0
  75. package/lib/Adapters/WebSocketServer/WSSAdapter.js +66 -0
  76. package/lib/Auth.js +687 -0
  77. package/lib/AuthDataLock.js +53 -0
  78. package/lib/ClientSDK.js +39 -0
  79. package/lib/Config.js +879 -0
  80. package/lib/Controllers/AdaptableController.js +72 -0
  81. package/lib/Controllers/AnalyticsController.js +43 -0
  82. package/lib/Controllers/CacheController.js +71 -0
  83. package/lib/Controllers/DatabaseController.js +1685 -0
  84. package/lib/Controllers/FilesController.js +122 -0
  85. package/lib/Controllers/HooksController.js +254 -0
  86. package/lib/Controllers/LiveQueryController.js +72 -0
  87. package/lib/Controllers/LoggerController.js +222 -0
  88. package/lib/Controllers/ParseGraphQLController.js +294 -0
  89. package/lib/Controllers/PushController.js +224 -0
  90. package/lib/Controllers/SchemaController.js +1563 -0
  91. package/lib/Controllers/UserController.js +364 -0
  92. package/lib/Controllers/index.js +251 -0
  93. package/lib/Controllers/types.js +2 -0
  94. package/lib/Deprecator/Deprecations.js +100 -0
  95. package/lib/Deprecator/Deprecator.js +140 -0
  96. package/lib/Error.js +50 -0
  97. package/lib/FileUrlValidator.js +69 -0
  98. package/lib/GraphQL/ParseGraphQLSchema.js +375 -0
  99. package/lib/GraphQL/ParseGraphQLServer.js +241 -0
  100. package/lib/GraphQL/helpers/objectsMutations.js +30 -0
  101. package/lib/GraphQL/helpers/objectsQueries.js +246 -0
  102. package/lib/GraphQL/helpers/queryComplexity.js +138 -0
  103. package/lib/GraphQL/loaders/configMutations.js +87 -0
  104. package/lib/GraphQL/loaders/configQueries.js +79 -0
  105. package/lib/GraphQL/loaders/defaultGraphQLMutations.js +21 -0
  106. package/lib/GraphQL/loaders/defaultGraphQLQueries.js +23 -0
  107. package/lib/GraphQL/loaders/defaultGraphQLTypes.js +1099 -0
  108. package/lib/GraphQL/loaders/defaultRelaySchema.js +53 -0
  109. package/lib/GraphQL/loaders/filesMutations.js +107 -0
  110. package/lib/GraphQL/loaders/functionsMutations.js +77 -0
  111. package/lib/GraphQL/loaders/parseClassMutations.js +267 -0
  112. package/lib/GraphQL/loaders/parseClassQueries.js +126 -0
  113. package/lib/GraphQL/loaders/parseClassTypes.js +493 -0
  114. package/lib/GraphQL/loaders/schemaDirectives.js +62 -0
  115. package/lib/GraphQL/loaders/schemaMutations.js +161 -0
  116. package/lib/GraphQL/loaders/schemaQueries.js +80 -0
  117. package/lib/GraphQL/loaders/schemaTypes.js +341 -0
  118. package/lib/GraphQL/loaders/usersMutations.js +433 -0
  119. package/lib/GraphQL/loaders/usersQueries.js +90 -0
  120. package/lib/GraphQL/parseGraphQLUtils.js +71 -0
  121. package/lib/GraphQL/transformers/className.js +14 -0
  122. package/lib/GraphQL/transformers/constraintType.js +53 -0
  123. package/lib/GraphQL/transformers/inputType.js +51 -0
  124. package/lib/GraphQL/transformers/mutation.js +280 -0
  125. package/lib/GraphQL/transformers/outputType.js +51 -0
  126. package/lib/GraphQL/transformers/query.js +237 -0
  127. package/lib/GraphQL/transformers/schemaFields.js +99 -0
  128. package/lib/InstallationDedup.js +178 -0
  129. package/lib/KeyPromiseQueue.js +48 -0
  130. package/lib/LiveQuery/Client.js +90 -0
  131. package/lib/LiveQuery/Id.js +20 -0
  132. package/lib/LiveQuery/ParseCloudCodePublisher.js +54 -0
  133. package/lib/LiveQuery/ParseLiveQueryServer.js +1071 -0
  134. package/lib/LiveQuery/ParsePubSub.js +37 -0
  135. package/lib/LiveQuery/ParseWebSocketServer.js +66 -0
  136. package/lib/LiveQuery/QueryTools.js +443 -0
  137. package/lib/LiveQuery/RequestSchema.js +161 -0
  138. package/lib/LiveQuery/SessionTokenCache.js +51 -0
  139. package/lib/LiveQuery/Subscription.js +47 -0
  140. package/lib/LiveQuery/equalObjects.js +50 -0
  141. package/lib/Options/Definitions.js +1599 -0
  142. package/lib/Options/docs.js +389 -0
  143. package/lib/Options/index.js +12 -0
  144. package/lib/Options/parsers.js +89 -0
  145. package/lib/Page.js +44 -0
  146. package/lib/ParseMessageQueue.js +24 -0
  147. package/lib/ParseServer.js +632 -0
  148. package/lib/ParseServerRESTController.js +173 -0
  149. package/lib/PromiseRouter.js +208 -0
  150. package/lib/Push/PushQueue.js +67 -0
  151. package/lib/Push/PushWorker.js +101 -0
  152. package/lib/Push/utils.js +129 -0
  153. package/lib/RestQuery.js +1208 -0
  154. package/lib/RestWrite.js +1671 -0
  155. package/lib/Routers/AggregateRouter.js +150 -0
  156. package/lib/Routers/AnalyticsRouter.js +26 -0
  157. package/lib/Routers/AudiencesRouter.js +54 -0
  158. package/lib/Routers/ClassesRouter.js +191 -0
  159. package/lib/Routers/CloudCodeRouter.js +87 -0
  160. package/lib/Routers/FeaturesRouter.js +72 -0
  161. package/lib/Routers/FilesRouter.js +772 -0
  162. package/lib/Routers/FunctionsRouter.js +341 -0
  163. package/lib/Routers/GlobalConfigRouter.js +123 -0
  164. package/lib/Routers/GraphQLRouter.js +41 -0
  165. package/lib/Routers/HooksRouter.js +121 -0
  166. package/lib/Routers/IAPValidationRouter.js +113 -0
  167. package/lib/Routers/InstallationsRouter.js +46 -0
  168. package/lib/Routers/LogsRouter.js +57 -0
  169. package/lib/Routers/PagesRouter.js +676 -0
  170. package/lib/Routers/PurgeRouter.js +45 -0
  171. package/lib/Routers/PushRouter.js +75 -0
  172. package/lib/Routers/RolesRouter.js +33 -0
  173. package/lib/Routers/SchemasRouter.js +118 -0
  174. package/lib/Routers/SecurityRouter.js +34 -0
  175. package/lib/Routers/SessionsRouter.js +126 -0
  176. package/lib/Routers/UsersRouter.js +733 -0
  177. package/lib/SchemaMigrations/DefinedSchemas.js +379 -0
  178. package/lib/SchemaMigrations/Migrations.js +30 -0
  179. package/lib/Security/Check.js +109 -0
  180. package/lib/Security/CheckGroup.js +44 -0
  181. package/lib/Security/CheckGroups/CheckGroupDatabase.js +44 -0
  182. package/lib/Security/CheckGroups/CheckGroupServerConfig.js +160 -0
  183. package/lib/Security/CheckGroups/CheckGroups.js +21 -0
  184. package/lib/Security/CheckRunner.js +213 -0
  185. package/lib/SharedRest.js +34 -0
  186. package/lib/StatusHandler.js +329 -0
  187. package/lib/TestUtils.js +87 -0
  188. package/lib/Utils.js +577 -0
  189. package/lib/batch.js +185 -0
  190. package/lib/cache.js +12 -0
  191. package/lib/cli/definitions/parse-live-query-server.js +9 -0
  192. package/lib/cli/definitions/parse-server.js +9 -0
  193. package/lib/cli/parse-live-query-server.js +14 -0
  194. package/lib/cli/parse-server.js +101 -0
  195. package/lib/cli/utils/commander.js +132 -0
  196. package/lib/cli/utils/runner.js +53 -0
  197. package/lib/cloud-code/Parse.Cloud.js +797 -0
  198. package/lib/cloud-code/Parse.Server.js +21 -0
  199. package/lib/cryptoUtils.js +54 -0
  200. package/lib/defaults.js +58 -0
  201. package/lib/deprecated.js +12 -0
  202. package/lib/index.js +89 -0
  203. package/lib/logger.js +40 -0
  204. package/lib/middlewares.js +810 -0
  205. package/lib/password.js +40 -0
  206. package/lib/request.js +175 -0
  207. package/lib/requiredParameter.js +11 -0
  208. package/lib/rest.js +264 -0
  209. package/lib/triggers.js +949 -0
  210. package/lib/vendor/README.md +8 -0
  211. package/lib/vendor/mongodbUrl.js +1012 -0
  212. package/package.json +172 -0
  213. package/postinstall.js +38 -0
  214. package/public/custom_json.html +17 -0
  215. package/public/custom_json.json +23 -0
  216. package/public/custom_page.html +15 -0
  217. package/public/de/email_verification_link_expired.html +24 -0
  218. package/public/de/email_verification_link_invalid.html +21 -0
  219. package/public/de/email_verification_send_fail.html +21 -0
  220. package/public/de/email_verification_send_success.html +19 -0
  221. package/public/de/email_verification_success.html +18 -0
  222. package/public/de/password_reset.html +65 -0
  223. package/public/de/password_reset_link_invalid.html +19 -0
  224. package/public/de/password_reset_success.html +18 -0
  225. package/public/de-AT/email_verification_link_expired.html +24 -0
  226. package/public/de-AT/email_verification_link_invalid.html +21 -0
  227. package/public/de-AT/email_verification_send_fail.html +21 -0
  228. package/public/de-AT/email_verification_send_success.html +19 -0
  229. package/public/de-AT/email_verification_success.html +18 -0
  230. package/public/de-AT/password_reset.html +65 -0
  231. package/public/de-AT/password_reset_link_invalid.html +19 -0
  232. package/public/de-AT/password_reset_success.html +18 -0
  233. package/public/email_verification_link_expired.html +24 -0
  234. package/public/email_verification_link_invalid.html +21 -0
  235. package/public/email_verification_send_fail.html +21 -0
  236. package/public/email_verification_send_success.html +19 -0
  237. package/public/email_verification_success.html +18 -0
  238. package/public/password_reset.html +65 -0
  239. package/public/password_reset_link_invalid.html +19 -0
  240. package/public/password_reset_success.html +18 -0
  241. package/types/@types/@parse/fs-files-adapter/index.d.ts +5 -0
  242. package/types/@types/deepcopy/index.d.ts +5 -0
  243. package/types/LiveQuery/ParseLiveQueryServer.d.ts +40 -0
  244. package/types/Options/index.d.ts +320 -0
  245. package/types/ParseServer.d.ts +65 -0
  246. package/types/eslint.config.mjs +30 -0
  247. package/types/index.d.ts +21 -0
  248. package/types/logger.d.ts +2 -0
  249. package/types/tests.ts +44 -0
  250. package/types/tsconfig.json +24 -0
  251. package/views/choose_password +215 -0
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Parse Server authentication adapter for Janrain Capture API.
5
+ *
6
+ * @class JanrainCapture
7
+ * @param {Object} options - The adapter configuration options.
8
+ * @param {String} options.janrain_capture_host - The Janrain Capture API host.
9
+ *
10
+ * @param {Object} authData - The authentication data provided by the client.
11
+ * @param {String} authData.id - The Janrain Capture user ID.
12
+ * @param {String} authData.access_token - The Janrain Capture access token.
13
+ *
14
+ * @description
15
+ * ## Parse Server Configuration
16
+ * To configure Parse Server for Janrain Capture authentication, use the following structure:
17
+ * ```json
18
+ * {
19
+ * "auth": {
20
+ * "janrain": {
21
+ * "janrain_capture_host": "your-janrain-capture-host"
22
+ * }
23
+ * }
24
+ * }
25
+ * ```
26
+ *
27
+ * The adapter requires the following `authData` fields:
28
+ * - `id`: The Janrain Capture user ID.
29
+ * - `access_token`: An authorized Janrain Capture access token for the user.
30
+ *
31
+ * ## Auth Payload Example
32
+ * ```json
33
+ * {
34
+ * "janrain": {
35
+ * "id": "user's Janrain Capture ID as a string",
36
+ * "access_token": "an authorized Janrain Capture access token for the user"
37
+ * }
38
+ * }
39
+ * ```
40
+ *
41
+ * ## Notes
42
+ * Parse Server validates the provided `authData` using the Janrain Capture API.
43
+ *
44
+ * @see {@link https://docs.janrain.com/api/registration/entity/#entity Janrain Capture API Documentation}
45
+ */
46
+
47
+ // Helper functions for accessing the Janrain Capture API.
48
+ var Parse = require('parse/node').Parse;
49
+ var querystring = require('querystring');
50
+ const httpsRequest = require('./httpsRequest');
51
+
52
+ // Returns a promise that fulfills iff this user id is valid.
53
+ function validateAuthData(authData, options) {
54
+ return request(options.janrain_capture_host, authData.access_token).then(data => {
55
+ //successful response will have a "stat" (status) of 'ok' and a result node that stores the uuid, because that's all we asked for
56
+ //see: https://docs.janrain.com/api/registration/entity/#entity
57
+ if (data && data.stat == 'ok' && data.result == authData.id) {
58
+ return;
59
+ }
60
+ throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Janrain capture auth is invalid for this user.');
61
+ });
62
+ }
63
+
64
+ // Returns a promise that fulfills iff this app id is valid.
65
+ function validateAppId() {
66
+ //no-op
67
+ return Promise.resolve();
68
+ }
69
+
70
+ // A promisey wrapper for api requests
71
+ function request(host, access_token) {
72
+ var query_string_data = querystring.stringify({
73
+ access_token: access_token,
74
+ attribute_name: 'uuid' // we only need to pull the uuid for this access token to make sure it matches
75
+ });
76
+ return httpsRequest.get({
77
+ host: host,
78
+ path: '/entity?' + query_string_data
79
+ });
80
+ }
81
+ module.exports = {
82
+ validateAppId: validateAppId,
83
+ validateAuthData: validateAuthData
84
+ };
85
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJQYXJzZSIsInJlcXVpcmUiLCJxdWVyeXN0cmluZyIsImh0dHBzUmVxdWVzdCIsInZhbGlkYXRlQXV0aERhdGEiLCJhdXRoRGF0YSIsIm9wdGlvbnMiLCJyZXF1ZXN0IiwiamFucmFpbl9jYXB0dXJlX2hvc3QiLCJhY2Nlc3NfdG9rZW4iLCJ0aGVuIiwiZGF0YSIsInN0YXQiLCJyZXN1bHQiLCJpZCIsIkVycm9yIiwiT0JKRUNUX05PVF9GT1VORCIsInZhbGlkYXRlQXBwSWQiLCJQcm9taXNlIiwicmVzb2x2ZSIsImhvc3QiLCJxdWVyeV9zdHJpbmdfZGF0YSIsInN0cmluZ2lmeSIsImF0dHJpYnV0ZV9uYW1lIiwiZ2V0IiwicGF0aCIsIm1vZHVsZSIsImV4cG9ydHMiXSwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvQWRhcHRlcnMvQXV0aC9qYW5yYWluY2FwdHVyZS5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFBhcnNlIFNlcnZlciBhdXRoZW50aWNhdGlvbiBhZGFwdGVyIGZvciBKYW5yYWluIENhcHR1cmUgQVBJLlxuICpcbiAqIEBjbGFzcyBKYW5yYWluQ2FwdHVyZVxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgYWRhcHRlciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gKiBAcGFyYW0ge1N0cmluZ30gb3B0aW9ucy5qYW5yYWluX2NhcHR1cmVfaG9zdCAtIFRoZSBKYW5yYWluIENhcHR1cmUgQVBJIGhvc3QuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IGF1dGhEYXRhIC0gVGhlIGF1dGhlbnRpY2F0aW9uIGRhdGEgcHJvdmlkZWQgYnkgdGhlIGNsaWVudC5cbiAqIEBwYXJhbSB7U3RyaW5nfSBhdXRoRGF0YS5pZCAtIFRoZSBKYW5yYWluIENhcHR1cmUgdXNlciBJRC5cbiAqIEBwYXJhbSB7U3RyaW5nfSBhdXRoRGF0YS5hY2Nlc3NfdG9rZW4gLSBUaGUgSmFucmFpbiBDYXB0dXJlIGFjY2VzcyB0b2tlbi5cbiAqXG4gKiBAZGVzY3JpcHRpb25cbiAqICMjIFBhcnNlIFNlcnZlciBDb25maWd1cmF0aW9uXG4gKiBUbyBjb25maWd1cmUgUGFyc2UgU2VydmVyIGZvciBKYW5yYWluIENhcHR1cmUgYXV0aGVudGljYXRpb24sIHVzZSB0aGUgZm9sbG93aW5nIHN0cnVjdHVyZTpcbiAqIGBgYGpzb25cbiAqIHtcbiAqICAgXCJhdXRoXCI6IHtcbiAqICAgICBcImphbnJhaW5cIjoge1xuICogICAgICAgXCJqYW5yYWluX2NhcHR1cmVfaG9zdFwiOiBcInlvdXItamFucmFpbi1jYXB0dXJlLWhvc3RcIlxuICogICAgIH1cbiAqICAgfVxuICogfVxuICogYGBgXG4gKlxuICogVGhlIGFkYXB0ZXIgcmVxdWlyZXMgdGhlIGZvbGxvd2luZyBgYXV0aERhdGFgIGZpZWxkczpcbiAqIC0gYGlkYDogVGhlIEphbnJhaW4gQ2FwdHVyZSB1c2VyIElELlxuICogLSBgYWNjZXNzX3Rva2VuYDogQW4gYXV0aG9yaXplZCBKYW5yYWluIENhcHR1cmUgYWNjZXNzIHRva2VuIGZvciB0aGUgdXNlci5cbiAqXG4gKiAjIyBBdXRoIFBheWxvYWQgRXhhbXBsZVxuICogYGBganNvblxuICoge1xuICogICBcImphbnJhaW5cIjoge1xuICogICAgIFwiaWRcIjogXCJ1c2VyJ3MgSmFucmFpbiBDYXB0dXJlIElEIGFzIGEgc3RyaW5nXCIsXG4gKiAgICAgXCJhY2Nlc3NfdG9rZW5cIjogXCJhbiBhdXRob3JpemVkIEphbnJhaW4gQ2FwdHVyZSBhY2Nlc3MgdG9rZW4gZm9yIHRoZSB1c2VyXCJcbiAqICAgfVxuICogfVxuICogYGBgXG4gKlxuICogIyMgTm90ZXNcbiAqIFBhcnNlIFNlcnZlciB2YWxpZGF0ZXMgdGhlIHByb3ZpZGVkIGBhdXRoRGF0YWAgdXNpbmcgdGhlIEphbnJhaW4gQ2FwdHVyZSBBUEkuXG4gKlxuICogQHNlZSB7QGxpbmsgaHR0cHM6Ly9kb2NzLmphbnJhaW4uY29tL2FwaS9yZWdpc3RyYXRpb24vZW50aXR5LyNlbnRpdHkgSmFucmFpbiBDYXB0dXJlIEFQSSBEb2N1bWVudGF0aW9ufVxuICovXG5cblxuLy8gSGVscGVyIGZ1bmN0aW9ucyBmb3IgYWNjZXNzaW5nIHRoZSBKYW5yYWluIENhcHR1cmUgQVBJLlxudmFyIFBhcnNlID0gcmVxdWlyZSgncGFyc2Uvbm9kZScpLlBhcnNlO1xudmFyIHF1ZXJ5c3RyaW5nID0gcmVxdWlyZSgncXVlcnlzdHJpbmcnKTtcbmNvbnN0IGh0dHBzUmVxdWVzdCA9IHJlcXVpcmUoJy4vaHR0cHNSZXF1ZXN0Jyk7XG5cbi8vIFJldHVybnMgYSBwcm9taXNlIHRoYXQgZnVsZmlsbHMgaWZmIHRoaXMgdXNlciBpZCBpcyB2YWxpZC5cbmZ1bmN0aW9uIHZhbGlkYXRlQXV0aERhdGEoYXV0aERhdGEsIG9wdGlvbnMpIHtcbiAgcmV0dXJuIHJlcXVlc3Qob3B0aW9ucy5qYW5yYWluX2NhcHR1cmVfaG9zdCwgYXV0aERhdGEuYWNjZXNzX3Rva2VuKS50aGVuKGRhdGEgPT4ge1xuICAgIC8vc3VjY2Vzc2Z1bCByZXNwb25zZSB3aWxsIGhhdmUgYSBcInN0YXRcIiAoc3RhdHVzKSBvZiAnb2snIGFuZCBhIHJlc3VsdCBub2RlIHRoYXQgc3RvcmVzIHRoZSB1dWlkLCBiZWNhdXNlIHRoYXQncyBhbGwgd2UgYXNrZWQgZm9yXG4gICAgLy9zZWU6IGh0dHBzOi8vZG9jcy5qYW5yYWluLmNvbS9hcGkvcmVnaXN0cmF0aW9uL2VudGl0eS8jZW50aXR5XG4gICAgaWYgKGRhdGEgJiYgZGF0YS5zdGF0ID09ICdvaycgJiYgZGF0YS5yZXN1bHQgPT0gYXV0aERhdGEuaWQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhyb3cgbmV3IFBhcnNlLkVycm9yKFxuICAgICAgUGFyc2UuRXJyb3IuT0JKRUNUX05PVF9GT1VORCxcbiAgICAgICdKYW5yYWluIGNhcHR1cmUgYXV0aCBpcyBpbnZhbGlkIGZvciB0aGlzIHVzZXIuJ1xuICAgICk7XG4gIH0pO1xufVxuXG4vLyBSZXR1cm5zIGEgcHJvbWlzZSB0aGF0IGZ1bGZpbGxzIGlmZiB0aGlzIGFwcCBpZCBpcyB2YWxpZC5cbmZ1bmN0aW9uIHZhbGlkYXRlQXBwSWQoKSB7XG4gIC8vbm8tb3BcbiAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpO1xufVxuXG4vLyBBIHByb21pc2V5IHdyYXBwZXIgZm9yIGFwaSByZXF1ZXN0c1xuZnVuY3Rpb24gcmVxdWVzdChob3N0LCBhY2Nlc3NfdG9rZW4pIHtcbiAgdmFyIHF1ZXJ5X3N0cmluZ19kYXRhID0gcXVlcnlzdHJpbmcuc3RyaW5naWZ5KHtcbiAgICBhY2Nlc3NfdG9rZW46IGFjY2Vzc190b2tlbixcbiAgICBhdHRyaWJ1dGVfbmFtZTogJ3V1aWQnLCAvLyB3ZSBvbmx5IG5lZWQgdG8gcHVsbCB0aGUgdXVpZCBmb3IgdGhpcyBhY2Nlc3MgdG9rZW4gdG8gbWFrZSBzdXJlIGl0IG1hdGNoZXNcbiAgfSk7XG5cbiAgcmV0dXJuIGh0dHBzUmVxdWVzdC5nZXQoeyBob3N0OiBob3N0LCBwYXRoOiAnL2VudGl0eT8nICsgcXVlcnlfc3RyaW5nX2RhdGEgfSk7XG59XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICB2YWxpZGF0ZUFwcElkOiB2YWxpZGF0ZUFwcElkLFxuICB2YWxpZGF0ZUF1dGhEYXRhOiB2YWxpZGF0ZUF1dGhEYXRhLFxufTtcbiJdLCJtYXBwaW5ncyI6Ijs7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFHQTtBQUNBLElBQUlBLEtBQUssR0FBR0MsT0FBTyxDQUFDLFlBQVksQ0FBQyxDQUFDRCxLQUFLO0FBQ3ZDLElBQUlFLFdBQVcsR0FBR0QsT0FBTyxDQUFDLGFBQWEsQ0FBQztBQUN4QyxNQUFNRSxZQUFZLEdBQUdGLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQzs7QUFFOUM7QUFDQSxTQUFTRyxnQkFBZ0JBLENBQUNDLFFBQVEsRUFBRUMsT0FBTyxFQUFFO0VBQzNDLE9BQU9DLE9BQU8sQ0FBQ0QsT0FBTyxDQUFDRSxvQkFBb0IsRUFBRUgsUUFBUSxDQUFDSSxZQUFZLENBQUMsQ0FBQ0MsSUFBSSxDQUFDQyxJQUFJLElBQUk7SUFDL0U7SUFDQTtJQUNBLElBQUlBLElBQUksSUFBSUEsSUFBSSxDQUFDQyxJQUFJLElBQUksSUFBSSxJQUFJRCxJQUFJLENBQUNFLE1BQU0sSUFBSVIsUUFBUSxDQUFDUyxFQUFFLEVBQUU7TUFDM0Q7SUFDRjtJQUNBLE1BQU0sSUFBSWQsS0FBSyxDQUFDZSxLQUFLLENBQ25CZixLQUFLLENBQUNlLEtBQUssQ0FBQ0MsZ0JBQWdCLEVBQzVCLGdEQUNGLENBQUM7RUFDSCxDQUFDLENBQUM7QUFDSjs7QUFFQTtBQUNBLFNBQVNDLGFBQWFBLENBQUEsRUFBRztFQUN2QjtFQUNBLE9BQU9DLE9BQU8sQ0FBQ0MsT0FBTyxDQUFDLENBQUM7QUFDMUI7O0FBRUE7QUFDQSxTQUFTWixPQUFPQSxDQUFDYSxJQUFJLEVBQUVYLFlBQVksRUFBRTtFQUNuQyxJQUFJWSxpQkFBaUIsR0FBR25CLFdBQVcsQ0FBQ29CLFNBQVMsQ0FBQztJQUM1Q2IsWUFBWSxFQUFFQSxZQUFZO0lBQzFCYyxjQUFjLEVBQUUsTUFBTSxDQUFFO0VBQzFCLENBQUMsQ0FBQztFQUVGLE9BQU9wQixZQUFZLENBQUNxQixHQUFHLENBQUM7SUFBRUosSUFBSSxFQUFFQSxJQUFJO0lBQUVLLElBQUksRUFBRSxVQUFVLEdBQUdKO0VBQWtCLENBQUMsQ0FBQztBQUMvRTtBQUVBSyxNQUFNLENBQUNDLE9BQU8sR0FBRztFQUNmVixhQUFhLEVBQUVBLGFBQWE7RUFDNUJiLGdCQUFnQixFQUFFQTtBQUNwQixDQUFDIiwiaWdub3JlTGlzdCI6W119
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+
3
+ var _Config = _interopRequireDefault(require("../../Config"));
4
+ var _Deprecator = _interopRequireDefault(require("../../Deprecator/Deprecator"));
5
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
6
+ // Helper functions for accessing the Janrain Engage API.
7
+ var httpsRequest = require('./httpsRequest');
8
+ var Parse = require('parse/node').Parse;
9
+ var querystring = require('querystring');
10
+ // Returns a promise that fulfills iff this user id is valid.
11
+ function validateAuthData(authData, options) {
12
+ const config = _Config.default.get(Parse.applicationId);
13
+ _Deprecator.default.logRuntimeDeprecation({
14
+ usage: 'janrainengage adapter'
15
+ });
16
+ if (!config?.auth?.janrainengage?.enableInsecureAuth || !config.enableInsecureAuthAdapters) {
17
+ throw new Parse.Error(Parse.Error.INTERNAL_SERVER_ERROR, 'janrainengage adapter only works with enableInsecureAuth: true');
18
+ }
19
+ return apiRequest(options.api_key, authData.auth_token).then(data => {
20
+ //successful response will have a "stat" (status) of 'ok' and a profile node with an identifier
21
+ //see: http://developers.janrain.com/overview/social-login/identity-providers/user-profile-data/#normalized-user-profile-data
22
+ if (data && data.stat == 'ok' && data.profile.identifier == authData.id) {
23
+ return;
24
+ }
25
+ throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Janrain engage auth is invalid for this user.');
26
+ });
27
+ }
28
+
29
+ // Returns a promise that fulfills iff this app id is valid.
30
+ function validateAppId() {
31
+ //no-op
32
+ return Promise.resolve();
33
+ }
34
+
35
+ // A promisey wrapper for api requests
36
+ function apiRequest(api_key, auth_token) {
37
+ var post_data = querystring.stringify({
38
+ token: auth_token,
39
+ apiKey: api_key,
40
+ format: 'json'
41
+ });
42
+ var post_options = {
43
+ host: 'rpxnow.com',
44
+ path: '/api/v2/auth_info',
45
+ method: 'POST',
46
+ headers: {
47
+ 'Content-Type': 'application/x-www-form-urlencoded',
48
+ 'Content-Length': post_data.length
49
+ }
50
+ };
51
+ return httpsRequest.request(post_options, post_data);
52
+ }
53
+ module.exports = {
54
+ validateAppId: validateAppId,
55
+ validateAuthData: validateAuthData
56
+ };
57
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfQ29uZmlnIiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfRGVwcmVjYXRvciIsImUiLCJfX2VzTW9kdWxlIiwiZGVmYXVsdCIsImh0dHBzUmVxdWVzdCIsIlBhcnNlIiwicXVlcnlzdHJpbmciLCJ2YWxpZGF0ZUF1dGhEYXRhIiwiYXV0aERhdGEiLCJvcHRpb25zIiwiY29uZmlnIiwiQ29uZmlnIiwiZ2V0IiwiYXBwbGljYXRpb25JZCIsIkRlcHJlY2F0b3IiLCJsb2dSdW50aW1lRGVwcmVjYXRpb24iLCJ1c2FnZSIsImF1dGgiLCJqYW5yYWluZW5nYWdlIiwiZW5hYmxlSW5zZWN1cmVBdXRoIiwiZW5hYmxlSW5zZWN1cmVBdXRoQWRhcHRlcnMiLCJFcnJvciIsIklOVEVSTkFMX1NFUlZFUl9FUlJPUiIsImFwaVJlcXVlc3QiLCJhcGlfa2V5IiwiYXV0aF90b2tlbiIsInRoZW4iLCJkYXRhIiwic3RhdCIsInByb2ZpbGUiLCJpZGVudGlmaWVyIiwiaWQiLCJPQkpFQ1RfTk9UX0ZPVU5EIiwidmFsaWRhdGVBcHBJZCIsIlByb21pc2UiLCJyZXNvbHZlIiwicG9zdF9kYXRhIiwic3RyaW5naWZ5IiwidG9rZW4iLCJhcGlLZXkiLCJmb3JtYXQiLCJwb3N0X29wdGlvbnMiLCJob3N0IiwicGF0aCIsIm1ldGhvZCIsImhlYWRlcnMiLCJsZW5ndGgiLCJyZXF1ZXN0IiwibW9kdWxlIiwiZXhwb3J0cyJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9BZGFwdGVycy9BdXRoL2phbnJhaW5lbmdhZ2UuanMiXSwic291cmNlc0NvbnRlbnQiOlsiLy8gSGVscGVyIGZ1bmN0aW9ucyBmb3IgYWNjZXNzaW5nIHRoZSBKYW5yYWluIEVuZ2FnZSBBUEkuXG52YXIgaHR0cHNSZXF1ZXN0ID0gcmVxdWlyZSgnLi9odHRwc1JlcXVlc3QnKTtcbnZhciBQYXJzZSA9IHJlcXVpcmUoJ3BhcnNlL25vZGUnKS5QYXJzZTtcbnZhciBxdWVyeXN0cmluZyA9IHJlcXVpcmUoJ3F1ZXJ5c3RyaW5nJyk7XG5pbXBvcnQgQ29uZmlnIGZyb20gJy4uLy4uL0NvbmZpZyc7XG5pbXBvcnQgRGVwcmVjYXRvciBmcm9tICcuLi8uLi9EZXByZWNhdG9yL0RlcHJlY2F0b3InO1xuXG4vLyBSZXR1cm5zIGEgcHJvbWlzZSB0aGF0IGZ1bGZpbGxzIGlmZiB0aGlzIHVzZXIgaWQgaXMgdmFsaWQuXG5mdW5jdGlvbiB2YWxpZGF0ZUF1dGhEYXRhKGF1dGhEYXRhLCBvcHRpb25zKSB7XG4gIGNvbnN0IGNvbmZpZyA9IENvbmZpZy5nZXQoUGFyc2UuYXBwbGljYXRpb25JZCk7XG5cbiAgRGVwcmVjYXRvci5sb2dSdW50aW1lRGVwcmVjYXRpb24oeyB1c2FnZTogJ2phbnJhaW5lbmdhZ2UgYWRhcHRlcicgfSk7XG4gIGlmICghY29uZmlnPy5hdXRoPy5qYW5yYWluZW5nYWdlPy5lbmFibGVJbnNlY3VyZUF1dGggfHwgIWNvbmZpZy5lbmFibGVJbnNlY3VyZUF1dGhBZGFwdGVycykge1xuICAgIHRocm93IG5ldyBQYXJzZS5FcnJvcihQYXJzZS5FcnJvci5JTlRFUk5BTF9TRVJWRVJfRVJST1IsICdqYW5yYWluZW5nYWdlIGFkYXB0ZXIgb25seSB3b3JrcyB3aXRoIGVuYWJsZUluc2VjdXJlQXV0aDogdHJ1ZScpO1xuICB9XG5cbiAgcmV0dXJuIGFwaVJlcXVlc3Qob3B0aW9ucy5hcGlfa2V5LCBhdXRoRGF0YS5hdXRoX3Rva2VuKS50aGVuKGRhdGEgPT4ge1xuICAgIC8vc3VjY2Vzc2Z1bCByZXNwb25zZSB3aWxsIGhhdmUgYSBcInN0YXRcIiAoc3RhdHVzKSBvZiAnb2snIGFuZCBhIHByb2ZpbGUgbm9kZSB3aXRoIGFuIGlkZW50aWZpZXJcbiAgICAvL3NlZTogaHR0cDovL2RldmVsb3BlcnMuamFucmFpbi5jb20vb3ZlcnZpZXcvc29jaWFsLWxvZ2luL2lkZW50aXR5LXByb3ZpZGVycy91c2VyLXByb2ZpbGUtZGF0YS8jbm9ybWFsaXplZC11c2VyLXByb2ZpbGUtZGF0YVxuICAgIGlmIChkYXRhICYmIGRhdGEuc3RhdCA9PSAnb2snICYmIGRhdGEucHJvZmlsZS5pZGVudGlmaWVyID09IGF1dGhEYXRhLmlkKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHRocm93IG5ldyBQYXJzZS5FcnJvcihcbiAgICAgIFBhcnNlLkVycm9yLk9CSkVDVF9OT1RfRk9VTkQsXG4gICAgICAnSmFucmFpbiBlbmdhZ2UgYXV0aCBpcyBpbnZhbGlkIGZvciB0aGlzIHVzZXIuJ1xuICAgICk7XG4gIH0pO1xufVxuXG4vLyBSZXR1cm5zIGEgcHJvbWlzZSB0aGF0IGZ1bGZpbGxzIGlmZiB0aGlzIGFwcCBpZCBpcyB2YWxpZC5cbmZ1bmN0aW9uIHZhbGlkYXRlQXBwSWQoKSB7XG4gIC8vbm8tb3BcbiAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpO1xufVxuXG4vLyBBIHByb21pc2V5IHdyYXBwZXIgZm9yIGFwaSByZXF1ZXN0c1xuZnVuY3Rpb24gYXBpUmVxdWVzdChhcGlfa2V5LCBhdXRoX3Rva2VuKSB7XG4gIHZhciBwb3N0X2RhdGEgPSBxdWVyeXN0cmluZy5zdHJpbmdpZnkoe1xuICAgIHRva2VuOiBhdXRoX3Rva2VuLFxuICAgIGFwaUtleTogYXBpX2tleSxcbiAgICBmb3JtYXQ6ICdqc29uJyxcbiAgfSk7XG5cbiAgdmFyIHBvc3Rfb3B0aW9ucyA9IHtcbiAgICBob3N0OiAncnB4bm93LmNvbScsXG4gICAgcGF0aDogJy9hcGkvdjIvYXV0aF9pbmZvJyxcbiAgICBtZXRob2Q6ICdQT1NUJyxcbiAgICBoZWFkZXJzOiB7XG4gICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCcsXG4gICAgICAnQ29udGVudC1MZW5ndGgnOiBwb3N0X2RhdGEubGVuZ3RoLFxuICAgIH0sXG4gIH07XG5cbiAgcmV0dXJuIGh0dHBzUmVxdWVzdC5yZXF1ZXN0KHBvc3Rfb3B0aW9ucywgcG9zdF9kYXRhKTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gIHZhbGlkYXRlQXBwSWQ6IHZhbGlkYXRlQXBwSWQsXG4gIHZhbGlkYXRlQXV0aERhdGE6IHZhbGlkYXRlQXV0aERhdGEsXG59O1xuIl0sIm1hcHBpbmdzIjoiOztBQUlBLElBQUFBLE9BQUEsR0FBQUMsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFDLFdBQUEsR0FBQUYsc0JBQUEsQ0FBQUMsT0FBQTtBQUFxRCxTQUFBRCx1QkFBQUcsQ0FBQSxXQUFBQSxDQUFBLElBQUFBLENBQUEsQ0FBQUMsVUFBQSxHQUFBRCxDQUFBLEtBQUFFLE9BQUEsRUFBQUYsQ0FBQTtBQUxyRDtBQUNBLElBQUlHLFlBQVksR0FBR0wsT0FBTyxDQUFDLGdCQUFnQixDQUFDO0FBQzVDLElBQUlNLEtBQUssR0FBR04sT0FBTyxDQUFDLFlBQVksQ0FBQyxDQUFDTSxLQUFLO0FBQ3ZDLElBQUlDLFdBQVcsR0FBR1AsT0FBTyxDQUFDLGFBQWEsQ0FBQztBQUl4QztBQUNBLFNBQVNRLGdCQUFnQkEsQ0FBQ0MsUUFBUSxFQUFFQyxPQUFPLEVBQUU7RUFDM0MsTUFBTUMsTUFBTSxHQUFHQyxlQUFNLENBQUNDLEdBQUcsQ0FBQ1AsS0FBSyxDQUFDUSxhQUFhLENBQUM7RUFFOUNDLG1CQUFVLENBQUNDLHFCQUFxQixDQUFDO0lBQUVDLEtBQUssRUFBRTtFQUF3QixDQUFDLENBQUM7RUFDcEUsSUFBSSxDQUFDTixNQUFNLEVBQUVPLElBQUksRUFBRUMsYUFBYSxFQUFFQyxrQkFBa0IsSUFBSSxDQUFDVCxNQUFNLENBQUNVLDBCQUEwQixFQUFFO0lBQzFGLE1BQU0sSUFBSWYsS0FBSyxDQUFDZ0IsS0FBSyxDQUFDaEIsS0FBSyxDQUFDZ0IsS0FBSyxDQUFDQyxxQkFBcUIsRUFBRSxnRUFBZ0UsQ0FBQztFQUM1SDtFQUVBLE9BQU9DLFVBQVUsQ0FBQ2QsT0FBTyxDQUFDZSxPQUFPLEVBQUVoQixRQUFRLENBQUNpQixVQUFVLENBQUMsQ0FBQ0MsSUFBSSxDQUFDQyxJQUFJLElBQUk7SUFDbkU7SUFDQTtJQUNBLElBQUlBLElBQUksSUFBSUEsSUFBSSxDQUFDQyxJQUFJLElBQUksSUFBSSxJQUFJRCxJQUFJLENBQUNFLE9BQU8sQ0FBQ0MsVUFBVSxJQUFJdEIsUUFBUSxDQUFDdUIsRUFBRSxFQUFFO01BQ3ZFO0lBQ0Y7SUFDQSxNQUFNLElBQUkxQixLQUFLLENBQUNnQixLQUFLLENBQ25CaEIsS0FBSyxDQUFDZ0IsS0FBSyxDQUFDVyxnQkFBZ0IsRUFDNUIsK0NBQ0YsQ0FBQztFQUNILENBQUMsQ0FBQztBQUNKOztBQUVBO0FBQ0EsU0FBU0MsYUFBYUEsQ0FBQSxFQUFHO0VBQ3ZCO0VBQ0EsT0FBT0MsT0FBTyxDQUFDQyxPQUFPLENBQUMsQ0FBQztBQUMxQjs7QUFFQTtBQUNBLFNBQVNaLFVBQVVBLENBQUNDLE9BQU8sRUFBRUMsVUFBVSxFQUFFO0VBQ3ZDLElBQUlXLFNBQVMsR0FBRzlCLFdBQVcsQ0FBQytCLFNBQVMsQ0FBQztJQUNwQ0MsS0FBSyxFQUFFYixVQUFVO0lBQ2pCYyxNQUFNLEVBQUVmLE9BQU87SUFDZmdCLE1BQU0sRUFBRTtFQUNWLENBQUMsQ0FBQztFQUVGLElBQUlDLFlBQVksR0FBRztJQUNqQkMsSUFBSSxFQUFFLFlBQVk7SUFDbEJDLElBQUksRUFBRSxtQkFBbUI7SUFDekJDLE1BQU0sRUFBRSxNQUFNO0lBQ2RDLE9BQU8sRUFBRTtNQUNQLGNBQWMsRUFBRSxtQ0FBbUM7TUFDbkQsZ0JBQWdCLEVBQUVULFNBQVMsQ0FBQ1U7SUFDOUI7RUFDRixDQUFDO0VBRUQsT0FBTzFDLFlBQVksQ0FBQzJDLE9BQU8sQ0FBQ04sWUFBWSxFQUFFTCxTQUFTLENBQUM7QUFDdEQ7QUFFQVksTUFBTSxDQUFDQyxPQUFPLEdBQUc7RUFDZmhCLGFBQWEsRUFBRUEsYUFBYTtFQUM1QjFCLGdCQUFnQixFQUFFQTtBQUNwQixDQUFDIiwiaWdub3JlTGlzdCI6W119
@@ -0,0 +1,168 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Parse Server authentication adapter for Keycloak.
5
+ *
6
+ * @class KeycloakAdapter
7
+ * @param {Object} options - The adapter configuration options.
8
+ * @param {Object} options.config - The Keycloak configuration object, typically loaded from a JSON file.
9
+ * @param {String} options.config.auth-server-url - The Keycloak authentication server URL.
10
+ * @param {String} options.config.realm - The Keycloak realm name.
11
+ * @param {String} options.config.client-id - The Keycloak client ID.
12
+ *
13
+ * @param {Object} authData - The authentication data provided by the client.
14
+ * @param {String} authData.access_token - The Keycloak access token retrieved during client authentication.
15
+ * @param {String} authData.id - The user ID retrieved from Keycloak during client authentication.
16
+ * @param {Array} [authData.roles] - The roles assigned to the user in Keycloak (optional).
17
+ * @param {Array} [authData.groups] - The groups assigned to the user in Keycloak (optional).
18
+ *
19
+ * @description
20
+ * ## Parse Server Configuration
21
+ * To configure Parse Server for Keycloak authentication, use the following structure:
22
+ * ```javascript
23
+ * {
24
+ * "auth": {
25
+ * "keycloak": {
26
+ * "config": require('./auth/keycloak.json')
27
+ * }
28
+ * }
29
+ * }
30
+ * ```
31
+ * Ensure the `keycloak.json` configuration file is generated from Keycloak's setup guide and includes:
32
+ * - `auth-server-url`: The Keycloak authentication server URL.
33
+ * - `realm`: The Keycloak realm name.
34
+ * - `client-id`: The Keycloak client ID.
35
+ *
36
+ * ## Auth Data
37
+ * The adapter requires the following `authData` fields:
38
+ * - `access_token`: The Keycloak access token retrieved during client authentication.
39
+ * - `id`: The user ID retrieved from Keycloak during client authentication.
40
+ * - `roles` (optional): The roles assigned to the user in Keycloak.
41
+ * - `groups` (optional): The groups assigned to the user in Keycloak.
42
+ *
43
+ * ## Auth Payload Example
44
+ * ### Example Auth Data
45
+ * ```json
46
+ * {
47
+ * "keycloak": {
48
+ * "access_token": "an authorized Keycloak access token for the user",
49
+ * "id": "user's Keycloak ID as a string",
50
+ * "roles": ["admin", "user"],
51
+ * "groups": ["group1", "group2"]
52
+ * }
53
+ * }
54
+ * ```
55
+ *
56
+ * ## Notes
57
+ * - Parse Server validates the provided `authData` by making a `userinfo` call to Keycloak and ensures the attributes match those returned by Keycloak.
58
+ *
59
+ * ## Keycloak Configuration
60
+ * To configure Keycloak, copy the JSON configuration file generated from Keycloak's setup guide:
61
+ * - [Keycloak Securing Apps Documentation](https://www.keycloak.org/docs/latest/securing_apps/index.html#_javascript_adapter)
62
+ *
63
+ * Place the configuration file on your server, for example:
64
+ * - `auth/keycloak.json`
65
+ *
66
+ * For more information on Keycloak authentication, see:
67
+ * - [Securing Apps Documentation](https://www.keycloak.org/docs/latest/securing_apps/)
68
+ * - [Server Administration Documentation](https://www.keycloak.org/docs/latest/server_admin/)
69
+ */
70
+
71
+ const {
72
+ Parse
73
+ } = require('parse/node');
74
+ const jwksClient = require('jwks-rsa');
75
+ const jwt = require('jsonwebtoken');
76
+ const authUtils = require('./utils');
77
+ const arraysEqual = (_arr1, _arr2) => {
78
+ if (!Array.isArray(_arr1) || !Array.isArray(_arr2) || _arr1.length !== _arr2.length) {
79
+ return false;
80
+ }
81
+ var arr1 = _arr1.concat().sort();
82
+ var arr2 = _arr2.concat().sort();
83
+ for (var i = 0; i < arr1.length; i++) {
84
+ if (arr1[i] !== arr2[i]) {
85
+ return false;
86
+ }
87
+ }
88
+ return true;
89
+ };
90
+ const getKeycloakKeyByKeyId = async (keyId, jwksUri, cacheMaxEntries, cacheMaxAge) => {
91
+ const client = jwksClient({
92
+ jwksUri,
93
+ cache: true,
94
+ cacheMaxEntries,
95
+ cacheMaxAge
96
+ });
97
+ let key;
98
+ try {
99
+ key = await authUtils.getSigningKey(client, keyId);
100
+ } catch {
101
+ throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, `Unable to find matching key for Key ID: ${keyId}`);
102
+ }
103
+ return key;
104
+ };
105
+ const verifyAccessToken = async ({
106
+ access_token,
107
+ id,
108
+ roles,
109
+ groups
110
+ } = {}, {
111
+ config,
112
+ cacheMaxEntries,
113
+ cacheMaxAge
114
+ } = {}) => {
115
+ if (!(access_token && id)) {
116
+ throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Missing access token and/or User id');
117
+ }
118
+ if (!config || !(config['auth-server-url'] && config['realm'])) {
119
+ throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Missing keycloak configuration');
120
+ }
121
+ if (!config['client-id']) {
122
+ throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Keycloak auth is not configured. Missing client-id.');
123
+ }
124
+ const expectedIssuer = `${config['auth-server-url']}/realms/${config['realm']}`;
125
+ const jwksUri = `${config['auth-server-url']}/realms/${config['realm']}/protocol/openid-connect/certs`;
126
+ const {
127
+ kid: keyId
128
+ } = authUtils.getHeaderFromToken(access_token);
129
+ const ONE_HOUR_IN_MS = 3600000;
130
+ cacheMaxAge = cacheMaxAge || ONE_HOUR_IN_MS;
131
+ cacheMaxEntries = cacheMaxEntries || 5;
132
+ const keycloakKey = await getKeycloakKeyByKeyId(keyId, jwksUri, cacheMaxEntries, cacheMaxAge);
133
+ const signingKey = keycloakKey.publicKey || keycloakKey.rsaPublicKey;
134
+ let jwtClaims;
135
+ try {
136
+ jwtClaims = jwt.verify(access_token, signingKey, {
137
+ algorithms: ['RS256']
138
+ });
139
+ } catch (exception) {
140
+ throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, `${exception.message}`);
141
+ }
142
+ if (jwtClaims.iss !== expectedIssuer) {
143
+ throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, `access token not issued by correct provider - expected: ${expectedIssuer} | from: ${jwtClaims.iss}`);
144
+ }
145
+ if (jwtClaims.azp !== config['client-id']) {
146
+ throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, `access token is not authorized for this client - expected: ${config['client-id']} | from: ${jwtClaims.azp}`);
147
+ }
148
+ if (jwtClaims.sub !== id) {
149
+ throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'auth data is invalid for this user.');
150
+ }
151
+ const rolesMatch = jwtClaims.roles === roles || arraysEqual(jwtClaims.roles, roles);
152
+ const groupsMatch = jwtClaims.groups === groups || arraysEqual(jwtClaims.groups, groups);
153
+ if (!rolesMatch || !groupsMatch) {
154
+ throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Invalid authentication');
155
+ }
156
+ return jwtClaims;
157
+ };
158
+ function validateAuthData(authData, options = {}) {
159
+ return verifyAccessToken(authData, options);
160
+ }
161
+ function validateAppId() {
162
+ return Promise.resolve();
163
+ }
164
+ module.exports = {
165
+ validateAppId,
166
+ validateAuthData
167
+ };
168
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJQYXJzZSIsInJlcXVpcmUiLCJqd2tzQ2xpZW50Iiwiand0IiwiYXV0aFV0aWxzIiwiYXJyYXlzRXF1YWwiLCJfYXJyMSIsIl9hcnIyIiwiQXJyYXkiLCJpc0FycmF5IiwibGVuZ3RoIiwiYXJyMSIsImNvbmNhdCIsInNvcnQiLCJhcnIyIiwiaSIsImdldEtleWNsb2FrS2V5QnlLZXlJZCIsImtleUlkIiwiandrc1VyaSIsImNhY2hlTWF4RW50cmllcyIsImNhY2hlTWF4QWdlIiwiY2xpZW50IiwiY2FjaGUiLCJrZXkiLCJnZXRTaWduaW5nS2V5IiwiRXJyb3IiLCJPQkpFQ1RfTk9UX0ZPVU5EIiwidmVyaWZ5QWNjZXNzVG9rZW4iLCJhY2Nlc3NfdG9rZW4iLCJpZCIsInJvbGVzIiwiZ3JvdXBzIiwiY29uZmlnIiwiZXhwZWN0ZWRJc3N1ZXIiLCJraWQiLCJnZXRIZWFkZXJGcm9tVG9rZW4iLCJPTkVfSE9VUl9JTl9NUyIsImtleWNsb2FrS2V5Iiwic2lnbmluZ0tleSIsInB1YmxpY0tleSIsInJzYVB1YmxpY0tleSIsImp3dENsYWltcyIsInZlcmlmeSIsImFsZ29yaXRobXMiLCJleGNlcHRpb24iLCJtZXNzYWdlIiwiaXNzIiwiYXpwIiwic3ViIiwicm9sZXNNYXRjaCIsImdyb3Vwc01hdGNoIiwidmFsaWRhdGVBdXRoRGF0YSIsImF1dGhEYXRhIiwib3B0aW9ucyIsInZhbGlkYXRlQXBwSWQiLCJQcm9taXNlIiwicmVzb2x2ZSIsIm1vZHVsZSIsImV4cG9ydHMiXSwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvQWRhcHRlcnMvQXV0aC9rZXljbG9hay5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFBhcnNlIFNlcnZlciBhdXRoZW50aWNhdGlvbiBhZGFwdGVyIGZvciBLZXljbG9hay5cbiAqXG4gKiBAY2xhc3MgS2V5Y2xvYWtBZGFwdGVyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBhZGFwdGVyIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zLmNvbmZpZyAtIFRoZSBLZXljbG9hayBjb25maWd1cmF0aW9uIG9iamVjdCwgdHlwaWNhbGx5IGxvYWRlZCBmcm9tIGEgSlNPTiBmaWxlLlxuICogQHBhcmFtIHtTdHJpbmd9IG9wdGlvbnMuY29uZmlnLmF1dGgtc2VydmVyLXVybCAtIFRoZSBLZXljbG9hayBhdXRoZW50aWNhdGlvbiBzZXJ2ZXIgVVJMLlxuICogQHBhcmFtIHtTdHJpbmd9IG9wdGlvbnMuY29uZmlnLnJlYWxtIC0gVGhlIEtleWNsb2FrIHJlYWxtIG5hbWUuXG4gKiBAcGFyYW0ge1N0cmluZ30gb3B0aW9ucy5jb25maWcuY2xpZW50LWlkIC0gVGhlIEtleWNsb2FrIGNsaWVudCBJRC5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gYXV0aERhdGEgLSBUaGUgYXV0aGVudGljYXRpb24gZGF0YSBwcm92aWRlZCBieSB0aGUgY2xpZW50LlxuICogQHBhcmFtIHtTdHJpbmd9IGF1dGhEYXRhLmFjY2Vzc190b2tlbiAtIFRoZSBLZXljbG9hayBhY2Nlc3MgdG9rZW4gcmV0cmlldmVkIGR1cmluZyBjbGllbnQgYXV0aGVudGljYXRpb24uXG4gKiBAcGFyYW0ge1N0cmluZ30gYXV0aERhdGEuaWQgLSBUaGUgdXNlciBJRCByZXRyaWV2ZWQgZnJvbSBLZXljbG9hayBkdXJpbmcgY2xpZW50IGF1dGhlbnRpY2F0aW9uLlxuICogQHBhcmFtIHtBcnJheX0gW2F1dGhEYXRhLnJvbGVzXSAtIFRoZSByb2xlcyBhc3NpZ25lZCB0byB0aGUgdXNlciBpbiBLZXljbG9hayAob3B0aW9uYWwpLlxuICogQHBhcmFtIHtBcnJheX0gW2F1dGhEYXRhLmdyb3Vwc10gLSBUaGUgZ3JvdXBzIGFzc2lnbmVkIHRvIHRoZSB1c2VyIGluIEtleWNsb2FrIChvcHRpb25hbCkuXG4gKlxuICogQGRlc2NyaXB0aW9uXG4gKiAjIyBQYXJzZSBTZXJ2ZXIgQ29uZmlndXJhdGlvblxuICogVG8gY29uZmlndXJlIFBhcnNlIFNlcnZlciBmb3IgS2V5Y2xvYWsgYXV0aGVudGljYXRpb24sIHVzZSB0aGUgZm9sbG93aW5nIHN0cnVjdHVyZTpcbiAqIGBgYGphdmFzY3JpcHRcbiAqIHtcbiAqICAgXCJhdXRoXCI6IHtcbiAqICAgICBcImtleWNsb2FrXCI6IHtcbiAqICAgICAgIFwiY29uZmlnXCI6IHJlcXVpcmUoJy4vYXV0aC9rZXljbG9hay5qc29uJylcbiAqICAgICB9XG4gKiAgIH1cbiAqIH1cbiAqIGBgYFxuICogRW5zdXJlIHRoZSBga2V5Y2xvYWsuanNvbmAgY29uZmlndXJhdGlvbiBmaWxlIGlzIGdlbmVyYXRlZCBmcm9tIEtleWNsb2FrJ3Mgc2V0dXAgZ3VpZGUgYW5kIGluY2x1ZGVzOlxuICogLSBgYXV0aC1zZXJ2ZXItdXJsYDogVGhlIEtleWNsb2FrIGF1dGhlbnRpY2F0aW9uIHNlcnZlciBVUkwuXG4gKiAtIGByZWFsbWA6IFRoZSBLZXljbG9hayByZWFsbSBuYW1lLlxuICogLSBgY2xpZW50LWlkYDogVGhlIEtleWNsb2FrIGNsaWVudCBJRC5cbiAqXG4gKiAjIyBBdXRoIERhdGFcbiAqIFRoZSBhZGFwdGVyIHJlcXVpcmVzIHRoZSBmb2xsb3dpbmcgYGF1dGhEYXRhYCBmaWVsZHM6XG4gKiAtIGBhY2Nlc3NfdG9rZW5gOiBUaGUgS2V5Y2xvYWsgYWNjZXNzIHRva2VuIHJldHJpZXZlZCBkdXJpbmcgY2xpZW50IGF1dGhlbnRpY2F0aW9uLlxuICogLSBgaWRgOiBUaGUgdXNlciBJRCByZXRyaWV2ZWQgZnJvbSBLZXljbG9hayBkdXJpbmcgY2xpZW50IGF1dGhlbnRpY2F0aW9uLlxuICogLSBgcm9sZXNgIChvcHRpb25hbCk6IFRoZSByb2xlcyBhc3NpZ25lZCB0byB0aGUgdXNlciBpbiBLZXljbG9hay5cbiAqIC0gYGdyb3Vwc2AgKG9wdGlvbmFsKTogVGhlIGdyb3VwcyBhc3NpZ25lZCB0byB0aGUgdXNlciBpbiBLZXljbG9hay5cbiAqXG4gKiAjIyBBdXRoIFBheWxvYWQgRXhhbXBsZVxuICogIyMjIEV4YW1wbGUgQXV0aCBEYXRhXG4gKiBgYGBqc29uXG4gKiB7XG4gKiAgIFwia2V5Y2xvYWtcIjoge1xuICogICAgIFwiYWNjZXNzX3Rva2VuXCI6IFwiYW4gYXV0aG9yaXplZCBLZXljbG9hayBhY2Nlc3MgdG9rZW4gZm9yIHRoZSB1c2VyXCIsXG4gKiAgICAgXCJpZFwiOiBcInVzZXIncyBLZXljbG9hayBJRCBhcyBhIHN0cmluZ1wiLFxuICogICAgIFwicm9sZXNcIjogW1wiYWRtaW5cIiwgXCJ1c2VyXCJdLFxuICogICAgIFwiZ3JvdXBzXCI6IFtcImdyb3VwMVwiLCBcImdyb3VwMlwiXVxuICogICB9XG4gKiB9XG4gKiBgYGBcbiAqXG4gKiAjIyBOb3Rlc1xuICogLSBQYXJzZSBTZXJ2ZXIgdmFsaWRhdGVzIHRoZSBwcm92aWRlZCBgYXV0aERhdGFgIGJ5IG1ha2luZyBhIGB1c2VyaW5mb2AgY2FsbCB0byBLZXljbG9hayBhbmQgZW5zdXJlcyB0aGUgYXR0cmlidXRlcyBtYXRjaCB0aG9zZSByZXR1cm5lZCBieSBLZXljbG9hay5cbiAqXG4gKiAjIyBLZXljbG9hayBDb25maWd1cmF0aW9uXG4gKiBUbyBjb25maWd1cmUgS2V5Y2xvYWssIGNvcHkgdGhlIEpTT04gY29uZmlndXJhdGlvbiBmaWxlIGdlbmVyYXRlZCBmcm9tIEtleWNsb2FrJ3Mgc2V0dXAgZ3VpZGU6XG4gKiAtIFtLZXljbG9hayBTZWN1cmluZyBBcHBzIERvY3VtZW50YXRpb25dKGh0dHBzOi8vd3d3LmtleWNsb2FrLm9yZy9kb2NzL2xhdGVzdC9zZWN1cmluZ19hcHBzL2luZGV4Lmh0bWwjX2phdmFzY3JpcHRfYWRhcHRlcilcbiAqXG4gKiBQbGFjZSB0aGUgY29uZmlndXJhdGlvbiBmaWxlIG9uIHlvdXIgc2VydmVyLCBmb3IgZXhhbXBsZTpcbiAqIC0gYGF1dGgva2V5Y2xvYWsuanNvbmBcbiAqXG4gKiBGb3IgbW9yZSBpbmZvcm1hdGlvbiBvbiBLZXljbG9hayBhdXRoZW50aWNhdGlvbiwgc2VlOlxuICogLSBbU2VjdXJpbmcgQXBwcyBEb2N1bWVudGF0aW9uXShodHRwczovL3d3dy5rZXljbG9hay5vcmcvZG9jcy9sYXRlc3Qvc2VjdXJpbmdfYXBwcy8pXG4gKiAtIFtTZXJ2ZXIgQWRtaW5pc3RyYXRpb24gRG9jdW1lbnRhdGlvbl0oaHR0cHM6Ly93d3cua2V5Y2xvYWsub3JnL2RvY3MvbGF0ZXN0L3NlcnZlcl9hZG1pbi8pXG4gKi9cblxuY29uc3QgeyBQYXJzZSB9ID0gcmVxdWlyZSgncGFyc2Uvbm9kZScpO1xuY29uc3Qgandrc0NsaWVudCA9IHJlcXVpcmUoJ2p3a3MtcnNhJyk7XG5jb25zdCBqd3QgPSByZXF1aXJlKCdqc29ud2VidG9rZW4nKTtcbmNvbnN0IGF1dGhVdGlscyA9IHJlcXVpcmUoJy4vdXRpbHMnKTtcblxuY29uc3QgYXJyYXlzRXF1YWwgPSAoX2FycjEsIF9hcnIyKSA9PiB7XG4gIGlmICghQXJyYXkuaXNBcnJheShfYXJyMSkgfHwgIUFycmF5LmlzQXJyYXkoX2FycjIpIHx8IF9hcnIxLmxlbmd0aCAhPT0gX2FycjIubGVuZ3RoKSB7IHJldHVybiBmYWxzZTsgfVxuXG4gIHZhciBhcnIxID0gX2FycjEuY29uY2F0KCkuc29ydCgpO1xuICB2YXIgYXJyMiA9IF9hcnIyLmNvbmNhdCgpLnNvcnQoKTtcblxuICBmb3IgKHZhciBpID0gMDsgaSA8IGFycjEubGVuZ3RoOyBpKyspIHtcbiAgICBpZiAoYXJyMVtpXSAhPT0gYXJyMltpXSkgeyByZXR1cm4gZmFsc2U7IH1cbiAgfVxuXG4gIHJldHVybiB0cnVlO1xufTtcblxuY29uc3QgZ2V0S2V5Y2xvYWtLZXlCeUtleUlkID0gYXN5bmMgKGtleUlkLCBqd2tzVXJpLCBjYWNoZU1heEVudHJpZXMsIGNhY2hlTWF4QWdlKSA9PiB7XG4gIGNvbnN0IGNsaWVudCA9IGp3a3NDbGllbnQoe1xuICAgIGp3a3NVcmksXG4gICAgY2FjaGU6IHRydWUsXG4gICAgY2FjaGVNYXhFbnRyaWVzLFxuICAgIGNhY2hlTWF4QWdlLFxuICB9KTtcblxuICBsZXQga2V5O1xuICB0cnkge1xuICAgIGtleSA9IGF3YWl0IGF1dGhVdGlscy5nZXRTaWduaW5nS2V5KGNsaWVudCwga2V5SWQpO1xuICB9IGNhdGNoIHtcbiAgICB0aHJvdyBuZXcgUGFyc2UuRXJyb3IoXG4gICAgICBQYXJzZS5FcnJvci5PQkpFQ1RfTk9UX0ZPVU5ELFxuICAgICAgYFVuYWJsZSB0byBmaW5kIG1hdGNoaW5nIGtleSBmb3IgS2V5IElEOiAke2tleUlkfWBcbiAgICApO1xuICB9XG4gIHJldHVybiBrZXk7XG59O1xuXG5jb25zdCB2ZXJpZnlBY2Nlc3NUb2tlbiA9IGFzeW5jIChcbiAgeyBhY2Nlc3NfdG9rZW4sIGlkLCByb2xlcywgZ3JvdXBzIH0gPSB7fSxcbiAgeyBjb25maWcsIGNhY2hlTWF4RW50cmllcywgY2FjaGVNYXhBZ2UgfSA9IHt9XG4pID0+IHtcbiAgaWYgKCEoYWNjZXNzX3Rva2VuICYmIGlkKSkge1xuICAgIHRocm93IG5ldyBQYXJzZS5FcnJvcihQYXJzZS5FcnJvci5PQkpFQ1RfTk9UX0ZPVU5ELCAnTWlzc2luZyBhY2Nlc3MgdG9rZW4gYW5kL29yIFVzZXIgaWQnKTtcbiAgfVxuICBpZiAoIWNvbmZpZyB8fCAhKGNvbmZpZ1snYXV0aC1zZXJ2ZXItdXJsJ10gJiYgY29uZmlnWydyZWFsbSddKSkge1xuICAgIHRocm93IG5ldyBQYXJzZS5FcnJvcihQYXJzZS5FcnJvci5PQkpFQ1RfTk9UX0ZPVU5ELCAnTWlzc2luZyBrZXljbG9hayBjb25maWd1cmF0aW9uJyk7XG4gIH1cbiAgaWYgKCFjb25maWdbJ2NsaWVudC1pZCddKSB7XG4gICAgdGhyb3cgbmV3IFBhcnNlLkVycm9yKFxuICAgICAgUGFyc2UuRXJyb3IuT0JKRUNUX05PVF9GT1VORCxcbiAgICAgICdLZXljbG9hayBhdXRoIGlzIG5vdCBjb25maWd1cmVkLiBNaXNzaW5nIGNsaWVudC1pZC4nXG4gICAgKTtcbiAgfVxuXG4gIGNvbnN0IGV4cGVjdGVkSXNzdWVyID0gYCR7Y29uZmlnWydhdXRoLXNlcnZlci11cmwnXX0vcmVhbG1zLyR7Y29uZmlnWydyZWFsbSddfWA7XG4gIGNvbnN0IGp3a3NVcmkgPSBgJHtjb25maWdbJ2F1dGgtc2VydmVyLXVybCddfS9yZWFsbXMvJHtjb25maWdbJ3JlYWxtJ119L3Byb3RvY29sL29wZW5pZC1jb25uZWN0L2NlcnRzYDtcblxuICBjb25zdCB7IGtpZDoga2V5SWQgfSA9IGF1dGhVdGlscy5nZXRIZWFkZXJGcm9tVG9rZW4oYWNjZXNzX3Rva2VuKTtcbiAgY29uc3QgT05FX0hPVVJfSU5fTVMgPSAzNjAwMDAwO1xuXG4gIGNhY2hlTWF4QWdlID0gY2FjaGVNYXhBZ2UgfHwgT05FX0hPVVJfSU5fTVM7XG4gIGNhY2hlTWF4RW50cmllcyA9IGNhY2hlTWF4RW50cmllcyB8fCA1O1xuXG4gIGNvbnN0IGtleWNsb2FrS2V5ID0gYXdhaXQgZ2V0S2V5Y2xvYWtLZXlCeUtleUlkKGtleUlkLCBqd2tzVXJpLCBjYWNoZU1heEVudHJpZXMsIGNhY2hlTWF4QWdlKTtcbiAgY29uc3Qgc2lnbmluZ0tleSA9IGtleWNsb2FrS2V5LnB1YmxpY0tleSB8fCBrZXljbG9ha0tleS5yc2FQdWJsaWNLZXk7XG5cbiAgbGV0IGp3dENsYWltcztcbiAgdHJ5IHtcbiAgICBqd3RDbGFpbXMgPSBqd3QudmVyaWZ5KGFjY2Vzc190b2tlbiwgc2lnbmluZ0tleSwge1xuICAgICAgYWxnb3JpdGhtczogWydSUzI1NiddLFxuICAgIH0pO1xuICB9IGNhdGNoIChleGNlcHRpb24pIHtcbiAgICB0aHJvdyBuZXcgUGFyc2UuRXJyb3IoUGFyc2UuRXJyb3IuT0JKRUNUX05PVF9GT1VORCwgYCR7ZXhjZXB0aW9uLm1lc3NhZ2V9YCk7XG4gIH1cblxuICBpZiAoand0Q2xhaW1zLmlzcyAhPT0gZXhwZWN0ZWRJc3N1ZXIpIHtcbiAgICB0aHJvdyBuZXcgUGFyc2UuRXJyb3IoXG4gICAgICBQYXJzZS5FcnJvci5PQkpFQ1RfTk9UX0ZPVU5ELFxuICAgICAgYGFjY2VzcyB0b2tlbiBub3QgaXNzdWVkIGJ5IGNvcnJlY3QgcHJvdmlkZXIgLSBleHBlY3RlZDogJHtleHBlY3RlZElzc3Vlcn0gfCBmcm9tOiAke2p3dENsYWltcy5pc3N9YFxuICAgICk7XG4gIH1cblxuICBpZiAoand0Q2xhaW1zLmF6cCAhPT0gY29uZmlnWydjbGllbnQtaWQnXSkge1xuICAgIHRocm93IG5ldyBQYXJzZS5FcnJvcihcbiAgICAgIFBhcnNlLkVycm9yLk9CSkVDVF9OT1RfRk9VTkQsXG4gICAgICBgYWNjZXNzIHRva2VuIGlzIG5vdCBhdXRob3JpemVkIGZvciB0aGlzIGNsaWVudCAtIGV4cGVjdGVkOiAke2NvbmZpZ1snY2xpZW50LWlkJ119IHwgZnJvbTogJHtqd3RDbGFpbXMuYXpwfWBcbiAgICApO1xuICB9XG5cbiAgaWYgKGp3dENsYWltcy5zdWIgIT09IGlkKSB7XG4gICAgdGhyb3cgbmV3IFBhcnNlLkVycm9yKFBhcnNlLkVycm9yLk9CSkVDVF9OT1RfRk9VTkQsICdhdXRoIGRhdGEgaXMgaW52YWxpZCBmb3IgdGhpcyB1c2VyLicpO1xuICB9XG5cbiAgY29uc3Qgcm9sZXNNYXRjaCA9IGp3dENsYWltcy5yb2xlcyA9PT0gcm9sZXMgfHwgYXJyYXlzRXF1YWwoand0Q2xhaW1zLnJvbGVzLCByb2xlcyk7XG4gIGNvbnN0IGdyb3Vwc01hdGNoID0gand0Q2xhaW1zLmdyb3VwcyA9PT0gZ3JvdXBzIHx8IGFycmF5c0VxdWFsKGp3dENsYWltcy5ncm91cHMsIGdyb3Vwcyk7XG5cbiAgaWYgKCFyb2xlc01hdGNoIHx8ICFncm91cHNNYXRjaCkge1xuICAgIHRocm93IG5ldyBQYXJzZS5FcnJvcihQYXJzZS5FcnJvci5PQkpFQ1RfTk9UX0ZPVU5ELCAnSW52YWxpZCBhdXRoZW50aWNhdGlvbicpO1xuICB9XG5cbiAgcmV0dXJuIGp3dENsYWltcztcbn07XG5cbmZ1bmN0aW9uIHZhbGlkYXRlQXV0aERhdGEoYXV0aERhdGEsIG9wdGlvbnMgPSB7fSkge1xuICByZXR1cm4gdmVyaWZ5QWNjZXNzVG9rZW4oYXV0aERhdGEsIG9wdGlvbnMpO1xufVxuXG5mdW5jdGlvbiB2YWxpZGF0ZUFwcElkKCkge1xuICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKCk7XG59XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICB2YWxpZGF0ZUFwcElkLFxuICB2YWxpZGF0ZUF1dGhEYXRhLFxufTtcbiJdLCJtYXBwaW5ncyI6Ijs7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxNQUFNO0VBQUVBO0FBQU0sQ0FBQyxHQUFHQyxPQUFPLENBQUMsWUFBWSxDQUFDO0FBQ3ZDLE1BQU1DLFVBQVUsR0FBR0QsT0FBTyxDQUFDLFVBQVUsQ0FBQztBQUN0QyxNQUFNRSxHQUFHLEdBQUdGLE9BQU8sQ0FBQyxjQUFjLENBQUM7QUFDbkMsTUFBTUcsU0FBUyxHQUFHSCxPQUFPLENBQUMsU0FBUyxDQUFDO0FBRXBDLE1BQU1JLFdBQVcsR0FBR0EsQ0FBQ0MsS0FBSyxFQUFFQyxLQUFLLEtBQUs7RUFDcEMsSUFBSSxDQUFDQyxLQUFLLENBQUNDLE9BQU8sQ0FBQ0gsS0FBSyxDQUFDLElBQUksQ0FBQ0UsS0FBSyxDQUFDQyxPQUFPLENBQUNGLEtBQUssQ0FBQyxJQUFJRCxLQUFLLENBQUNJLE1BQU0sS0FBS0gsS0FBSyxDQUFDRyxNQUFNLEVBQUU7SUFBRSxPQUFPLEtBQUs7RUFBRTtFQUVyRyxJQUFJQyxJQUFJLEdBQUdMLEtBQUss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
@@ -0,0 +1,193 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Parse Server authentication adapter for LDAP.
5
+ *
6
+ * @class LDAP
7
+ * @param {Object} options - The adapter configuration options.
8
+ * @param {String} options.url - The LDAP server URL. Must start with `ldap://` or `ldaps://`.
9
+ * @param {String} options.suffix - The LDAP suffix for user distinguished names (DN).
10
+ * @param {String} [options.dn] - The distinguished name (DN) template for user authentication. Replace `{{id}}` with the username.
11
+ * @param {Object} [options.tlsOptions] - Options for LDAPS TLS connections.
12
+ * @param {String} [options.groupCn] - The common name (CN) of the group to verify user membership.
13
+ * @param {String} [options.groupFilter] - The LDAP search filter for groups, with `{{id}}` replaced by the username.
14
+ *
15
+ * @param {Object} authData - The authentication data provided by the client.
16
+ * @param {String} authData.id - The user's LDAP username.
17
+ * @param {String} authData.password - The user's LDAP password.
18
+ *
19
+ * @description
20
+ * ## Parse Server Configuration
21
+ * To configure Parse Server for LDAP authentication, use the following structure:
22
+ * ```javascript
23
+ * {
24
+ * auth: {
25
+ * ldap: {
26
+ * url: 'ldaps://ldap.example.com',
27
+ * suffix: 'ou=users,dc=example,dc=com',
28
+ * groupCn: 'admins',
29
+ * groupFilter: '(memberUid={{id}})',
30
+ * tlsOptions: {
31
+ * rejectUnauthorized: false
32
+ * }
33
+ * }
34
+ * }
35
+ * }
36
+ * ```
37
+ *
38
+ * ## Authentication Process
39
+ * 1. Validates the provided `authData` using an LDAP bind operation.
40
+ * 2. Optionally, verifies that the user belongs to a specific group by performing an LDAP search using the provided `groupCn` or `groupFilter`.
41
+ *
42
+ * ## Auth Payload
43
+ * The adapter requires the following `authData` fields:
44
+ * - `id`: The user's LDAP username.
45
+ * - `password`: The user's LDAP password.
46
+ *
47
+ * ### Example Auth Payload
48
+ * ```json
49
+ * {
50
+ * "ldap": {
51
+ * "id": "jdoe",
52
+ * "password": "password123"
53
+ * }
54
+ * }
55
+ * ```
56
+ *
57
+ * @example <caption>Configuration Example</caption>
58
+ * // Example Parse Server configuration:
59
+ * const config = {
60
+ * auth: {
61
+ * ldap: {
62
+ * url: 'ldaps://ldap.example.com',
63
+ * suffix: 'ou=users,dc=example,dc=com',
64
+ * groupCn: 'admins',
65
+ * groupFilter: '(memberUid={{id}})',
66
+ * tlsOptions: {
67
+ * rejectUnauthorized: false
68
+ * }
69
+ * }
70
+ * }
71
+ * };
72
+ *
73
+ * @see {@link https://ldap.com/ LDAP Basics}
74
+ * @see {@link https://ldap.com/ldap-filters/ LDAP Filters}
75
+ */
76
+
77
+ const ldapjs = require('ldapjs');
78
+ const Parse = require('parse/node').Parse;
79
+
80
+ // Escape LDAP DN special characters per RFC 4514
81
+ // https://datatracker.ietf.org/doc/html/rfc4514#section-2.4
82
+ function escapeDN(value) {
83
+ let escaped = value.replace(/\\/g, '\\\\').replace(/,/g, '\\,').replace(/=/g, '\\=').replace(/\+/g, '\\+').replace(/</g, '\\<').replace(/>/g, '\\>').replace(/#/g, '\\#').replace(/;/g, '\\;').replace(/"/g, '\\"');
84
+ if (escaped.startsWith(' ')) {
85
+ escaped = '\\ ' + escaped.slice(1);
86
+ }
87
+ if (escaped.endsWith(' ')) {
88
+ escaped = escaped.slice(0, -1) + '\\ ';
89
+ }
90
+ return escaped;
91
+ }
92
+
93
+ // Escape LDAP filter special characters per RFC 4515
94
+ // https://datatracker.ietf.org/doc/html/rfc4515#section-3
95
+ function escapeFilter(value) {
96
+ // eslint-disable-next-line no-control-regex
97
+ return value.replace(/[\\*()\x00]/g, ch => '\\' + ch.charCodeAt(0).toString(16).padStart(2, '0'));
98
+ }
99
+ function validateAuthData(authData, options) {
100
+ if (!optionsAreValid(options)) {
101
+ return new Promise((_, reject) => {
102
+ reject(new Parse.Error(Parse.Error.INTERNAL_SERVER_ERROR, 'LDAP auth configuration missing'));
103
+ });
104
+ }
105
+ const clientOptions = options.url.startsWith('ldaps://') ? {
106
+ url: options.url,
107
+ tlsOptions: options.tlsOptions
108
+ } : {
109
+ url: options.url
110
+ };
111
+ if (typeof authData.id !== 'string') {
112
+ return Promise.reject(new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'LDAP: Wrong username or password'));
113
+ }
114
+ const client = ldapjs.createClient(clientOptions);
115
+ const escapedId = escapeDN(authData.id);
116
+ const userCn = typeof options.dn === 'string' ? options.dn.replace('{{id}}', escapedId) : `uid=${escapedId},${options.suffix}`;
117
+ return new Promise((resolve, reject) => {
118
+ client.bind(userCn, authData.password, ldapError => {
119
+ delete authData.password;
120
+ if (ldapError) {
121
+ let error;
122
+ switch (ldapError.code) {
123
+ case 49:
124
+ error = new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'LDAP: Wrong username or password');
125
+ break;
126
+ case 'DEPTH_ZERO_SELF_SIGNED_CERT':
127
+ error = new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'LDAPS: Certificate mismatch');
128
+ break;
129
+ default:
130
+ error = new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'LDAP: Somthing went wrong (' + ldapError.code + ')');
131
+ }
132
+ reject(error);
133
+ client.destroy(ldapError);
134
+ return;
135
+ }
136
+ if (typeof options.groupCn === 'string' && typeof options.groupFilter === 'string') {
137
+ searchForGroup(client, options, authData.id, resolve, reject);
138
+ } else {
139
+ client.unbind();
140
+ client.destroy();
141
+ resolve();
142
+ }
143
+ });
144
+ });
145
+ }
146
+ function optionsAreValid(options) {
147
+ return typeof options === 'object' && typeof options.suffix === 'string' && typeof options.url === 'string' && (options.url.startsWith('ldap://') || options.url.startsWith('ldaps://') && typeof options.tlsOptions === 'object');
148
+ }
149
+ function searchForGroup(client, options, id, resolve, reject) {
150
+ const filter = options.groupFilter.replace(/{{id}}/gi, escapeFilter(id));
151
+ const opts = {
152
+ scope: 'sub',
153
+ filter: filter
154
+ };
155
+ let found = false;
156
+ client.search(options.suffix, opts, (searchError, res) => {
157
+ if (searchError) {
158
+ client.unbind();
159
+ client.destroy();
160
+ return reject(new Parse.Error(Parse.Error.INTERNAL_SERVER_ERROR, 'LDAP group search failed'));
161
+ }
162
+ res.on('searchEntry', entry => {
163
+ if (entry.pojo.attributes.find(obj => obj.type === 'cn').values.includes(options.groupCn)) {
164
+ found = true;
165
+ client.unbind();
166
+ client.destroy();
167
+ return resolve();
168
+ }
169
+ });
170
+ res.on('end', () => {
171
+ if (!found) {
172
+ client.unbind();
173
+ client.destroy();
174
+ return reject(new Parse.Error(Parse.Error.INTERNAL_SERVER_ERROR, 'LDAP: User not in group'));
175
+ }
176
+ });
177
+ res.on('error', () => {
178
+ client.unbind();
179
+ client.destroy();
180
+ return reject(new Parse.Error(Parse.Error.INTERNAL_SERVER_ERROR, 'LDAP group search failed'));
181
+ });
182
+ });
183
+ }
184
+ function validateAppId() {
185
+ return Promise.resolve();
186
+ }
187
+ module.exports = {
188
+ validateAppId,
189
+ validateAuthData,
190
+ escapeDN,
191
+ escapeFilter
192
+ };
193
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJsZGFwanMiLCJyZXF1aXJlIiwiUGFyc2UiLCJlc2NhcGVETiIsInZhbHVlIiwiZXNjYXBlZCIsInJlcGxhY2UiLCJzdGFydHNXaXRoIiwic2xpY2UiLCJlbmRzV2l0aCIsImVzY2FwZUZpbHRlciIsImNoIiwiY2hhckNvZGVBdCIsInRvU3RyaW5nIiwicGFkU3RhcnQiLCJ2YWxpZGF0ZUF1dGhEYXRhIiwiYXV0aERhdGEiLCJvcHRpb25zIiwib3B0aW9uc0FyZVZhbGlkIiwiUHJvbWlzZSIsIl8iLCJyZWplY3QiLCJFcnJvciIsIklOVEVSTkFMX1NFUlZFUl9FUlJPUiIsImNsaWVudE9wdGlvbnMiLCJ1cmwiLCJ0bHNPcHRpb25zIiwiaWQiLCJPQkpFQ1RfTk9UX0ZPVU5EIiwiY2xpZW50IiwiY3JlYXRlQ2xpZW50IiwiZXNjYXBlZElkIiwidXNlckNuIiwiZG4iLCJzdWZmaXgiLCJyZXNvbHZlIiwiYmluZCIsInBhc3N3b3JkIiwibGRhcEVycm9yIiwiZXJyb3IiLCJjb2RlIiwiZGVzdHJveSIsImdyb3VwQ24iLCJncm91cEZpbHRlciIsInNlYXJjaEZvckdyb3VwIiwidW5iaW5kIiwiZmlsdGVyIiwib3B0cyIsInNjb3BlIiwiZm91bmQiLCJzZWFyY2giLCJzZWFyY2hFcnJvciIsInJlcyIsIm9uIiwiZW50cnkiLCJwb2pvIiwiYXR0cmlidXRlcyIsImZpbmQiLCJvYmoiLCJ0eXBlIiwidmFsdWVzIiwiaW5jbHVkZXMiLCJ2YWxpZGF0ZUFwcElkIiwibW9kdWxlIiwiZXhwb3J0cyJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9BZGFwdGVycy9BdXRoL2xkYXAuanMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBQYXJzZSBTZXJ2ZXIgYXV0aGVudGljYXRpb24gYWRhcHRlciBmb3IgTERBUC5cbiAqXG4gKiBAY2xhc3MgTERBUFxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgYWRhcHRlciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gKiBAcGFyYW0ge1N0cmluZ30gb3B0aW9ucy51cmwgLSBUaGUgTERBUCBzZXJ2ZXIgVVJMLiBNdXN0IHN0YXJ0IHdpdGggYGxkYXA6Ly9gIG9yIGBsZGFwczovL2AuXG4gKiBAcGFyYW0ge1N0cmluZ30gb3B0aW9ucy5zdWZmaXggLSBUaGUgTERBUCBzdWZmaXggZm9yIHVzZXIgZGlzdGluZ3Vpc2hlZCBuYW1lcyAoRE4pLlxuICogQHBhcmFtIHtTdHJpbmd9IFtvcHRpb25zLmRuXSAtIFRoZSBkaXN0aW5ndWlzaGVkIG5hbWUgKEROKSB0ZW1wbGF0ZSBmb3IgdXNlciBhdXRoZW50aWNhdGlvbi4gUmVwbGFjZSBge3tpZH19YCB3aXRoIHRoZSB1c2VybmFtZS5cbiAqIEBwYXJhbSB7T2JqZWN0fSBbb3B0aW9ucy50bHNPcHRpb25zXSAtIE9wdGlvbnMgZm9yIExEQVBTIFRMUyBjb25uZWN0aW9ucy5cbiAqIEBwYXJhbSB7U3RyaW5nfSBbb3B0aW9ucy5ncm91cENuXSAtIFRoZSBjb21tb24gbmFtZSAoQ04pIG9mIHRoZSBncm91cCB0byB2ZXJpZnkgdXNlciBtZW1iZXJzaGlwLlxuICogQHBhcmFtIHtTdHJpbmd9IFtvcHRpb25zLmdyb3VwRmlsdGVyXSAtIFRoZSBMREFQIHNlYXJjaCBmaWx0ZXIgZm9yIGdyb3Vwcywgd2l0aCBge3tpZH19YCByZXBsYWNlZCBieSB0aGUgdXNlcm5hbWUuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IGF1dGhEYXRhIC0gVGhlIGF1dGhlbnRpY2F0aW9uIGRhdGEgcHJvdmlkZWQgYnkgdGhlIGNsaWVudC5cbiAqIEBwYXJhbSB7U3RyaW5nfSBhdXRoRGF0YS5pZCAtIFRoZSB1c2VyJ3MgTERBUCB1c2VybmFtZS5cbiAqIEBwYXJhbSB7U3RyaW5nfSBhdXRoRGF0YS5wYXNzd29yZCAtIFRoZSB1c2VyJ3MgTERBUCBwYXNzd29yZC5cbiAqXG4gKiBAZGVzY3JpcHRpb25cbiAqICMjIFBhcnNlIFNlcnZlciBDb25maWd1cmF0aW9uXG4gKiBUbyBjb25maWd1cmUgUGFyc2UgU2VydmVyIGZvciBMREFQIGF1dGhlbnRpY2F0aW9uLCB1c2UgdGhlIGZvbGxvd2luZyBzdHJ1Y3R1cmU6XG4gKiBgYGBqYXZhc2NyaXB0XG4gKiB7XG4gKiAgIGF1dGg6IHtcbiAqICAgICBsZGFwOiB7XG4gKiAgICAgICB1cmw6ICdsZGFwczovL2xkYXAuZXhhbXBsZS5jb20nLFxuICogICAgICAgc3VmZml4OiAnb3U9dXNlcnMsZGM9ZXhhbXBsZSxkYz1jb20nLFxuICogICAgICAgZ3JvdXBDbjogJ2FkbWlucycsXG4gKiAgICAgICBncm91cEZpbHRlcjogJyhtZW1iZXJVaWQ9e3tpZH19KScsXG4gKiAgICAgICB0bHNPcHRpb25zOiB7XG4gKiAgICAgICAgIHJlamVjdFVuYXV0aG9yaXplZDogZmFsc2VcbiAqICAgICAgIH1cbiAqICAgICB9XG4gKiAgIH1cbiAqIH1cbiAqIGBgYFxuICpcbiAqICMjIEF1dGhlbnRpY2F0aW9uIFByb2Nlc3NcbiAqIDEuIFZhbGlkYXRlcyB0aGUgcHJvdmlkZWQgYGF1dGhEYXRhYCB1c2luZyBhbiBMREFQIGJpbmQgb3BlcmF0aW9uLlxuICogMi4gT3B0aW9uYWxseSwgdmVyaWZpZXMgdGhhdCB0aGUgdXNlciBiZWxvbmdzIHRvIGEgc3BlY2lmaWMgZ3JvdXAgYnkgcGVyZm9ybWluZyBhbiBMREFQIHNlYXJjaCB1c2luZyB0aGUgcHJvdmlkZWQgYGdyb3VwQ25gIG9yIGBncm91cEZpbHRlcmAuXG4gKlxuICogIyMgQXV0aCBQYXlsb2FkXG4gKiBUaGUgYWRhcHRlciByZXF1aXJlcyB0aGUgZm9sbG93aW5nIGBhdXRoRGF0YWAgZmllbGRzOlxuICogLSBgaWRgOiBUaGUgdXNlcidzIExEQVAgdXNlcm5hbWUuXG4gKiAtIGBwYXNzd29yZGA6IFRoZSB1c2VyJ3MgTERBUCBwYXNzd29yZC5cbiAqXG4gKiAjIyMgRXhhbXBsZSBBdXRoIFBheWxvYWRcbiAqIGBgYGpzb25cbiAqIHtcbiAqICAgXCJsZGFwXCI6IHtcbiAqICAgICBcImlkXCI6IFwiamRvZVwiLFxuICogICAgIFwicGFzc3dvcmRcIjogXCJwYXNzd29yZDEyM1wiXG4gKiAgIH1cbiAqIH1cbiAqIGBgYFxuICpcbiAqIEBleGFtcGxlIDxjYXB0aW9uPkNvbmZpZ3VyYXRpb24gRXhhbXBsZTwvY2FwdGlvbj5cbiAqIC8vIEV4YW1wbGUgUGFyc2UgU2VydmVyIGNvbmZpZ3VyYXRpb246XG4gKiBjb25zdCBjb25maWcgPSB7XG4gKiAgIGF1dGg6IHtcbiAqICAgICBsZGFwOiB7XG4gKiAgICAgICB1cmw6ICdsZGFwczovL2xkYXAuZXhhbXBsZS5jb20nLFxuICogICAgICAgc3VmZml4OiAnb3U9dXNlcnMsZGM9ZXhhbXBsZSxkYz1jb20nLFxuICogICAgICAgZ3JvdXBDbjogJ2FkbWlucycsXG4gKiAgICAgICBncm91cEZpbHRlcjogJyhtZW1iZXJVaWQ9e3tpZH19KScsXG4gKiAgICAgICB0bHNPcHRpb25zOiB7XG4gKiAgICAgICAgIHJlamVjdFVuYXV0aG9yaXplZDogZmFsc2VcbiAqICAgICAgIH1cbiAqICAgICB9XG4gKiAgIH1cbiAqIH07XG4gKlxuICogQHNlZSB7QGxpbmsgaHR0cHM6Ly9sZGFwLmNvbS8gTERBUCBCYXNpY3N9XG4gKiBAc2VlIHtAbGluayBodHRwczovL2xkYXAuY29tL2xkYXAtZmlsdGVycy8gTERBUCBGaWx0ZXJzfVxuICovXG5cblxuY29uc3QgbGRhcGpzID0gcmVxdWlyZSgnbGRhcGpzJyk7XG5jb25zdCBQYXJzZSA9IHJlcXVpcmUoJ3BhcnNlL25vZGUnKS5QYXJzZTtcblxuLy8gRXNjYXBlIExEQVAgRE4gc3BlY2lhbCBjaGFyYWN0ZXJzIHBlciBSRkMgNDUxNFxuLy8gaHR0cHM6Ly9kYXRhdHJhY2tlci5pZXRmLm9yZy9kb2MvaHRtbC9yZmM0NTE0I3NlY3Rpb24tMi40XG5mdW5jdGlvbiBlc2NhcGVETih2YWx1ZSkge1xuICBsZXQgZXNjYXBlZCA9IHZhbHVlXG4gICAgLnJlcGxhY2UoL1xcXFwvZywgJ1xcXFxcXFxcJylcbiAgICAucmVwbGFjZSgvLC9nLCAnXFxcXCwnKVxuICAgIC5yZXBsYWNlKC89L2csICdcXFxcPScpXG4gICAgLnJlcGxhY2UoL1xcKy9nLCAnXFxcXCsnKVxuICAgIC5yZXBsYWNlKC88L2csICdcXFxcPCcpXG4gICAgLnJlcGxhY2UoLz4vZywgJ1xcXFw+JylcbiAgICAucmVwbGFjZSgvIy9nLCAnXFxcXCMnKVxuICAgIC5yZXBsYWNlKC87L2csICdcXFxcOycpXG4gICAgLnJlcGxhY2UoL1wiL2csICdcXFxcXCInKTtcbiAgaWYgKGVzY2FwZWQuc3RhcnRzV2l0aCgnICcpKSB7XG4gICAgZXNjYXBlZCA9ICdcXFxcICcgKyBlc2NhcGVkLnNsaWNlKDEpO1xuICB9XG4gIGlmIChlc2NhcGVkLmVuZHNXaXRoKCcgJykpIHtcbiAgICBlc2NhcGVkID0gZXNjYXBlZC5zbGljZSgwLCAtMSkgKyAnXFxcXCAnO1xuICB9XG4gIHJldHVybiBlc2NhcGVkO1xufVxuXG4vLyBFc2NhcGUgTERBUCBmaWx0ZXIgc3BlY2lhbCBjaGFyYWN0ZXJzIHBlciBSRkMgNDUxNVxuLy8gaHR0cHM6Ly9kYXRhdHJhY2tlci5pZXRmLm9yZy9kb2MvaHRtbC9yZmM0NTE1I3NlY3Rpb24tM1xuZnVuY3Rpb24gZXNjYXBlRmlsdGVyKHZhbHVlKSB7XG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1jb250cm9sLXJlZ2V4XG4gIHJldHVybiB2YWx1ZS5yZXBsYWNlKC9bXFxcXCooKVxceDAwXS9nLCBjaCA9PlxuICAgICdcXFxcJyArIGNoLmNoYXJDb2RlQXQoMCkudG9TdHJpbmcoMTYpLnBhZFN0YXJ0KDIsICcwJylcbiAgKTtcbn1cblxuZnVuY3Rpb24gdmFsaWRhdGVBdXRoRGF0YShhdXRoRGF0YSwgb3B0aW9ucykge1xuICBpZiAoIW9wdGlvbnNBcmVWYWxpZChvcHRpb25zKSkge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgoXywgcmVqZWN0KSA9PiB7XG4gICAgICByZWplY3QobmV3IFBhcnNlLkVycm9yKFBhcnNlLkVycm9yLklOVEVSTkFMX1NFUlZFUl9FUlJPUiwgJ0xEQVAgYXV0aCBjb25maWd1cmF0aW9uIG1pc3NpbmcnKSk7XG4gICAgfSk7XG4gIH1cbiAgY29uc3QgY2xpZW50T3B0aW9ucyA9IG9wdGlvbnMudXJsLnN0YXJ0c1dpdGgoJ2xkYXBzOi8vJylcbiAgICA/IHsgdXJsOiBvcHRpb25zLnVybCwgdGxzT3B0aW9uczogb3B0aW9ucy50bHNPcHRpb25zIH1cbiAgICA6IHsgdXJsOiBvcHRpb25zLnVybCB9O1xuXG4gIGlmICh0eXBlb2YgYXV0aERhdGEuaWQgIT09ICdzdHJpbmcnKSB7XG4gICAgcmV0dXJuIFByb21pc2UucmVqZWN0KFxuICAgICAgbmV3IFBhcnNlLkVycm9yKFBhcnNlLkVycm9yLk9CSkVDVF9OT1RfRk9VTkQsICdMREFQOiBXcm9uZyB1c2VybmFtZSBvciBwYXNzd29yZCcpXG4gICAgKTtcbiAgfVxuICBjb25zdCBjbGllbnQgPSBsZGFwanMuY3JlYXRlQ2xpZW50KGNsaWVudE9wdGlvbnMpO1xuICBjb25zdCBlc2NhcGVkSWQgPSBlc2NhcGVETihhdXRoRGF0YS5pZCk7XG4gIGNvbnN0IHVzZXJDbiA9XG4gICAgdHlwZW9mIG9wdGlvbnMuZG4gPT09ICdzdHJpbmcnXG4gICAgICA/IG9wdGlvbnMuZG4ucmVwbGFjZSgne3tpZH19JywgZXNjYXBlZElkKVxuICAgICAgOiBgdWlkPSR7ZXNjYXBlZElkfSwke29wdGlvbnMuc3VmZml4fWA7XG5cbiAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICBjbGllbnQuYmluZCh1c2VyQ24sIGF1dGhEYXRhLnBhc3N3b3JkLCBsZGFwRXJyb3IgPT4ge1xuICAgICAgZGVsZXRlIGF1dGhEYXRhLnBhc3N3b3JkO1xuICAgICAgaWYgKGxkYXBFcnJvcikge1xuICAgICAgICBsZXQgZXJyb3I7XG4gICAgICAgIHN3aXRjaCAobGRhcEVycm9yLmNvZGUpIHtcbiAgICAgICAgICBjYXNlIDQ5OlxuICAgICAgICAgICAgZXJyb3IgPSBuZXcgUGFyc2UuRXJyb3IoXG4gICAgICAgICAgICAgIFBhcnNlLkVycm9yLk9CSkVDVF9OT1RfRk9VTkQsXG4gICAgICAgICAgICAgICdMREFQOiBXcm9uZyB1c2VybmFtZSBvciBwYXNzd29yZCdcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICBjYXNlICdERVBUSF9aRVJPX1NFTEZfU0lHTkVEX0NFUlQnOlxuICAgICAgICAgICAgZXJyb3IgPSBuZXcgUGFyc2UuRXJyb3IoUGFyc2UuRXJyb3IuT0JKRUNUX05PVF9GT1VORCwgJ0xEQVBTOiBDZXJ0aWZpY2F0ZSBtaXNtYXRjaCcpO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgIGVycm9yID0gbmV3IFBhcnNlLkVycm9yKFxuICAgICAgICAgICAgICBQYXJzZS5FcnJvci5PQkpFQ1RfTk9UX0ZPVU5ELFxuICAgICAgICAgICAgICAnTERBUDogU29tdGhpbmcgd2VudCB3cm9uZyAoJyArIGxkYXBFcnJvci5jb2RlICsgJyknXG4gICAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIHJlamVjdChlcnJvcik7XG4gICAgICAgIGNsaWVudC5kZXN0cm95KGxkYXBFcnJvcik7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKHR5cGVvZiBvcHRpb25zLmdyb3VwQ24gPT09ICdzdHJpbmcnICYmIHR5cGVvZiBvcHRpb25zLmdyb3VwRmlsdGVyID09PSAnc3RyaW5nJykge1xuICAgICAgICBzZWFyY2hGb3JHcm91cChjbGllbnQsIG9wdGlvbnMsIGF1dGhEYXRhLmlkLCByZXNvbHZlLCByZWplY3QpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY2xpZW50LnVuYmluZCgpO1xuICAgICAgICBjbGllbnQuZGVzdHJveSgpO1xuICAgICAgICByZXNvbHZlKCk7XG4gICAgICB9XG4gICAgfSk7XG4gIH0pO1xufVxuXG5mdW5jdGlvbiBvcHRpb25zQXJlVmFsaWQob3B0aW9ucykge1xuICByZXR1cm4gKFxuICAgIHR5cGVvZiBvcHRpb25zID09PSAnb2JqZWN0JyAmJlxuICAgIHR5cGVvZiBvcHRpb25zLnN1ZmZpeCA9PT0gJ3N0cmluZycgJiZcbiAgICB0eXBlb2Ygb3B0aW9ucy51cmwgPT09ICdzdHJpbmcnICYmXG4gICAgKG9wdGlvbnMudXJsLnN0YXJ0c1dpdGgoJ2xkYXA6Ly8nKSB8fFxuICAgICAgKG9wdGlvbnMudXJsLnN0YXJ0c1dpdGgoJ2xkYXBzOi8vJykgJiYgdHlwZW9mIG9wdGlvbnMudGxzT3B0aW9ucyA9PT0gJ29iamVjdCcpKVxuICApO1xufVxuXG5mdW5jdGlvbiBzZWFyY2hGb3JHcm91cChjbGllbnQsIG9wdGlvbnMsIGlkLCByZXNvbHZlLCByZWplY3QpIHtcbiAgY29uc3QgZmlsdGVyID0gb3B0aW9ucy5ncm91cEZpbHRlci5yZXBsYWNlKC97e2lkfX0vZ2ksIGVzY2FwZUZpbHRlcihpZCkpO1xuICBjb25zdCBvcHRzID0ge1xuICAgIHNjb3BlOiAnc3ViJyxcbiAgICBmaWx0ZXI6IGZpbHRlcixcbiAgfTtcbiAgbGV0IGZvdW5kID0gZmFsc2U7XG4gIGNsaWVudC5zZWFyY2gob3B0aW9ucy5zdWZmaXgsIG9wdHMsIChzZWFyY2hFcnJvciwgcmVzKSA9PiB7XG4gICAgaWYgKHNlYXJjaEVycm9yKSB7XG4gICAgICBjbGllbnQudW5iaW5kKCk7XG4gICAgICBjbGllbnQuZGVzdHJveSgpO1xuICAgICAgcmV0dXJuIHJlamVjdChuZXcgUGFyc2UuRXJyb3IoUGFyc2UuRXJyb3IuSU5URVJOQUxfU0VSVkVSX0VSUk9SLCAnTERBUCBncm91cCBzZWFyY2ggZmFpbGVkJykpO1xuICAgIH1cbiAgICByZXMub24oJ3NlYXJjaEVudHJ5JywgZW50cnkgPT4ge1xuICAgICAgaWYgKGVudHJ5LnBvam8uYXR0cmlidXRlcy5maW5kKG9iaiA9PiBvYmoudHlwZSA9PT0gJ2NuJykudmFsdWVzLmluY2x1ZGVzKG9wdGlvbnMuZ3JvdXBDbikpIHtcbiAgICAgICAgZm91bmQgPSB0cnVlO1xuICAgICAgICBjbGllbnQudW5iaW5kKCk7XG4gICAgICAgIGNsaWVudC5kZXN0cm95KCk7XG4gICAgICAgIHJldHVybiByZXNvbHZlKCk7XG4gICAgICB9XG4gICAgfSk7XG4gICAgcmVzLm9uKCdlbmQnLCAoKSA9PiB7XG4gICAgICBpZiAoIWZvdW5kKSB7XG4gICAgICAgIGNsaWVudC51bmJpbmQoKTtcbiAgICAgICAgY2xpZW50LmRlc3Ryb3koKTtcbiAgICAgICAgcmV0dXJuIHJlamVjdChcbiAgICAgICAgICBuZXcgUGFyc2UuRXJyb3IoUGFyc2UuRXJyb3IuSU5URVJOQUxfU0VSVkVSX0VSUk9SLCAnTERBUDogVXNlciBub3QgaW4gZ3JvdXAnKVxuICAgICAgICApO1xuICAgICAgfVxuICAgIH0pO1xuICAgIHJlcy5vbignZXJyb3InLCAoKSA9PiB7XG4gICAgICBjbGllbnQudW5iaW5kKCk7XG4gICAgICBjbGllbnQuZGVzdHJveSgpO1xuICAgICAgcmV0dXJuIHJlamVjdChuZXcgUGFyc2UuRXJyb3IoUGFyc2UuRXJyb3IuSU5URVJOQUxfU0VSVkVSX0VSUk9SLCAnTERBUCBncm91cCBzZWFyY2ggZmFpbGVkJykpO1xuICAgIH0pO1xuICB9KTtcbn1cblxuZnVuY3Rpb24gdmFsaWRhdGVBcHBJZCgpIHtcbiAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgdmFsaWRhdGVBcHBJZCxcbiAgdmFsaWRhdGVBdXRoRGF0YSxcbiAgZXNjYXBlRE4sXG4gIGVzY2FwZUZpbHRlcixcbn07XG4iXSwibWFwcGluZ3MiOiI7O0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7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