culparepellendus 1.0.0

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 (470) hide show
  1. package/.env.example +2 -0
  2. package/.eslintrc.js +20 -0
  3. package/.github/workflows/deploy-docs.yml +27 -0
  4. package/.github/workflows/pre-release-tests.yml +45 -0
  5. package/.github/workflows/pull-request-tests.yml +45 -0
  6. package/.prettierignore +2 -0
  7. package/.prettierrc +19 -0
  8. package/.vscode/launch.json +24 -0
  9. package/.vscode/settings.json +3 -0
  10. package/codecov.yml +7 -0
  11. package/demos/.eslintrc.js +13 -0
  12. package/demos/ago-node-cli/README.md +29 -0
  13. package/demos/ago-node-cli/ago.js +33 -0
  14. package/demos/ago-node-cli/index.js +11 -0
  15. package/demos/ago-node-cli/lib/item-export-command.js +48 -0
  16. package/demos/ago-node-cli/lib/item-search-command.js +35 -0
  17. package/demos/ago-node-cli/package-lock.json +430 -0
  18. package/demos/ago-node-cli/package.json +30 -0
  19. package/demos/attachments/README.md +5 -0
  20. package/demos/attachments/index.html +165 -0
  21. package/demos/attachments/package-lock.json +543 -0
  22. package/demos/attachments/package.json +18 -0
  23. package/demos/batch-geocoder-node/NYC_Restaurant_Inspection_Results.csv +100 -0
  24. package/demos/batch-geocoder-node/README.md +15 -0
  25. package/demos/batch-geocoder-node/batch-geocode.js +115 -0
  26. package/demos/batch-geocoder-node/config-template.js +18 -0
  27. package/demos/batch-geocoder-node/package-lock.json +336 -0
  28. package/demos/batch-geocoder-node/package.json +37 -0
  29. package/demos/express/README.md +15 -0
  30. package/demos/express/config.json.template +3 -0
  31. package/demos/express/package-lock.json +1008 -0
  32. package/demos/express/package.json +18 -0
  33. package/demos/express/server.js +33 -0
  34. package/demos/feature-service-browser/README.md +6 -0
  35. package/demos/feature-service-browser/index.html +122 -0
  36. package/demos/feature-service-browser/package-lock.json +543 -0
  37. package/demos/feature-service-browser/package.json +18 -0
  38. package/demos/geocoder-browser/README.md +10 -0
  39. package/demos/geocoder-browser/config.js.template +1 -0
  40. package/demos/geocoder-browser/index.html +131 -0
  41. package/demos/geocoder-browser/package-lock.json +610 -0
  42. package/demos/geocoder-browser/package.json +19 -0
  43. package/demos/geocoder-browser/post-sign-in.html +25 -0
  44. package/demos/jsapi-integration/README.md +25 -0
  45. package/demos/jsapi-integration/config.js +6 -0
  46. package/demos/jsapi-integration/index.html +93 -0
  47. package/demos/jsapi-integration/package-lock.json +247 -0
  48. package/demos/jsapi-integration/package.json +19 -0
  49. package/demos/node-cli-item-management/README.md +10 -0
  50. package/demos/node-cli-item-management/index.js +238 -0
  51. package/demos/node-cli-item-management/package-lock.json +432 -0
  52. package/demos/node-cli-item-management/package.json +27 -0
  53. package/demos/node-cli-item-management/screenshot.png +0 -0
  54. package/demos/oauth2-browser/README.md +14 -0
  55. package/demos/oauth2-browser/authenticate.html +30 -0
  56. package/demos/oauth2-browser/config.js.template +6 -0
  57. package/demos/oauth2-browser/index.html +211 -0
  58. package/demos/oauth2-browser/logo.svg +4 -0
  59. package/demos/oauth2-browser/package-lock.json +474 -0
  60. package/demos/oauth2-browser/package.json +18 -0
  61. package/demos/oauth2-browser/style.css +36 -0
  62. package/demos/oauth2-browser-retry/README.md +25 -0
  63. package/demos/oauth2-browser-retry/authenticate.html +22 -0
  64. package/demos/oauth2-browser-retry/index.html +116 -0
  65. package/demos/oauth2-browser-retry/logo.svg +4 -0
  66. package/demos/stream-response-to-file/README.md +7 -0
  67. package/demos/stream-response-to-file/index.js +36 -0
  68. package/demos/stream-response-to-file/output/.gitkeep +0 -0
  69. package/demos/stream-response-to-file/package-lock.json +227 -0
  70. package/demos/stream-response-to-file/package.json +33 -0
  71. package/demos/tree-shaking-rollup/.babelrc +3 -0
  72. package/demos/tree-shaking-rollup/README.md +9 -0
  73. package/demos/tree-shaking-rollup/index.html +11 -0
  74. package/demos/tree-shaking-rollup/package-lock.json +5646 -0
  75. package/demos/tree-shaking-rollup/package.json +25 -0
  76. package/demos/tree-shaking-rollup/rollup.config.js +17 -0
  77. package/demos/tree-shaking-rollup/src/index.js +8 -0
  78. package/demos/tree-shaking-webpack/README.md +8 -0
  79. package/demos/tree-shaking-webpack/index.html +11 -0
  80. package/demos/tree-shaking-webpack/package-lock.json +11455 -0
  81. package/demos/tree-shaking-webpack/package.json +24 -0
  82. package/demos/tree-shaking-webpack/src/index.js +10 -0
  83. package/demos/tree-shaking-webpack/webpack.config.js +27 -0
  84. package/demos/vue/.env.example +11 -0
  85. package/demos/vue/.eslintrc.js +17 -0
  86. package/demos/vue/.postcssrc.js +5 -0
  87. package/demos/vue/README.md +17 -0
  88. package/demos/vue/babel.config.js +3 -0
  89. package/demos/vue/package-lock.json +28044 -0
  90. package/demos/vue/package.json +33 -0
  91. package/demos/vue/public/favicon.ico +0 -0
  92. package/demos/vue/public/index.html +24 -0
  93. package/demos/vue/src/assets/logo.svg +29 -0
  94. package/demos/vue/src/components/App.vue +305 -0
  95. package/demos/vue/src/components/Authenticate.vue +65 -0
  96. package/demos/vue/src/components/Loader.vue +230 -0
  97. package/demos/vue/src/main.js +92 -0
  98. package/demos/webmap-checker-sapper/.env.example +5 -0
  99. package/demos/webmap-checker-sapper/README.md +123 -0
  100. package/demos/webmap-checker-sapper/appveyor.yml +18 -0
  101. package/demos/webmap-checker-sapper/cypress/fixtures/example.json +5 -0
  102. package/demos/webmap-checker-sapper/cypress/integration/spec.js +19 -0
  103. package/demos/webmap-checker-sapper/cypress/plugins/index.js +17 -0
  104. package/demos/webmap-checker-sapper/cypress/support/commands.js +25 -0
  105. package/demos/webmap-checker-sapper/cypress/support/index.js +20 -0
  106. package/demos/webmap-checker-sapper/cypress.json +4 -0
  107. package/demos/webmap-checker-sapper/package-lock.json +9622 -0
  108. package/demos/webmap-checker-sapper/package.json +50 -0
  109. package/demos/webmap-checker-sapper/rollup.config.js +87 -0
  110. package/demos/webmap-checker-sapper/src/client.js +20 -0
  111. package/demos/webmap-checker-sapper/src/components/LayerStatus.html +108 -0
  112. package/demos/webmap-checker-sapper/src/components/Nav.html +21 -0
  113. package/demos/webmap-checker-sapper/src/components/WebMap.html +62 -0
  114. package/demos/webmap-checker-sapper/src/routes/_error.html +41 -0
  115. package/demos/webmap-checker-sapper/src/routes/_layout.html +21 -0
  116. package/demos/webmap-checker-sapper/src/routes/auth/authorize.js +18 -0
  117. package/demos/webmap-checker-sapper/src/routes/auth/exchange-token.js +20 -0
  118. package/demos/webmap-checker-sapper/src/routes/auth/post-sign-in.js +24 -0
  119. package/demos/webmap-checker-sapper/src/routes/auth/sign-out.js +10 -0
  120. package/demos/webmap-checker-sapper/src/routes/index.html +20 -0
  121. package/demos/webmap-checker-sapper/src/routes/webmaps/[webmapId].html +83 -0
  122. package/demos/webmap-checker-sapper/src/routes/webmaps/index.html +59 -0
  123. package/demos/webmap-checker-sapper/src/server.js +101 -0
  124. package/demos/webmap-checker-sapper/src/service-worker.js +82 -0
  125. package/demos/webmap-checker-sapper/src/template.html +33 -0
  126. package/demos/webmap-checker-sapper/src/userInfoMiddleware.js +21 -0
  127. package/demos/webmap-checker-sapper/src/utils.js +33 -0
  128. package/demos/webmap-checker-sapper/static/favicon.png +0 -0
  129. package/demos/webmap-checker-sapper/static/global.css +36 -0
  130. package/demos/webmap-checker-sapper/static/manifest.json +20 -0
  131. package/demos/webmap-checker-sapper/static/svelte-logo-192.png +0 -0
  132. package/demos/webmap-checker-sapper/static/svelte-logo-512.png +0 -0
  133. package/docs/.eslintrc.js +12 -0
  134. package/docs/FAQ.md +48 -0
  135. package/docs/HISTORY.md +62 -0
  136. package/docs/acetate.config.js +262 -0
  137. package/docs/build-typedoc.js +434 -0
  138. package/docs/generate-srihashes.js +53 -0
  139. package/docs/src/_layout.html +86 -0
  140. package/docs/src/api/_declaration.html +600 -0
  141. package/docs/src/api/_layout.html +204 -0
  142. package/docs/src/api/_package.html +38 -0
  143. package/docs/src/api/index.html +16 -0
  144. package/docs/src/guides/_layout.html +24 -0
  145. package/docs/src/guides/amd-requirejs-dojo.md +40 -0
  146. package/docs/src/guides/browser-authentication.md +39 -0
  147. package/docs/src/guides/bundlers.md +52 -0
  148. package/docs/src/guides/cli-authentication.md +9 -0
  149. package/docs/src/guides/client-server-authentication.md +9 -0
  150. package/docs/src/guides/embedded-apps.md +106 -0
  151. package/docs/src/guides/from-a-cdn.md +38 -0
  152. package/docs/src/guides/index.md +59 -0
  153. package/docs/src/guides/node.md +104 -0
  154. package/docs/src/guides/package-overview.md +111 -0
  155. package/docs/src/guides/server-authentication.md +9 -0
  156. package/docs/src/guides/whats-new-v2-0.md +305 -0
  157. package/docs/src/img/icons.png +0 -0
  158. package/docs/src/img/icons@2x.png +0 -0
  159. package/docs/src/img/oauth-browser.png +0 -0
  160. package/docs/src/index.html +12 -0
  161. package/docs/src/js/api-search.js +112 -0
  162. package/docs/src/js/nav-toggle.js +41 -0
  163. package/docs/src/sass/_highlight.scss +96 -0
  164. package/docs/src/sass/_icons.scss +157 -0
  165. package/docs/src/sass/style.scss +242 -0
  166. package/docs/src/srihashes.json +12 -0
  167. package/jasmine.json +7 -0
  168. package/jasmine.live.json +7 -0
  169. package/karma.conf.js +107 -0
  170. package/lerna.json +8 -0
  171. package/notes/README.md +68 -0
  172. package/package.json +87 -0
  173. package/packages/arcgis-rest-auth/README.md +71 -0
  174. package/packages/arcgis-rest-auth/package-lock.json +27 -0
  175. package/packages/arcgis-rest-auth/package.json +69 -0
  176. package/packages/arcgis-rest-auth/post-message-auth-spec.md +70 -0
  177. package/packages/arcgis-rest-auth/src/ApiKey.ts +41 -0
  178. package/packages/arcgis-rest-auth/src/ApplicationSession.ts +122 -0
  179. package/packages/arcgis-rest-auth/src/UserSession.ts +1376 -0
  180. package/packages/arcgis-rest-auth/src/app-tokens.ts +131 -0
  181. package/packages/arcgis-rest-auth/src/authenticated-request-options.ts +24 -0
  182. package/packages/arcgis-rest-auth/src/federation-utils.ts +85 -0
  183. package/packages/arcgis-rest-auth/src/fetch-token.ts +50 -0
  184. package/packages/arcgis-rest-auth/src/generate-token.ts +35 -0
  185. package/packages/arcgis-rest-auth/src/index.ts +13 -0
  186. package/packages/arcgis-rest-auth/src/validate-app-access.ts +68 -0
  187. package/packages/arcgis-rest-auth/test/ApiKey.test.ts +35 -0
  188. package/packages/arcgis-rest-auth/test/ApplicationSession.test.ts +124 -0
  189. package/packages/arcgis-rest-auth/test/UserSession.test.ts +2430 -0
  190. package/packages/arcgis-rest-auth/test/app-tokens.test.ts +95 -0
  191. package/packages/arcgis-rest-auth/test/federation-utils.test.ts +323 -0
  192. package/packages/arcgis-rest-auth/test/fetchToken.test.ts +112 -0
  193. package/packages/arcgis-rest-auth/test/generateToken.test.ts +102 -0
  194. package/packages/arcgis-rest-auth/test/utils.ts +14 -0
  195. package/packages/arcgis-rest-auth/test/validate-app-access.test.ts +46 -0
  196. package/packages/arcgis-rest-auth/tsconfig.json +6 -0
  197. package/packages/arcgis-rest-demographics/README.md +75 -0
  198. package/packages/arcgis-rest-demographics/package-lock.json +11 -0
  199. package/packages/arcgis-rest-demographics/package.json +69 -0
  200. package/packages/arcgis-rest-demographics/src/getAvailableCountries.ts +113 -0
  201. package/packages/arcgis-rest-demographics/src/getAvailableDataCollections.ts +166 -0
  202. package/packages/arcgis-rest-demographics/src/getAvailableGeographyLevels.ts +88 -0
  203. package/packages/arcgis-rest-demographics/src/getGeography.ts +152 -0
  204. package/packages/arcgis-rest-demographics/src/helpers.ts +28 -0
  205. package/packages/arcgis-rest-demographics/src/index.ts +8 -0
  206. package/packages/arcgis-rest-demographics/src/queryDemographicData.ts +106 -0
  207. package/packages/arcgis-rest-demographics/test/getAvailableCountries.test.ts +92 -0
  208. package/packages/arcgis-rest-demographics/test/getAvailableDataCollections.test.ts +115 -0
  209. package/packages/arcgis-rest-demographics/test/getAvailableGeographyLevels.test.ts +72 -0
  210. package/packages/arcgis-rest-demographics/test/getGeography.test.ts +141 -0
  211. package/packages/arcgis-rest-demographics/test/mocks/responses.ts +4 -0
  212. package/packages/arcgis-rest-demographics/test/queryDemographicData.test.live.ts +42 -0
  213. package/packages/arcgis-rest-demographics/test/queryDemographicData.test.ts +113 -0
  214. package/packages/arcgis-rest-demographics/tsconfig.json +6 -0
  215. package/packages/arcgis-rest-feature-layer/README.md +77 -0
  216. package/packages/arcgis-rest-feature-layer/package-lock.json +11 -0
  217. package/packages/arcgis-rest-feature-layer/package.json +64 -0
  218. package/packages/arcgis-rest-feature-layer/src/add.ts +56 -0
  219. package/packages/arcgis-rest-feature-layer/src/addAttachment.ts +53 -0
  220. package/packages/arcgis-rest-feature-layer/src/applyEdits.ts +95 -0
  221. package/packages/arcgis-rest-feature-layer/src/decodeValues.ts +122 -0
  222. package/packages/arcgis-rest-feature-layer/src/delete.ts +61 -0
  223. package/packages/arcgis-rest-feature-layer/src/deleteAttachments.ts +52 -0
  224. package/packages/arcgis-rest-feature-layer/src/getAllLayersAndTables.ts +30 -0
  225. package/packages/arcgis-rest-feature-layer/src/getAttachments.ts +55 -0
  226. package/packages/arcgis-rest-feature-layer/src/getLayer.ts +24 -0
  227. package/packages/arcgis-rest-feature-layer/src/getService.ts +26 -0
  228. package/packages/arcgis-rest-feature-layer/src/helpers.ts +97 -0
  229. package/packages/arcgis-rest-feature-layer/src/index.ts +32 -0
  230. package/packages/arcgis-rest-feature-layer/src/query.ts +204 -0
  231. package/packages/arcgis-rest-feature-layer/src/queryRelated.ts +89 -0
  232. package/packages/arcgis-rest-feature-layer/src/update.ts +60 -0
  233. package/packages/arcgis-rest-feature-layer/src/updateAttachment.ts +59 -0
  234. package/packages/arcgis-rest-feature-layer/test/attachments.test.ts +200 -0
  235. package/packages/arcgis-rest-feature-layer/test/crud.test.ts +197 -0
  236. package/packages/arcgis-rest-feature-layer/test/decodeValues.test.ts +67 -0
  237. package/packages/arcgis-rest-feature-layer/test/getAllLayersAndTables.test.ts +28 -0
  238. package/packages/arcgis-rest-feature-layer/test/getLayer.test.ts +31 -0
  239. package/packages/arcgis-rest-feature-layer/test/getService.test.ts +31 -0
  240. package/packages/arcgis-rest-feature-layer/test/helpers.test.ts +25 -0
  241. package/packages/arcgis-rest-feature-layer/test/mocks/allLayersAndTablesResponse.ts +906 -0
  242. package/packages/arcgis-rest-feature-layer/test/mocks/cvdQueryResponse.ts +225 -0
  243. package/packages/arcgis-rest-feature-layer/test/mocks/feature.ts +302 -0
  244. package/packages/arcgis-rest-feature-layer/test/mocks/fields.ts +779 -0
  245. package/packages/arcgis-rest-feature-layer/test/mocks/foo.txt +1 -0
  246. package/packages/arcgis-rest-feature-layer/test/mocks/service.ts +398 -0
  247. package/packages/arcgis-rest-feature-layer/test/query.test.ts +167 -0
  248. package/packages/arcgis-rest-feature-layer/tsconfig.json +6 -0
  249. package/packages/arcgis-rest-geocoding/README.md +86 -0
  250. package/packages/arcgis-rest-geocoding/package-lock.json +43 -0
  251. package/packages/arcgis-rest-geocoding/package.json +66 -0
  252. package/packages/arcgis-rest-geocoding/src/bulk.ts +104 -0
  253. package/packages/arcgis-rest-geocoding/src/geocode.ts +166 -0
  254. package/packages/arcgis-rest-geocoding/src/helpers.ts +56 -0
  255. package/packages/arcgis-rest-geocoding/src/index.ts +15 -0
  256. package/packages/arcgis-rest-geocoding/src/reverse.ts +84 -0
  257. package/packages/arcgis-rest-geocoding/src/suggest.ts +45 -0
  258. package/packages/arcgis-rest-geocoding/test/bulk.test.ts +194 -0
  259. package/packages/arcgis-rest-geocoding/test/geocode.test.ts +253 -0
  260. package/packages/arcgis-rest-geocoding/test/helpers.test.ts +85 -0
  261. package/packages/arcgis-rest-geocoding/test/mocks/responses.ts +591 -0
  262. package/packages/arcgis-rest-geocoding/test/reverse.test.ts +126 -0
  263. package/packages/arcgis-rest-geocoding/test/suggest.test.ts +53 -0
  264. package/packages/arcgis-rest-geocoding/tsconfig.json +6 -0
  265. package/packages/arcgis-rest-portal/README.md +73 -0
  266. package/packages/arcgis-rest-portal/package-lock.json +37 -0
  267. package/packages/arcgis-rest-portal/package.json +64 -0
  268. package/packages/arcgis-rest-portal/src/groups/add-users.ts +140 -0
  269. package/packages/arcgis-rest-portal/src/groups/create.ts +43 -0
  270. package/packages/arcgis-rest-portal/src/groups/get.ts +184 -0
  271. package/packages/arcgis-rest-portal/src/groups/helpers.ts +14 -0
  272. package/packages/arcgis-rest-portal/src/groups/invite-users.ts +127 -0
  273. package/packages/arcgis-rest-portal/src/groups/join.ts +57 -0
  274. package/packages/arcgis-rest-portal/src/groups/notification.ts +77 -0
  275. package/packages/arcgis-rest-portal/src/groups/protect.ts +56 -0
  276. package/packages/arcgis-rest-portal/src/groups/remove-users.ts +76 -0
  277. package/packages/arcgis-rest-portal/src/groups/remove.ts +32 -0
  278. package/packages/arcgis-rest-portal/src/groups/search.ts +47 -0
  279. package/packages/arcgis-rest-portal/src/groups/update-user-membership.ts +63 -0
  280. package/packages/arcgis-rest-portal/src/groups/update.ts +39 -0
  281. package/packages/arcgis-rest-portal/src/index.ts +70 -0
  282. package/packages/arcgis-rest-portal/src/items/add.ts +138 -0
  283. package/packages/arcgis-rest-portal/src/items/content.ts +67 -0
  284. package/packages/arcgis-rest-portal/src/items/create.ts +150 -0
  285. package/packages/arcgis-rest-portal/src/items/export.ts +80 -0
  286. package/packages/arcgis-rest-portal/src/items/get.ts +437 -0
  287. package/packages/arcgis-rest-portal/src/items/helpers.ts +292 -0
  288. package/packages/arcgis-rest-portal/src/items/protect.ts +41 -0
  289. package/packages/arcgis-rest-portal/src/items/reassign.ts +61 -0
  290. package/packages/arcgis-rest-portal/src/items/remove.ts +141 -0
  291. package/packages/arcgis-rest-portal/src/items/search.ts +25 -0
  292. package/packages/arcgis-rest-portal/src/items/update.ts +185 -0
  293. package/packages/arcgis-rest-portal/src/items/upload.ts +125 -0
  294. package/packages/arcgis-rest-portal/src/orgs/notification.ts +131 -0
  295. package/packages/arcgis-rest-portal/src/services/get-unique-service-name.ts +35 -0
  296. package/packages/arcgis-rest-portal/src/services/is-service-name-available.ts +30 -0
  297. package/packages/arcgis-rest-portal/src/sharing/access.ts +84 -0
  298. package/packages/arcgis-rest-portal/src/sharing/helpers.ts +81 -0
  299. package/packages/arcgis-rest-portal/src/sharing/is-item-shared-with-group.ts +42 -0
  300. package/packages/arcgis-rest-portal/src/sharing/share-item-with-group.ts +340 -0
  301. package/packages/arcgis-rest-portal/src/sharing/unshare-item-with-group.ts +105 -0
  302. package/packages/arcgis-rest-portal/src/users/get-user-tags.ts +52 -0
  303. package/packages/arcgis-rest-portal/src/users/get-user-url.ts +18 -0
  304. package/packages/arcgis-rest-portal/src/users/get-user.ts +58 -0
  305. package/packages/arcgis-rest-portal/src/users/invitation.ts +156 -0
  306. package/packages/arcgis-rest-portal/src/users/notification.ts +68 -0
  307. package/packages/arcgis-rest-portal/src/users/search-users.ts +37 -0
  308. package/packages/arcgis-rest-portal/src/users/update.ts +66 -0
  309. package/packages/arcgis-rest-portal/src/util/SearchQueryBuilder.ts +391 -0
  310. package/packages/arcgis-rest-portal/src/util/array.ts +16 -0
  311. package/packages/arcgis-rest-portal/src/util/generic-search.ts +114 -0
  312. package/packages/arcgis-rest-portal/src/util/get-portal-settings.ts +45 -0
  313. package/packages/arcgis-rest-portal/src/util/get-portal-url.ts +28 -0
  314. package/packages/arcgis-rest-portal/src/util/get-portal.ts +53 -0
  315. package/packages/arcgis-rest-portal/src/util/get-subscription-info.ts +43 -0
  316. package/packages/arcgis-rest-portal/src/util/scrub-control-chars.ts +13 -0
  317. package/packages/arcgis-rest-portal/src/util/search.ts +47 -0
  318. package/packages/arcgis-rest-portal/test/groups/add-users.test.ts +239 -0
  319. package/packages/arcgis-rest-portal/test/groups/crud.test.ts +180 -0
  320. package/packages/arcgis-rest-portal/test/groups/get.test.ts +176 -0
  321. package/packages/arcgis-rest-portal/test/groups/invite-users.test.ts +146 -0
  322. package/packages/arcgis-rest-portal/test/groups/join.test.ts +72 -0
  323. package/packages/arcgis-rest-portal/test/groups/notification.test.ts +112 -0
  324. package/packages/arcgis-rest-portal/test/groups/protect.test.ts +72 -0
  325. package/packages/arcgis-rest-portal/test/groups/remove-users.test.ts +140 -0
  326. package/packages/arcgis-rest-portal/test/groups/search.test.ts +151 -0
  327. package/packages/arcgis-rest-portal/test/groups/update-user-membership.test.ts +62 -0
  328. package/packages/arcgis-rest-portal/test/items/add.test.ts +323 -0
  329. package/packages/arcgis-rest-portal/test/items/content.test.ts +156 -0
  330. package/packages/arcgis-rest-portal/test/items/create.test.ts +400 -0
  331. package/packages/arcgis-rest-portal/test/items/export.test.ts +122 -0
  332. package/packages/arcgis-rest-portal/test/items/get.test.ts +583 -0
  333. package/packages/arcgis-rest-portal/test/items/helpers.test.ts +60 -0
  334. package/packages/arcgis-rest-portal/test/items/protect.test.ts +122 -0
  335. package/packages/arcgis-rest-portal/test/items/reassign.test.ts +131 -0
  336. package/packages/arcgis-rest-portal/test/items/remove.test.ts +261 -0
  337. package/packages/arcgis-rest-portal/test/items/search.test.ts +322 -0
  338. package/packages/arcgis-rest-portal/test/items/update.test.ts +556 -0
  339. package/packages/arcgis-rest-portal/test/items/upload.test.ts +282 -0
  340. package/packages/arcgis-rest-portal/test/mocks/groups/responses.ts +208 -0
  341. package/packages/arcgis-rest-portal/test/mocks/items/foo.zip +0 -0
  342. package/packages/arcgis-rest-portal/test/mocks/items/item.ts +526 -0
  343. package/packages/arcgis-rest-portal/test/mocks/items/resources.ts +38 -0
  344. package/packages/arcgis-rest-portal/test/mocks/items/search.ts +121 -0
  345. package/packages/arcgis-rest-portal/test/mocks/portal/response.ts +126 -0
  346. package/packages/arcgis-rest-portal/test/mocks/portal/settings-response.ts +56 -0
  347. package/packages/arcgis-rest-portal/test/mocks/sharing/sharing.ts +18 -0
  348. package/packages/arcgis-rest-portal/test/mocks/users/invitation.ts +70 -0
  349. package/packages/arcgis-rest-portal/test/mocks/users/notification.ts +34 -0
  350. package/packages/arcgis-rest-portal/test/mocks/users/user-search.ts +388 -0
  351. package/packages/arcgis-rest-portal/test/mocks/users/user-tags.ts +5 -0
  352. package/packages/arcgis-rest-portal/test/mocks/users/user.ts +174 -0
  353. package/packages/arcgis-rest-portal/test/orgs/notification.test.ts +144 -0
  354. package/packages/arcgis-rest-portal/test/services/get-unique-service-name.test.ts +59 -0
  355. package/packages/arcgis-rest-portal/test/services/is-service-name-available.test.ts +46 -0
  356. package/packages/arcgis-rest-portal/test/sharing/access.test.ts +162 -0
  357. package/packages/arcgis-rest-portal/test/sharing/helpers.test.ts +55 -0
  358. package/packages/arcgis-rest-portal/test/sharing/share-item-with-group.test.ts +1382 -0
  359. package/packages/arcgis-rest-portal/test/sharing/unshare-item-with-group.test.ts +288 -0
  360. package/packages/arcgis-rest-portal/test/users/get-user-tags.test.ts +71 -0
  361. package/packages/arcgis-rest-portal/test/users/get-user-url.test.ts +40 -0
  362. package/packages/arcgis-rest-portal/test/users/get-user.test.ts +90 -0
  363. package/packages/arcgis-rest-portal/test/users/invitation.test.ts +127 -0
  364. package/packages/arcgis-rest-portal/test/users/notification.test.ts +77 -0
  365. package/packages/arcgis-rest-portal/test/users/search.test.ts +42 -0
  366. package/packages/arcgis-rest-portal/test/users/update.test.ts +151 -0
  367. package/packages/arcgis-rest-portal/test/util/SearchQueryBuilder.test.ts +345 -0
  368. package/packages/arcgis-rest-portal/test/util/array.test.ts +30 -0
  369. package/packages/arcgis-rest-portal/test/util/get-portal-settings.test.ts +68 -0
  370. package/packages/arcgis-rest-portal/test/util/get-portal-url.test.ts +37 -0
  371. package/packages/arcgis-rest-portal/test/util/portal.test.ts +148 -0
  372. package/packages/arcgis-rest-portal/test/util/scrub-control-chars.test.ts +22 -0
  373. package/packages/arcgis-rest-portal/tsconfig.json +6 -0
  374. package/packages/arcgis-rest-request/README.md +72 -0
  375. package/packages/arcgis-rest-request/package-lock.json +13 -0
  376. package/packages/arcgis-rest-request/package.json +60 -0
  377. package/packages/arcgis-rest-request/src/index.ts +25 -0
  378. package/packages/arcgis-rest-request/src/request.ts +433 -0
  379. package/packages/arcgis-rest-request/src/utils/ArcGISRequestError.ts +76 -0
  380. package/packages/arcgis-rest-request/src/utils/ErrorTypes.ts +29 -0
  381. package/packages/arcgis-rest-request/src/utils/GrantTypes.ts +5 -0
  382. package/packages/arcgis-rest-request/src/utils/HTTPMethods.ts +6 -0
  383. package/packages/arcgis-rest-request/src/utils/IAuthenticationManager.ts +22 -0
  384. package/packages/arcgis-rest-request/src/utils/IFetchTokenParams.ts +11 -0
  385. package/packages/arcgis-rest-request/src/utils/IGenerateTokenParams.ts +9 -0
  386. package/packages/arcgis-rest-request/src/utils/IParamBuilder.ts +3 -0
  387. package/packages/arcgis-rest-request/src/utils/IParams.ts +6 -0
  388. package/packages/arcgis-rest-request/src/utils/IParamsBuilder.ts +5 -0
  389. package/packages/arcgis-rest-request/src/utils/IRequestOptions.ts +54 -0
  390. package/packages/arcgis-rest-request/src/utils/ITokenRequestOptions.ts +9 -0
  391. package/packages/arcgis-rest-request/src/utils/ResponseFormats.ts +10 -0
  392. package/packages/arcgis-rest-request/src/utils/append-custom-params.ts +49 -0
  393. package/packages/arcgis-rest-request/src/utils/clean-url.ts +20 -0
  394. package/packages/arcgis-rest-request/src/utils/decode-query-string.ts +27 -0
  395. package/packages/arcgis-rest-request/src/utils/encode-form-data.ts +38 -0
  396. package/packages/arcgis-rest-request/src/utils/encode-query-string.ts +35 -0
  397. package/packages/arcgis-rest-request/src/utils/process-params.ts +109 -0
  398. package/packages/arcgis-rest-request/src/utils/retryAuthError.ts +10 -0
  399. package/packages/arcgis-rest-request/src/utils/warn.ts +11 -0
  400. package/packages/arcgis-rest-request/src/utils/with-options.ts +48 -0
  401. package/packages/arcgis-rest-request/test/mocks/errors.ts +76 -0
  402. package/packages/arcgis-rest-request/test/mocks/geojson-feature-collection.ts +13 -0
  403. package/packages/arcgis-rest-request/test/mocks/param-builder.ts +7 -0
  404. package/packages/arcgis-rest-request/test/mocks/sharing-rest-info.ts +41 -0
  405. package/packages/arcgis-rest-request/test/mocks/webmap.ts +41 -0
  406. package/packages/arcgis-rest-request/test/request.test.ts +621 -0
  407. package/packages/arcgis-rest-request/test/utils/ArcGISAuthError.test.ts +191 -0
  408. package/packages/arcgis-rest-request/test/utils/ArcGISRequestError.test.ts +51 -0
  409. package/packages/arcgis-rest-request/test/utils/check-for-errors.test.ts +111 -0
  410. package/packages/arcgis-rest-request/test/utils/clean-url.test.ts +50 -0
  411. package/packages/arcgis-rest-request/test/utils/encode-form-data.test.ts +133 -0
  412. package/packages/arcgis-rest-request/test/utils/encode-query-string.test.ts +18 -0
  413. package/packages/arcgis-rest-request/test/utils/process-params.test.ts +205 -0
  414. package/packages/arcgis-rest-request/test/utils/with-options.test.ts +133 -0
  415. package/packages/arcgis-rest-request/tsconfig.json +4 -0
  416. package/packages/arcgis-rest-routing/README.md +75 -0
  417. package/packages/arcgis-rest-routing/package-lock.json +43 -0
  418. package/packages/arcgis-rest-routing/package.json +65 -0
  419. package/packages/arcgis-rest-routing/src/closestFacility.ts +225 -0
  420. package/packages/arcgis-rest-routing/src/helpers.ts +104 -0
  421. package/packages/arcgis-rest-routing/src/index.ts +14 -0
  422. package/packages/arcgis-rest-routing/src/originDestinationMatrix.ts +223 -0
  423. package/packages/arcgis-rest-routing/src/serviceArea.ts +173 -0
  424. package/packages/arcgis-rest-routing/src/solveRoute.ts +180 -0
  425. package/packages/arcgis-rest-routing/test/closestFacility.test.ts +683 -0
  426. package/packages/arcgis-rest-routing/test/mocks/inputs.ts +132 -0
  427. package/packages/arcgis-rest-routing/test/mocks/responses.ts +13322 -0
  428. package/packages/arcgis-rest-routing/test/originDestinationMatrix.test.ts +797 -0
  429. package/packages/arcgis-rest-routing/test/serviceArea.test.ts +601 -0
  430. package/packages/arcgis-rest-routing/test/solveRoute.test.ts +677 -0
  431. package/packages/arcgis-rest-routing/tsconfig.json +6 -0
  432. package/packages/arcgis-rest-service-admin/README.md +73 -0
  433. package/packages/arcgis-rest-service-admin/package-lock.json +11 -0
  434. package/packages/arcgis-rest-service-admin/package.json +65 -0
  435. package/packages/arcgis-rest-service-admin/src/addTo.ts +70 -0
  436. package/packages/arcgis-rest-service-admin/src/create.ts +189 -0
  437. package/packages/arcgis-rest-service-admin/src/get-service-admin-info.ts +34 -0
  438. package/packages/arcgis-rest-service-admin/src/get-view-sources.ts +20 -0
  439. package/packages/arcgis-rest-service-admin/src/index.ts +14 -0
  440. package/packages/arcgis-rest-service-admin/src/update.ts +50 -0
  441. package/packages/arcgis-rest-service-admin/test/addTo.test.ts +350 -0
  442. package/packages/arcgis-rest-service-admin/test/create.test.ts +294 -0
  443. package/packages/arcgis-rest-service-admin/test/get-service-admin-info.test.ts +37 -0
  444. package/packages/arcgis-rest-service-admin/test/get-view-sources.test.ts +40 -0
  445. package/packages/arcgis-rest-service-admin/test/mocks/layerDefinition.ts +79 -0
  446. package/packages/arcgis-rest-service-admin/test/mocks/service.ts +81 -0
  447. package/packages/arcgis-rest-service-admin/test/update.test.ts +115 -0
  448. package/packages/arcgis-rest-service-admin/tsconfig.json +5 -0
  449. package/packages/arcgis-rest-types/README.md +66 -0
  450. package/packages/arcgis-rest-types/package-lock.json +5 -0
  451. package/packages/arcgis-rest-types/package.json +54 -0
  452. package/packages/arcgis-rest-types/src/feature.ts +42 -0
  453. package/packages/arcgis-rest-types/src/geometry.ts +272 -0
  454. package/packages/arcgis-rest-types/src/group.ts +72 -0
  455. package/packages/arcgis-rest-types/src/index.ts +9 -0
  456. package/packages/arcgis-rest-types/src/item.ts +81 -0
  457. package/packages/arcgis-rest-types/src/service.ts +156 -0
  458. package/packages/arcgis-rest-types/src/statisticDefinition.ts +33 -0
  459. package/packages/arcgis-rest-types/src/symbol.ts +170 -0
  460. package/packages/arcgis-rest-types/src/user.ts +49 -0
  461. package/packages/arcgis-rest-types/src/webmap.ts +1405 -0
  462. package/packages/arcgis-rest-types/tsconfig.json +10 -0
  463. package/support/changelog.js +393 -0
  464. package/support/deploy-doc-site.js +16 -0
  465. package/support/dev.sh +6 -0
  466. package/support/publish.sh +47 -0
  467. package/support/test-helpers.js +9 -0
  468. package/tsconfig.json +63 -0
  469. package/umd-base-profile.js +81 -0
  470. package/umd-production-profile.js +13 -0
@@ -0,0 +1,2430 @@
1
+ /* Copyright (c) 2018 Environmental Systems Research Institute, Inc.
2
+ * Apache-2.0 */
3
+
4
+ /* tslint:disable:no-empty */
5
+ import { UserSession } from "../src/index";
6
+ import { ICredential } from "../src/UserSession";
7
+
8
+ import {
9
+ request,
10
+ ArcGISRequestError,
11
+ ArcGISAuthError,
12
+ ErrorTypes,
13
+ } from "@esri/arcgis-rest-request";
14
+ import * as fetchMock from "fetch-mock";
15
+ import { YESTERDAY, TOMORROW } from "./utils";
16
+
17
+ describe("UserSession", () => {
18
+ afterEach(fetchMock.restore);
19
+
20
+ it("should serialize to and from JSON", () => {
21
+ const session = new UserSession({
22
+ clientId: "clientId",
23
+ redirectUri: "https://example-app.com/redirect-uri",
24
+ token: "token",
25
+ tokenExpires: TOMORROW,
26
+ refreshToken: "refreshToken",
27
+ refreshTokenExpires: TOMORROW,
28
+ refreshTokenTTL: 1440,
29
+ username: "c@sey",
30
+ password: "123456",
31
+ });
32
+
33
+ const session2 = UserSession.deserialize(session.serialize());
34
+
35
+ expect(session2.clientId).toEqual("clientId");
36
+ expect(session2.redirectUri).toEqual(
37
+ "https://example-app.com/redirect-uri"
38
+ );
39
+ expect(session2.ssl).toBe(undefined);
40
+ expect(session2.token).toEqual("token");
41
+ expect(session2.tokenExpires).toEqual(TOMORROW);
42
+ expect(session2.refreshToken).toEqual("refreshToken");
43
+ expect(session2.refreshTokenExpires).toEqual(TOMORROW);
44
+ expect(session2.username).toEqual("c@sey");
45
+ expect(session2.password).toEqual("123456");
46
+ expect(session2.tokenDuration).toEqual(20160);
47
+ expect(session2.refreshTokenTTL).toEqual(1440);
48
+ });
49
+
50
+ describe(".getToken()", () => {
51
+ it("should return unexpired tokens for trusted arcgis.com domains", (done) => {
52
+ const session = new UserSession({
53
+ clientId: "id",
54
+ token: "token",
55
+ tokenExpires: TOMORROW,
56
+ });
57
+
58
+ Promise.all([
59
+ session.getToken("https://www.arcgis.com/sharing/rest/portals/self"),
60
+ session.getToken(
61
+ "https://services1.arcgis.com/MOCK_ORG/arcgis/rest/services/Private_Service/FeatureServer"
62
+ ),
63
+ ])
64
+ .then(([token1, token2]) => {
65
+ expect(token1).toBe("token");
66
+ expect(token2).toBe("token");
67
+ done();
68
+ })
69
+ .catch((e) => {
70
+ fail(e);
71
+ });
72
+ });
73
+
74
+ it("should return unexpired tokens when an org url is passed", (done) => {
75
+ const session = new UserSession({
76
+ clientId: "id",
77
+ token: "token",
78
+ tokenExpires: TOMORROW,
79
+ portal: "https://custom.maps.arcgis.com/sharing/rest",
80
+ });
81
+
82
+ session
83
+ .getToken(
84
+ "https://services1.arcgis.com/MOCK_ORG/arcgis/rest/services/Private_Service/FeatureServer"
85
+ )
86
+ .then((token) => {
87
+ expect(token).toBe("token");
88
+ done();
89
+ })
90
+ .catch((e) => {
91
+ fail(e);
92
+ });
93
+ });
94
+
95
+ it("should return unexpired tokens when an org url is passed on other ArcGIS Online environments", (done) => {
96
+ const session = new UserSession({
97
+ clientId: "id",
98
+ token: "token",
99
+ tokenExpires: TOMORROW,
100
+ portal: "https://custom.mapsdev.arcgis.com/sharing/rest",
101
+ });
102
+
103
+ session
104
+ .getToken(
105
+ "https://services1dev.arcgis.com/MOCK_ORG/arcgis/rest/services/Private_Service/FeatureServer"
106
+ )
107
+ .then((token) => {
108
+ expect(token).toBe("token");
109
+ done();
110
+ })
111
+ .catch((e) => {
112
+ fail(e);
113
+ });
114
+ });
115
+
116
+ it("should return unexpired tokens when there is an http/https mismatch", (done) => {
117
+ const session = new UserSession({
118
+ clientId: "id",
119
+ token: "token",
120
+ tokenExpires: TOMORROW,
121
+ portal: "http://custom.mapsdev.arcgis.com/sharing/rest",
122
+ });
123
+
124
+ session
125
+ .getToken(
126
+ "https://services1dev.arcgis.com/MOCK_ORG/arcgis/rest/services/Private_Service/FeatureServer"
127
+ )
128
+ .then((token) => {
129
+ expect(token).toBe("token");
130
+ done();
131
+ })
132
+ .catch((e) => {
133
+ fail(e);
134
+ });
135
+ });
136
+
137
+ it("should return unexpired tokens for the configured portal domain", (done) => {
138
+ const session = new UserSession({
139
+ clientId: "id",
140
+ token: "token",
141
+ tokenExpires: TOMORROW,
142
+ portal: "https://gis.city.gov/sharing/rest",
143
+ });
144
+
145
+ session
146
+ .getToken("https://gis.city.gov/sharing/rest/portals/self")
147
+ .then((token) => {
148
+ expect(token).toBe("token");
149
+ done();
150
+ })
151
+ .catch((e) => {
152
+ fail(e);
153
+ });
154
+ });
155
+
156
+ it("should return unexpired tokens for the configured portal domain, regardless of CASING", (done) => {
157
+ // This was a real configuration discovered on a portal instance
158
+ const session = new UserSession({
159
+ clientId: "id",
160
+ token: "token",
161
+ tokenExpires: TOMORROW,
162
+ portal: "https://pnp00035.esri.com/sharing/rest",
163
+ });
164
+
165
+ session
166
+ .getToken("https://PNP00035.esri.com/sharing/rest/portals/self")
167
+ .then((token) => {
168
+ expect(token).toBe("token");
169
+ done();
170
+ })
171
+ .catch((e) => {
172
+ fail(e);
173
+ });
174
+ });
175
+
176
+ it("should fetch token when contacting a server that is federated, even if on same domain, regardless of domain casing", (done) => {
177
+ // This was a real configuration discovered on a portal instance
178
+ // apparently when federating servers, the UI does not force the
179
+ // server url to lowercase, and this any feature service items generated
180
+ // will have the server name using the casing the admin entered.
181
+ // this is just a test to ensure that the mis-matched casing does not
182
+ // break the federation flow.
183
+ const session = new UserSession({
184
+ clientId: "id",
185
+ token: "existing-session-token",
186
+ refreshToken: "refresh",
187
+ tokenExpires: TOMORROW,
188
+ portal: "https://pnp00035.esri.com/portal/sharing/rest",
189
+ });
190
+
191
+ fetchMock.postOnce("https://pnp00035.esri.com/server/rest/info", {
192
+ currentVersion: 10.61,
193
+ fullVersion: "10.6.1",
194
+ owningSystemUrl: "https://pnp00035.esri.com/portal",
195
+ authInfo: {
196
+ isTokenBasedSecurity: true,
197
+ tokenServicesUrl:
198
+ "https://pnp00035.esri.com/portal/sharing/rest/generateToken",
199
+ },
200
+ });
201
+
202
+ fetchMock.getOnce(
203
+ "https://pnp00035.esri.com/portal/sharing/rest/portals/self?f=json&token=existing-session-token",
204
+ {
205
+ authorizedCrossOriginDomains: [],
206
+ }
207
+ );
208
+
209
+ fetchMock.postOnce("https://pnp00035.esri.com/portal/sharing/rest/info", {
210
+ owningSystemUrl: "https://pnp00035.esri.com/portal",
211
+ authInfo: {
212
+ tokenServicesUrl:
213
+ "https://pnp00035.esri.com/portal/sharing/rest/generateToken",
214
+ isTokenBasedSecurity: true,
215
+ },
216
+ });
217
+
218
+ fetchMock.postOnce(
219
+ "https://pnp00035.esri.com/portal/sharing/rest/generateToken",
220
+ {
221
+ token: "new-server-token",
222
+ expires: TOMORROW,
223
+ }
224
+ );
225
+
226
+ // request the token twice, for the same domain, but with different casing
227
+ // and we expect a single POST to generate a token once
228
+ session
229
+ .getToken(
230
+ "https://PNP00035.esri.com/server/rest/services/Hosted/perimeters_dd83/FeatureServer"
231
+ )
232
+ .then((token) => {
233
+ expect(token).toBe("new-server-token");
234
+ return session.getToken(
235
+ "https://pnp00035.esri.com/server/rest/services/Hosted/otherService/FeatureServer"
236
+ );
237
+ })
238
+ .then((token) => {
239
+ expect(token).toBe("new-server-token");
240
+ done();
241
+ })
242
+ .catch((e) => {
243
+ fail(e);
244
+ });
245
+ });
246
+
247
+ it("should fetch new tokens when tokens for trusted arcgis.com domains are expired", (done) => {
248
+ const session = new UserSession({
249
+ clientId: "id",
250
+ token: "token",
251
+ refreshToken: "refresh",
252
+ tokenExpires: YESTERDAY,
253
+ });
254
+
255
+ fetchMock.mock(
256
+ "https://www.arcgis.com/sharing/rest/oauth2/token",
257
+ {
258
+ access_token: "new",
259
+ expires_in: 1800,
260
+ username: "c@sey",
261
+ },
262
+ { repeat: 2, method: "POST" }
263
+ );
264
+
265
+ Promise.all([
266
+ session.getToken("https://www.arcgis.com/sharing/rest/portals/self"),
267
+ session.getToken(
268
+ "https://services1.arcgis.com/MOCK_ORG/arcgis/rest/services/Private_Service/FeatureServer"
269
+ ),
270
+ ])
271
+ .then(([token1, token2]) => {
272
+ expect(token1).toBe("new");
273
+ expect(token2).toBe("new");
274
+ done();
275
+ })
276
+ .catch((e) => {
277
+ fail(e);
278
+ });
279
+ });
280
+
281
+ it("should pass through a token when no token expiration is present", (done) => {
282
+ const session = new UserSession({
283
+ token: "token",
284
+ });
285
+
286
+ session
287
+ .getToken("https://www.arcgis.com/sharing/rest/portals/self")
288
+ .then((token1) => {
289
+ expect(token1).toBe("token");
290
+ done();
291
+ })
292
+ .catch((e) => {
293
+ fail(e);
294
+ });
295
+ });
296
+
297
+ it("should generate a token for an untrusted, federated server", (done) => {
298
+ const session = new UserSession({
299
+ clientId: "id",
300
+ token: "token",
301
+ refreshToken: "refresh",
302
+ tokenExpires: TOMORROW,
303
+ portal: "https://gis.city.gov/sharing/rest",
304
+ });
305
+
306
+ fetchMock.postOnce("https://gisservices.city.gov/public/rest/info", {
307
+ currentVersion: 10.51,
308
+ fullVersion: "10.5.1.120",
309
+ owningSystemUrl: "https://gis.city.gov",
310
+ authInfo: {
311
+ isTokenBasedSecurity: true,
312
+ tokenServicesUrl: "https://gis.city.gov/sharing/generateToken",
313
+ },
314
+ });
315
+
316
+ fetchMock.getOnce(
317
+ "https://gis.city.gov/sharing/rest/portals/self?f=json&token=token",
318
+ {
319
+ authorizedCrossOriginDomains: [],
320
+ }
321
+ );
322
+
323
+ fetchMock.postOnce("https://gis.city.gov/sharing/rest/info", {
324
+ owningSystemUrl: "http://gis.city.gov",
325
+ authInfo: {
326
+ tokenServicesUrl: "https://gis.city.gov/sharing/generateToken",
327
+ isTokenBasedSecurity: true,
328
+ },
329
+ });
330
+
331
+ fetchMock.postOnce("https://gis.city.gov/sharing/generateToken", {
332
+ token: "serverToken",
333
+ expires: TOMORROW,
334
+ });
335
+
336
+ session
337
+ .getToken(
338
+ "https://gisservices.city.gov/public/rest/services/trees/FeatureServer/0/query"
339
+ )
340
+ .then((token) => {
341
+ expect(token).toBe("serverToken");
342
+ return session.getToken(
343
+ "https://gisservices.city.gov/public/rest/services/trees/FeatureServer/0/query"
344
+ );
345
+ })
346
+ .then((token) => {
347
+ expect(token).toBe("serverToken");
348
+ done();
349
+ })
350
+ .catch((e) => {
351
+ fail(e);
352
+ });
353
+ });
354
+
355
+ it("should generate a token for an untrusted, federated server admin call", (done) => {
356
+ const session = new UserSession({
357
+ clientId: "id",
358
+ token: "token",
359
+ refreshToken: "refresh",
360
+ tokenExpires: TOMORROW,
361
+ portal: "https://gis.city.gov/sharing/rest",
362
+ });
363
+
364
+ fetchMock.postOnce("https://gisservices.city.gov/public/rest/info", {
365
+ currentVersion: 10.51,
366
+ fullVersion: "10.5.1.120",
367
+ owningSystemUrl: "https://gis.city.gov",
368
+ authInfo: {
369
+ isTokenBasedSecurity: true,
370
+ tokenServicesUrl: "https://gis.city.gov/sharing/generateToken",
371
+ },
372
+ });
373
+
374
+ fetchMock.getOnce(
375
+ "https://gis.city.gov/sharing/rest/portals/self?f=json&token=token",
376
+ {
377
+ authorizedCrossOriginDomains: [],
378
+ }
379
+ );
380
+
381
+ fetchMock.postOnce("https://gis.city.gov/sharing/rest/info", {
382
+ owningSystemUrl: "http://gis.city.gov",
383
+ authInfo: {
384
+ tokenServicesUrl: "https://gis.city.gov/sharing/generateToken",
385
+ isTokenBasedSecurity: true,
386
+ },
387
+ });
388
+
389
+ fetchMock.postOnce("https://gis.city.gov/sharing/generateToken", {
390
+ token: "serverToken",
391
+ expires: TOMORROW,
392
+ });
393
+
394
+ session
395
+ .getToken(
396
+ "https://gisservices.city.gov/public/rest/admin/services/trees/FeatureServer/addToDefinition"
397
+ )
398
+ .then((token) => {
399
+ expect(token).toBe("serverToken");
400
+ return session.getToken(
401
+ "https://gisservices.city.gov/public/rest/admin/services/trees/FeatureServer/addToDefinition"
402
+ );
403
+ })
404
+ .then((token) => {
405
+ expect(token).toBe("serverToken");
406
+ done();
407
+ })
408
+ .catch((e) => {
409
+ fail(e);
410
+ });
411
+ });
412
+
413
+ it("should generate a token for an untrusted, federated server with user credentials", (done) => {
414
+ const session = new UserSession({
415
+ username: "c@sey",
416
+ password: "jones",
417
+ portal: "https://gis.city.gov/sharing/rest",
418
+ });
419
+
420
+ fetchMock.postOnce("https://gisservices.city.gov/public/rest/info", {
421
+ currentVersion: 10.51,
422
+ fullVersion: "10.5.1.120",
423
+ owningSystemUrl: "https://gis.city.gov",
424
+ authInfo: {
425
+ isTokenBasedSecurity: true,
426
+ tokenServicesUrl: "https://gis.city.gov/sharing/generateToken",
427
+ },
428
+ });
429
+
430
+ fetchMock.postOnce("https://gis.city.gov/sharing/rest/generateToken", {
431
+ token: "portalToken",
432
+ });
433
+
434
+ fetchMock.getOnce(
435
+ "https://gis.city.gov/sharing/rest/portals/self?f=json&token=portalToken",
436
+ {
437
+ authorizedCrossOriginDomains: [],
438
+ }
439
+ );
440
+
441
+ fetchMock.postOnce("https://gis.city.gov/sharing/rest/info", {
442
+ owningSystemUrl: "http://gis.city.gov",
443
+ authInfo: {
444
+ tokenServicesUrl: "https://gis.city.gov/sharing/generateToken",
445
+ isTokenBasedSecurity: true,
446
+ },
447
+ });
448
+
449
+ fetchMock.postOnce("https://gis.city.gov/sharing/generateToken", {
450
+ token: "serverToken",
451
+ expires: TOMORROW,
452
+ });
453
+
454
+ session
455
+ .getToken(
456
+ "https://gisservices.city.gov/public/rest/services/trees/FeatureServer/0/query"
457
+ )
458
+ .then((token) => {
459
+ expect(token).toBe("serverToken");
460
+ done();
461
+ })
462
+ .catch((e) => {
463
+ fail(e);
464
+ });
465
+ });
466
+
467
+ it("should only make 1 token request to an untrusted portal for similar URLs", (done) => {
468
+ const session = new UserSession({
469
+ clientId: "id",
470
+ token: "token",
471
+ refreshToken: "refresh",
472
+ tokenExpires: TOMORROW,
473
+ portal: "https://gis.city.gov/sharing/rest",
474
+ });
475
+
476
+ fetchMock.mock(
477
+ "https://gisservices.city.gov/public/rest/info",
478
+ {
479
+ currentVersion: 10.51,
480
+ fullVersion: "10.5.1.120",
481
+ owningSystemUrl: "https://gis.city.gov",
482
+ authInfo: {
483
+ isTokenBasedSecurity: true,
484
+ tokenServicesUrl: "https://gis.city.gov/sharing/generateToken",
485
+ },
486
+ },
487
+ { repeat: 1, method: "POST" }
488
+ );
489
+
490
+ fetchMock.getOnce(
491
+ "https://gis.city.gov/sharing/rest/portals/self?f=json&token=token",
492
+ {
493
+ authorizedCrossOriginDomains: [],
494
+ }
495
+ );
496
+
497
+ fetchMock.mock(
498
+ "https://gis.city.gov/sharing/rest/info",
499
+ {
500
+ owningSystemUrl: "http://gis.city.gov",
501
+ authInfo: {
502
+ tokenServicesUrl: "https://gis.city.gov/sharing/generateToken",
503
+ isTokenBasedSecurity: true,
504
+ },
505
+ },
506
+ { repeat: 1, method: "POST" }
507
+ );
508
+
509
+ fetchMock.mock(
510
+ "https://gis.city.gov/sharing/generateToken",
511
+ {
512
+ token: "serverToken",
513
+ expires: TOMORROW,
514
+ },
515
+ { repeat: 1, method: "POST" }
516
+ );
517
+
518
+ Promise.all([
519
+ session.getToken(
520
+ "https://gisservices.city.gov/public/rest/services/trees/FeatureServer/0/query"
521
+ ),
522
+ session.getToken(
523
+ "https://gisservices.city.gov/public/rest/services/trees/FeatureServer/0/query"
524
+ ),
525
+ ])
526
+ .then(([token1, token2]) => {
527
+ expect(token1).toBe("serverToken");
528
+ expect(token2).toBe("serverToken");
529
+ expect(
530
+ fetchMock.calls("https://gis.city.gov/sharing/generateToken").length
531
+ ).toBe(1);
532
+ done();
533
+ })
534
+ .catch((e) => {
535
+ fail(e);
536
+ });
537
+ });
538
+
539
+ it("should throw an ArcGISAuthError when the owning system doesn't match", (done) => {
540
+ const session = new UserSession({
541
+ clientId: "id",
542
+ token: "token",
543
+ refreshToken: "refresh",
544
+ tokenExpires: YESTERDAY,
545
+ });
546
+
547
+ // similates refreshing the token with the refresh token
548
+ fetchMock.postOnce("https://www.arcgis.com/sharing/rest/oauth2/token", {
549
+ access_token: "newToken",
550
+ expires_in: 60,
551
+ username: " c@sey",
552
+ });
553
+
554
+ fetchMock.getOnce(
555
+ "https://www.arcgis.com/sharing/rest/portals/self?f=json&token=newToken",
556
+ {
557
+ authorizedCrossOriginDomains: [],
558
+ }
559
+ );
560
+
561
+ fetchMock.post("https://gisservices.city.gov/public/rest/info", {
562
+ currentVersion: 10.51,
563
+ fullVersion: "10.5.1.120",
564
+ owningSystemUrl: "https://gis.city.gov",
565
+ authInfo: {
566
+ isTokenBasedSecurity: true,
567
+ tokenServicesUrl: "https://gis.city.gov/sharing/generateToken",
568
+ },
569
+ });
570
+
571
+ session
572
+ .getToken(
573
+ "https://gisservices.city.gov/public/rest/services/trees/FeatureServer/0/query"
574
+ )
575
+ .catch((e) => {
576
+ expect(e.name).toEqual(ErrorTypes.ArcGISAuthError);
577
+ expect(e.code).toEqual("NOT_FEDERATED");
578
+ expect(e.message).toEqual(
579
+ "NOT_FEDERATED: https://gisservices.city.gov/public/rest/services/trees/FeatureServer/0/query is not federated with https://www.arcgis.com/sharing/rest."
580
+ );
581
+ done();
582
+ });
583
+ });
584
+
585
+ it("should throw a fully hydrated ArcGISAuthError when no owning system is advertised", (done) => {
586
+ const session = new UserSession({
587
+ clientId: "id",
588
+ token: "token",
589
+ refreshToken: "refresh",
590
+ tokenExpires: YESTERDAY,
591
+ });
592
+
593
+ fetchMock.postOnce("https://www.arcgis.com/sharing/rest/oauth2/token", {
594
+ access_token: "newToken",
595
+ expires_in: 60,
596
+ username: " c@sey",
597
+ });
598
+
599
+ fetchMock.getOnce(
600
+ "https://www.arcgis.com/sharing/rest/portals/self?f=json&token=newToken",
601
+ {
602
+ authorizedCrossOriginDomains: [],
603
+ }
604
+ );
605
+
606
+ fetchMock.post("https://gisservices.city.gov/public/rest/info", {
607
+ currentVersion: 10.51,
608
+ fullVersion: "10.5.1.120",
609
+ });
610
+
611
+ fetchMock.post(
612
+ "https://gisservices.city.gov/public/rest/services/trees/FeatureServer/0/query",
613
+ {
614
+ error: {
615
+ code: 499,
616
+ message: "Token Required",
617
+ details: [],
618
+ },
619
+ }
620
+ );
621
+
622
+ request(
623
+ "https://gisservices.city.gov/public/rest/services/trees/FeatureServer/0/query",
624
+ {
625
+ authentication: session,
626
+ params: {
627
+ foo: "bar",
628
+ },
629
+ }
630
+ ).catch((e) => {
631
+ expect(e.name).toEqual(ErrorTypes.ArcGISAuthError);
632
+ expect(e.code).toEqual("NOT_FEDERATED");
633
+ expect(e.message).toEqual(
634
+ "NOT_FEDERATED: https://gisservices.city.gov/public/rest/services/trees/FeatureServer/0/query is not federated with any portal and is not explicitly trusted."
635
+ );
636
+ expect(e.url).toEqual(
637
+ "https://gisservices.city.gov/public/rest/services/trees/FeatureServer/0/query"
638
+ );
639
+ expect(e.options.params.foo).toEqual("bar");
640
+ done();
641
+ });
642
+ });
643
+
644
+ it("should not throw an ArcGISAuthError when the unfederated service is public", (done) => {
645
+ const session = new UserSession({
646
+ clientId: "id",
647
+ token: "token",
648
+ refreshToken: "refresh",
649
+ tokenExpires: YESTERDAY,
650
+ });
651
+
652
+ fetchMock.post("https://gisservices.city.gov/public/rest/info", {
653
+ currentVersion: 10.51,
654
+ fullVersion: "10.5.1.120",
655
+ });
656
+
657
+ fetchMock.postOnce("https://www.arcgis.com/sharing/rest/oauth2/token", {
658
+ access_token: "newToken",
659
+ expires_in: 60,
660
+ username: " c@sey",
661
+ });
662
+
663
+ fetchMock.getOnce(
664
+ "https://www.arcgis.com/sharing/rest/portals/self?f=json&token=newToken",
665
+ {
666
+ authorizedCrossOriginDomains: [],
667
+ }
668
+ );
669
+
670
+ fetchMock.post(
671
+ "https://gisservices.city.gov/public/rest/services/trees/FeatureServer/0/query",
672
+ {
673
+ count: 123,
674
+ }
675
+ );
676
+
677
+ request(
678
+ "https://gisservices.city.gov/public/rest/services/trees/FeatureServer/0/query",
679
+ {
680
+ authentication: session,
681
+ params: {
682
+ returnCount: true,
683
+ },
684
+ }
685
+ )
686
+ .then((res) => {
687
+ expect(res.count).toEqual(123);
688
+ done();
689
+ })
690
+ .catch((e) => {
691
+ fail(e);
692
+ });
693
+ });
694
+ });
695
+
696
+ describe(".refreshSession()", () => {
697
+ it("should refresh with a username and password if expired", (done) => {
698
+ const session = new UserSession({
699
+ username: "c@sey",
700
+ password: "123456",
701
+ });
702
+
703
+ fetchMock.postOnce("https://www.arcgis.com/sharing/rest/generateToken", {
704
+ token: "token",
705
+ expires: TOMORROW.getTime(),
706
+ username: " c@sey",
707
+ });
708
+
709
+ session
710
+ .refreshSession()
711
+ .then((s) => {
712
+ expect(s.token).toBe("token");
713
+ expect(s.tokenExpires).toEqual(TOMORROW);
714
+ done();
715
+ })
716
+ .catch((e) => {
717
+ fail(e);
718
+ });
719
+ });
720
+
721
+ it("should refresh with an unexpired refresh token", (done) => {
722
+ const session = new UserSession({
723
+ clientId: "clientId",
724
+ token: "token",
725
+ username: "c@sey",
726
+ refreshToken: "refreshToken",
727
+ refreshTokenExpires: TOMORROW,
728
+ });
729
+
730
+ fetchMock.postOnce("https://www.arcgis.com/sharing/rest/oauth2/token", {
731
+ access_token: "newToken",
732
+ expires_in: 60,
733
+ username: " c@sey",
734
+ });
735
+
736
+ session
737
+ .refreshSession()
738
+ .then((s) => {
739
+ expect(s.token).toBe("newToken");
740
+ expect(s.tokenExpires.getTime()).toBeGreaterThan(Date.now());
741
+ done();
742
+ })
743
+ .catch((e) => {
744
+ fail(e);
745
+ });
746
+ });
747
+
748
+ it("should refresh with an expired refresh token", (done) => {
749
+ const session = new UserSession({
750
+ clientId: "clientId",
751
+ token: "token",
752
+ username: "c@sey",
753
+ refreshToken: "refreshToken",
754
+ refreshTokenExpires: YESTERDAY,
755
+ redirectUri: "https://example-app.com/redirect-uri",
756
+ });
757
+
758
+ fetchMock.postOnce("https://www.arcgis.com/sharing/rest/oauth2/token", {
759
+ access_token: "newToken",
760
+ expires_in: 60,
761
+ username: " c@sey",
762
+ refresh_token: "newRefreshToken",
763
+ });
764
+
765
+ session
766
+ .refreshSession()
767
+ .then((s) => {
768
+ expect(s.token).toBe("newToken");
769
+ expect(s.tokenExpires.getTime()).toBeGreaterThan(Date.now());
770
+ expect(s.refreshToken).toBe("newRefreshToken");
771
+ expect(s.refreshTokenExpires.getTime()).toBeGreaterThan(Date.now());
772
+ done();
773
+ })
774
+ .catch((e) => {
775
+ fail(e);
776
+ });
777
+ });
778
+
779
+ it("should reject if we cannot refresh the token", (done) => {
780
+ const session = new UserSession({
781
+ clientId: "clientId",
782
+ token: "token",
783
+ username: "c@sey",
784
+ });
785
+
786
+ session.refreshSession().catch((e) => {
787
+ expect(e instanceof ArcGISAuthError).toBeTruthy();
788
+ expect(e.name).toBe("ArcGISAuthError");
789
+ expect(e.message).toBe("Unable to refresh token.");
790
+ done();
791
+ });
792
+ });
793
+
794
+ it("should only make 1 token request to the portal for similar URLs", (done) => {
795
+ const session = new UserSession({
796
+ clientId: "id",
797
+ token: "token",
798
+ refreshToken: "refresh",
799
+ tokenExpires: YESTERDAY,
800
+ });
801
+
802
+ fetchMock.mock(
803
+ "https://www.arcgis.com/sharing/rest/oauth2/token",
804
+ {
805
+ access_token: "new",
806
+ expires_in: 1800,
807
+ username: "c@sey",
808
+ },
809
+ { repeat: 1, method: "POST" }
810
+ );
811
+
812
+ Promise.all([
813
+ session.getToken("https://www.arcgis.com/sharing/rest/portals/self"),
814
+ session.getToken("https://www.arcgis.com/sharing/rest/portals/self"),
815
+ ])
816
+ .then(([token1, token2]) => {
817
+ expect(token1).toBe("new");
818
+ expect(token2).toBe("new");
819
+ expect(
820
+ fetchMock.calls("https://www.arcgis.com/sharing/rest/oauth2/token")
821
+ .length
822
+ ).toBe(1);
823
+ done();
824
+ })
825
+ .catch((e) => {
826
+ fail(e);
827
+ });
828
+ });
829
+ });
830
+
831
+ describe(".beginOAuth2()", () => {
832
+ it("should authorize via a popup", (done) => {
833
+ const MockWindow: any = {
834
+ open: jasmine.createSpy("spy"),
835
+ };
836
+
837
+ UserSession.beginOAuth2(
838
+ {
839
+ clientId: "clientId123",
840
+ redirectUri: "http://example-app.com/redirect",
841
+ state: "abc123",
842
+ },
843
+ MockWindow
844
+ )
845
+ .then((session) => {
846
+ expect(session.token).toBe("token");
847
+ expect(session.username).toBe("c@sey");
848
+ expect(session.ssl).toBe(true);
849
+ expect(session.tokenExpires).toEqual(TOMORROW);
850
+ done();
851
+ })
852
+ .catch((e) => {
853
+ fail(e);
854
+ });
855
+
856
+ expect(MockWindow.open).toHaveBeenCalledWith(
857
+ "https://www.arcgis.com/sharing/rest/oauth2/authorize?client_id=clientId123&response_type=token&expiration=20160&redirect_uri=http%3A%2F%2Fexample-app.com%2Fredirect&state=abc123&locale=",
858
+ "oauth-window",
859
+ "height=400,width=600,menubar=no,location=yes,resizable=yes,scrollbars=yes,status=yes"
860
+ );
861
+
862
+ MockWindow.__ESRI_REST_AUTH_HANDLER_clientId123(
863
+ JSON.stringify(undefined),
864
+ JSON.stringify({
865
+ token: "token",
866
+ expires: TOMORROW,
867
+ username: "c@sey",
868
+ ssl: true,
869
+ })
870
+ );
871
+ });
872
+
873
+ it("should reject the promise if there is an error", (done) => {
874
+ const MockWindow: any = {
875
+ open: jasmine.createSpy("spy"),
876
+ };
877
+
878
+ UserSession.beginOAuth2(
879
+ {
880
+ clientId: "clientId123",
881
+ redirectUri: "http://example-app.com/redirect",
882
+ locale: "fr",
883
+ },
884
+ MockWindow
885
+ ).catch((e) => {
886
+ done();
887
+ });
888
+
889
+ expect(MockWindow.open).toHaveBeenCalledWith(
890
+ "https://www.arcgis.com/sharing/rest/oauth2/authorize?client_id=clientId123&response_type=token&expiration=20160&redirect_uri=http%3A%2F%2Fexample-app.com%2Fredirect&state=clientId123&locale=fr",
891
+ "oauth-window",
892
+ "height=400,width=600,menubar=no,location=yes,resizable=yes,scrollbars=yes,status=yes"
893
+ );
894
+
895
+ MockWindow.__ESRI_REST_AUTH_HANDLER_clientId123(
896
+ JSON.stringify({
897
+ errorMessage: "unable to sign in",
898
+ error: "SIGN_IN_FAILED",
899
+ })
900
+ );
901
+ });
902
+
903
+ it("should authorize in the same window/tab", () => {
904
+ const MockWindow: any = {
905
+ location: {
906
+ href: "",
907
+ },
908
+ };
909
+
910
+ // https://github.com/palantir/tslint/issues/3056
911
+ void UserSession.beginOAuth2(
912
+ {
913
+ clientId: "clientId123",
914
+ redirectUri: "http://example-app.com/redirect",
915
+ popup: false,
916
+ },
917
+ MockWindow
918
+ );
919
+
920
+ expect(MockWindow.location.href).toBe(
921
+ "https://www.arcgis.com/sharing/rest/oauth2/authorize?client_id=clientId123&response_type=token&expiration=20160&redirect_uri=http%3A%2F%2Fexample-app.com%2Fredirect&state=clientId123&locale="
922
+ );
923
+ });
924
+
925
+ it("should authorize using a social media provider", () => {
926
+ const MockWindow: any = {
927
+ location: {
928
+ href: "",
929
+ },
930
+ };
931
+
932
+ // https://github.com/palantir/tslint/issues/3056
933
+ void UserSession.beginOAuth2(
934
+ {
935
+ clientId: "clientId123",
936
+ redirectUri: "http://example-app.com/redirect",
937
+ popup: false,
938
+ provider: "facebook",
939
+ },
940
+ MockWindow
941
+ );
942
+
943
+ expect(MockWindow.location.href).toBe(
944
+ "https://www.arcgis.com/sharing/rest/oauth2/social/authorize?client_id=clientId123&socialLoginProviderName=facebook&autoAccountCreateForSocial=true&response_type=token&expiration=20160&redirect_uri=http%3A%2F%2Fexample-app.com%2Fredirect&state=clientId123&locale="
945
+ );
946
+ });
947
+
948
+ it("should authorize using the other social media provider", () => {
949
+ const MockWindow: any = {
950
+ location: {
951
+ href: "",
952
+ },
953
+ };
954
+
955
+ // https://github.com/palantir/tslint/issues/3056
956
+ void UserSession.beginOAuth2(
957
+ {
958
+ clientId: "clientId123",
959
+ redirectUri: "http://example-app.com/redirect",
960
+ popup: false,
961
+ provider: "google",
962
+ },
963
+ MockWindow
964
+ );
965
+
966
+ expect(MockWindow.location.href).toBe(
967
+ "https://www.arcgis.com/sharing/rest/oauth2/social/authorize?client_id=clientId123&socialLoginProviderName=google&autoAccountCreateForSocial=true&response_type=token&expiration=20160&redirect_uri=http%3A%2F%2Fexample-app.com%2Fredirect&state=clientId123&locale="
968
+ );
969
+ });
970
+
971
+ it("should pass custom expiration", () => {
972
+ const MockWindow: any = {
973
+ location: {
974
+ href: "",
975
+ },
976
+ };
977
+
978
+ // https://github.com/palantir/tslint/issues/3056
979
+ void UserSession.beginOAuth2(
980
+ {
981
+ clientId: "clientId123",
982
+ redirectUri: "http://example-app.com/redirect",
983
+ popup: false,
984
+ expiration: 9000,
985
+ },
986
+ MockWindow
987
+ );
988
+
989
+ expect(MockWindow.location.href).toBe(
990
+ "https://www.arcgis.com/sharing/rest/oauth2/authorize?client_id=clientId123&response_type=token&expiration=9000&redirect_uri=http%3A%2F%2Fexample-app.com%2Fredirect&state=clientId123&locale="
991
+ );
992
+ });
993
+
994
+ it("should pass custom duration (DEPRECATED)", () => {
995
+ const MockWindow: any = {
996
+ location: {
997
+ href: "",
998
+ },
999
+ };
1000
+
1001
+ // https://github.com/palantir/tslint/issues/3056
1002
+ void UserSession.beginOAuth2(
1003
+ {
1004
+ clientId: "clientId123",
1005
+ redirectUri: "http://example-app.com/redirect",
1006
+ popup: false,
1007
+ duration: 9001,
1008
+ },
1009
+ MockWindow
1010
+ );
1011
+
1012
+ expect(MockWindow.location.href).toBe(
1013
+ "https://www.arcgis.com/sharing/rest/oauth2/authorize?client_id=clientId123&response_type=token&expiration=9001&redirect_uri=http%3A%2F%2Fexample-app.com%2Fredirect&state=clientId123&locale="
1014
+ );
1015
+ });
1016
+ });
1017
+
1018
+ describe(".completeOAuth2()", () => {
1019
+ it("should return a new user session if it cannot find a valid parent", () => {
1020
+ const MockWindow = {
1021
+ location: {
1022
+ hash: "#access_token=token&expires_in=1209600&username=c%40sey&ssl=true&persist=true",
1023
+ },
1024
+ get parent() {
1025
+ return this;
1026
+ },
1027
+ };
1028
+
1029
+ const session = UserSession.completeOAuth2(
1030
+ {
1031
+ clientId: "clientId",
1032
+ redirectUri: "https://example-app.com/redirect-uri",
1033
+ },
1034
+ MockWindow
1035
+ );
1036
+
1037
+ expect(session.token).toBe("token");
1038
+ expect(session.tokenExpires.getTime()).toBeGreaterThan(Date.now());
1039
+ expect(session.username).toBe("c@sey");
1040
+ expect(session.ssl).toBe(true);
1041
+ });
1042
+
1043
+ it("should return a new user session with ssl as false when callback hash does not have ssl parameter", () => {
1044
+ const MockWindow = {
1045
+ location: {
1046
+ hash: "#access_token=token&expires_in=1209600&username=c%40sey&persist=true",
1047
+ },
1048
+ get parent() {
1049
+ return this;
1050
+ },
1051
+ };
1052
+
1053
+ const session = UserSession.completeOAuth2(
1054
+ {
1055
+ clientId: "clientId",
1056
+ redirectUri: "https://example-app.com/redirect-uri",
1057
+ },
1058
+ MockWindow
1059
+ );
1060
+ expect(session.ssl).toBe(false);
1061
+ });
1062
+
1063
+ it("should callback to create a new user session if finds a valid opener.parent", (done) => {
1064
+ const MockWindow = {
1065
+ opener: {
1066
+ parent: {
1067
+ __ESRI_REST_AUTH_HANDLER_clientId(
1068
+ errorString: string,
1069
+ oauthInfoString: string
1070
+ ) {
1071
+ const oauthInfo = JSON.parse(oauthInfoString);
1072
+ expect(oauthInfo.token).toBe("token");
1073
+ expect(oauthInfo.username).toBe("c@sey");
1074
+ expect(oauthInfo.ssl).toBe(true);
1075
+ expect(new Date(oauthInfo.expires).getTime()).toBeGreaterThan(
1076
+ Date.now()
1077
+ );
1078
+ },
1079
+ },
1080
+ },
1081
+ close() {
1082
+ done();
1083
+ },
1084
+ location: {
1085
+ hash: "#access_token=token&expires_in=1209600&username=c%40sey&ssl=true",
1086
+ },
1087
+ };
1088
+
1089
+ UserSession.completeOAuth2(
1090
+ {
1091
+ clientId: "clientId",
1092
+ redirectUri: "https://example-app.com/redirect-uri",
1093
+ },
1094
+ MockWindow
1095
+ );
1096
+ });
1097
+
1098
+ it("should callback to create a new user session if finds a valid opener (Iframe support)", (done) => {
1099
+ const MockWindow = {
1100
+ opener: {
1101
+ __ESRI_REST_AUTH_HANDLER_clientId(
1102
+ errorString: string,
1103
+ oauthInfoString: string
1104
+ ) {
1105
+ const oauthInfo = JSON.parse(oauthInfoString);
1106
+ expect(oauthInfo.token).toBe("token");
1107
+ expect(oauthInfo.username).toBe("c@sey");
1108
+ expect(oauthInfo.ssl).toBe(true);
1109
+ expect(new Date(oauthInfo.expires).getTime()).toBeGreaterThan(
1110
+ Date.now()
1111
+ );
1112
+ },
1113
+ },
1114
+ close() {
1115
+ done();
1116
+ },
1117
+ location: {
1118
+ hash: "#access_token=token&expires_in=1209600&username=c%40sey&ssl=true",
1119
+ },
1120
+ };
1121
+
1122
+ UserSession.completeOAuth2(
1123
+ {
1124
+ clientId: "clientId",
1125
+ redirectUri: "https://example-app.com/redirect-uri",
1126
+ },
1127
+ MockWindow
1128
+ );
1129
+ });
1130
+
1131
+ it("should callback to create a new user session if finds a valid parent", (done) => {
1132
+ const MockWindow = {
1133
+ parent: {
1134
+ __ESRI_REST_AUTH_HANDLER_clientId(
1135
+ errorString: string,
1136
+ oauthInfoString: string
1137
+ ) {
1138
+ const oauthInfo = JSON.parse(oauthInfoString);
1139
+ expect(oauthInfo.token).toBe("token");
1140
+ expect(oauthInfo.username).toBe("c@sey");
1141
+ expect(oauthInfo.ssl).toBe(true);
1142
+ expect(new Date(oauthInfo.expires).getTime()).toBeGreaterThan(
1143
+ Date.now()
1144
+ );
1145
+ },
1146
+ },
1147
+ close() {
1148
+ done();
1149
+ },
1150
+ location: {
1151
+ hash: "#access_token=token&expires_in=1209600&username=c%40sey&ssl=true",
1152
+ },
1153
+ };
1154
+
1155
+ UserSession.completeOAuth2(
1156
+ {
1157
+ clientId: "clientId",
1158
+ redirectUri: "https://example-app.com/redirect-uri",
1159
+ },
1160
+ MockWindow
1161
+ );
1162
+ });
1163
+
1164
+ it("should throw an error from the authorization window", () => {
1165
+ const MockWindow = {
1166
+ location: {
1167
+ hash: "#error=Invalid_Signin&error_description=Invalid_Signin",
1168
+ },
1169
+ get parent() {
1170
+ return this;
1171
+ },
1172
+ };
1173
+
1174
+ expect(function () {
1175
+ UserSession.completeOAuth2(
1176
+ {
1177
+ clientId: "clientId",
1178
+ redirectUri: "https://example-app.com/redirect-uri",
1179
+ },
1180
+ MockWindow
1181
+ );
1182
+ }).toThrowError(ArcGISRequestError, "Invalid_Signin: Invalid_Signin");
1183
+ });
1184
+
1185
+ it("should throw an error if the handler or parent window cannot be accessed", () => {
1186
+ const MockParent = {
1187
+ get parent() {
1188
+ throw new Error(
1189
+ "This window isn't where auth started, but was opened from somewhere else via window.open() perhaps from another domain which would cause a cross domain error when read."
1190
+ );
1191
+ },
1192
+ };
1193
+
1194
+ const MockWindow = {
1195
+ location: {
1196
+ hash: "#error=Invalid_Signin&error_description=Invalid_Signin",
1197
+ },
1198
+ get opener() {
1199
+ return MockParent;
1200
+ },
1201
+ };
1202
+
1203
+ expect(function () {
1204
+ UserSession.completeOAuth2(
1205
+ {
1206
+ clientId: "clientId",
1207
+ redirectUri: "https://example-app.com/redirect-uri",
1208
+ },
1209
+ MockWindow
1210
+ );
1211
+ }).toThrowError(ArcGISAuthError);
1212
+ });
1213
+ });
1214
+
1215
+ describe("postmessage auth :: ", () => {
1216
+ const MockWindow = {
1217
+ addEventListener: () => {},
1218
+ removeEventListener: () => {},
1219
+ parent: {
1220
+ postMessage: () => {},
1221
+ },
1222
+ };
1223
+
1224
+ const cred = {
1225
+ expires: TOMORROW.getTime(),
1226
+ server: "https://www.arcgis.com/sharing/rest",
1227
+ ssl: false,
1228
+ token: "token",
1229
+ userId: "jsmith",
1230
+ };
1231
+
1232
+ it(".disablePostMessageAuth removes event listener", () => {
1233
+ const removeSpy = spyOn(MockWindow, "removeEventListener");
1234
+ const session = UserSession.fromCredential(cred);
1235
+ session.disablePostMessageAuth(MockWindow);
1236
+ expect(removeSpy.calls.count()).toBe(
1237
+ 1,
1238
+ "should call removeEventListener"
1239
+ );
1240
+ });
1241
+ it(".enablePostMessageAuth adds event listener", () => {
1242
+ const addSpy = spyOn(MockWindow, "addEventListener");
1243
+ const session = UserSession.fromCredential(cred);
1244
+ session.enablePostMessageAuth(
1245
+ ["https://storymaps.arcgis.com"],
1246
+ MockWindow
1247
+ );
1248
+ expect(addSpy.calls.count()).toBe(1, "should call addEventListener");
1249
+ });
1250
+
1251
+ it(".enablePostMessage handler returns credential to origin in list", () => {
1252
+ // ok, this gets kinda gnarly...
1253
+
1254
+ // create a mock window object
1255
+ // that will hold the passed in event handler so we can fire it manually
1256
+ const Win = {
1257
+ _fn: (evt: any) => {},
1258
+ addEventListener(evt: any, fn: any) {
1259
+ // enablePostMessageAuth passes in the handler, which is what we're actually testing
1260
+ Win._fn = fn;
1261
+ },
1262
+ removeEventListener() {},
1263
+ };
1264
+ // Create the session
1265
+ const session = UserSession.fromCredential(cred);
1266
+ // enable postMessageAuth allowing storymaps.arcgis.com to recieve creds
1267
+ session.enablePostMessageAuth(["https://storymaps.arcgis.com"], Win);
1268
+ // create an event object, with a matching origin
1269
+ // an a source.postMessage fn that we can spy on
1270
+ const event = {
1271
+ origin: "https://storymaps.arcgis.com",
1272
+ source: {
1273
+ postMessage(msg: any, origin: string) {},
1274
+ },
1275
+ data: {
1276
+ type: "arcgis:auth:requestCredential",
1277
+ },
1278
+ };
1279
+ // create the spy
1280
+ const sourceSpy = spyOn(event.source, "postMessage");
1281
+ // Now, fire the handler, simulating what happens when a postMessage event comes
1282
+ // from an embedded iframe
1283
+ Win._fn(event);
1284
+ // Expectations...
1285
+ expect(sourceSpy.calls.count()).toBe(
1286
+ 1,
1287
+ "souce.postMessage should be called in handler"
1288
+ );
1289
+ const args = sourceSpy.calls.argsFor(0);
1290
+ expect(args[0].type).toBe(
1291
+ "arcgis:auth:credential",
1292
+ "should send credential type"
1293
+ );
1294
+ expect(args[0].credential.userId).toBe(
1295
+ "jsmith",
1296
+ "should send credential"
1297
+ );
1298
+ expect(args[0].credential.server).toBe(
1299
+ "https://www.arcgis.com",
1300
+ "sends server url without /sharing/rest"
1301
+ );
1302
+ // now the case where it's not a valid origin
1303
+ event.origin = "https://evil.com";
1304
+ Win._fn(event);
1305
+ expect(sourceSpy.calls.count()).toBe(
1306
+ 1,
1307
+ "souce.postMessage should not be called in handler for invalid origin"
1308
+ );
1309
+ });
1310
+
1311
+ it(".enablePostMessage handler returns error if session is expired", () => {
1312
+ // ok, this gets kinda gnarly...
1313
+ const expiredCred = {
1314
+ expires: YESTERDAY.getTime(),
1315
+ server: "https://www.arcgis.com/sharing/rest",
1316
+ ssl: false,
1317
+ token: "token",
1318
+ userId: "jsmith",
1319
+ };
1320
+ // create a mock window object
1321
+ // that will hold the passed in event handler so we can fire it manually
1322
+ const Win = {
1323
+ _fn: (evt: any) => {},
1324
+ addEventListener(evt: any, fn: any) {
1325
+ // enablePostMessageAuth passes in the handler, which is what we're actually testing
1326
+ Win._fn = fn;
1327
+ },
1328
+ removeEventListener() {},
1329
+ };
1330
+ // Create the session
1331
+ const session = UserSession.fromCredential(expiredCred);
1332
+ // enable postMessageAuth allowing storymaps.arcgis.com to recieve creds
1333
+ session.enablePostMessageAuth(["https://storymaps.arcgis.com"], Win);
1334
+ // create an event object, with a matching origin
1335
+ // an a source.postMessage fn that we can spy on
1336
+ const event = {
1337
+ origin: "https://storymaps.arcgis.com",
1338
+ source: {
1339
+ postMessage(msg: any, origin: string) {},
1340
+ },
1341
+ data: {
1342
+ type: "arcgis:auth:requestCredential",
1343
+ },
1344
+ };
1345
+ // create the spy
1346
+ const sourceSpy = spyOn(event.source, "postMessage");
1347
+ // Now, fire the handler, simulating what happens when a postMessage event comes
1348
+ // from an embedded iframe
1349
+ Win._fn(event);
1350
+ // Expectations...
1351
+ expect(sourceSpy.calls.count()).toBe(
1352
+ 1,
1353
+ "souce.postMessage should be called in handler"
1354
+ );
1355
+ const args = sourceSpy.calls.argsFor(0);
1356
+ expect(args[0].type).toBe("arcgis:auth:error", "should send error type");
1357
+ expect(args[0].credential).not.toBeDefined();
1358
+ expect(args[0].error.name).toBe(
1359
+ "tokenExpiredError",
1360
+ "should recieve tokenExpiredError"
1361
+ );
1362
+ });
1363
+
1364
+ it(".fromParent happy path", () => {
1365
+ // create a mock window that will fire the handler
1366
+ const Win = {
1367
+ _fn: (evt: any) => {},
1368
+ addEventListener(evt: any, fn: any) {
1369
+ Win._fn = fn;
1370
+ },
1371
+ removeEventListener() {},
1372
+ parent: {
1373
+ postMessage(msg: any, origin: string) {
1374
+ Win._fn({
1375
+ origin: "https://origin.com",
1376
+ data: { type: "arcgis:auth:credential", credential: cred },
1377
+ source: Win.parent,
1378
+ });
1379
+ },
1380
+ },
1381
+ };
1382
+
1383
+ return UserSession.fromParent("https://origin.com", Win).then(
1384
+ (session) => {
1385
+ expect(session.username).toBe(
1386
+ "jsmith",
1387
+ "should use the cred wired throu the mock window"
1388
+ );
1389
+ }
1390
+ );
1391
+ });
1392
+
1393
+ it(".fromParent ignores other messages, then intercepts the correct one", async () => {
1394
+ // create a mock window that will fire the handler
1395
+ const Win = {
1396
+ _fn: (evt: any) => {},
1397
+ addEventListener(evt: any, fn: any) {
1398
+ Win._fn = fn;
1399
+ },
1400
+ removeEventListener() {},
1401
+ parent: {
1402
+ postMessage(msg: any, origin: string) {
1403
+ // fire one we intend to ignore
1404
+ Win._fn({
1405
+ origin: "https://notorigin.com",
1406
+ data: { type: "other:random", foo: { bar: "baz" } },
1407
+ source: "Not Parent Object",
1408
+ });
1409
+ // fire a second we want to intercept
1410
+ Win._fn({
1411
+ origin: "https://origin.com",
1412
+ data: { type: "arcgis:auth:credential", credential: cred },
1413
+ source: Win.parent,
1414
+ });
1415
+ },
1416
+ },
1417
+ };
1418
+
1419
+ return UserSession.fromParent("https://origin.com", Win).then((resp) => {
1420
+ expect(resp.username).toBe(
1421
+ "jsmith",
1422
+ "should use the cred wired throu the mock window"
1423
+ );
1424
+ });
1425
+ });
1426
+
1427
+ it(".fromParent rejects if invlid cred", () => {
1428
+ // create a mock window that will fire the handler
1429
+ const Win = {
1430
+ _fn: (evt: any) => {},
1431
+ addEventListener(evt: any, fn: any) {
1432
+ Win._fn = fn;
1433
+ },
1434
+ removeEventListener() {},
1435
+ parent: {
1436
+ postMessage(msg: any, origin: string) {
1437
+ Win._fn({
1438
+ origin: "https://origin.com",
1439
+ data: {
1440
+ type: "arcgis:auth:credential",
1441
+ credential: { foo: "bar" },
1442
+ },
1443
+ source: Win.parent,
1444
+ });
1445
+ },
1446
+ },
1447
+ };
1448
+
1449
+ return UserSession.fromParent("https://origin.com", Win).catch((err) => {
1450
+ expect(err).toBeDefined("Should reject");
1451
+ });
1452
+ });
1453
+
1454
+ it(".fromParent rejects if auth error recieved", () => {
1455
+ // create a mock window that will fire the handler
1456
+ const Win = {
1457
+ _fn: (evt: any) => {},
1458
+ addEventListener(evt: any, fn: any) {
1459
+ Win._fn = fn;
1460
+ },
1461
+ removeEventListener() {},
1462
+ parent: {
1463
+ postMessage(msg: any, origin: string) {
1464
+ Win._fn({
1465
+ origin: "https://origin.com",
1466
+ data: {
1467
+ type: "arcgis:auth:error",
1468
+ error: { message: "Rejected authentication request." },
1469
+ },
1470
+ source: Win.parent,
1471
+ });
1472
+ },
1473
+ },
1474
+ };
1475
+
1476
+ return UserSession.fromParent("https://origin.com", Win).catch((err) => {
1477
+ expect(err).toBeDefined("Should reject");
1478
+ });
1479
+ });
1480
+
1481
+ it(".fromParent rejects if auth unknown message", () => {
1482
+ // create a mock window that will fire the handler
1483
+ const Win = {
1484
+ _fn: (evt: any) => {},
1485
+ addEventListener(evt: any, fn: any) {
1486
+ Win._fn = fn;
1487
+ },
1488
+ removeEventListener() {},
1489
+ parent: {
1490
+ postMessage(msg: any, origin: string) {
1491
+ Win._fn({
1492
+ origin: "https://origin.com",
1493
+ data: { type: "arcgis:auth:other" },
1494
+ source: Win.parent,
1495
+ });
1496
+ },
1497
+ },
1498
+ };
1499
+
1500
+ return UserSession.fromParent("https://origin.com", Win).catch((err) => {
1501
+ expect(err.message).toBe("Unknown message type.", "Should reject");
1502
+ });
1503
+ });
1504
+ });
1505
+
1506
+ describe("validateAppAccess: ", () => {
1507
+ it("makes a request to /oauth2/validateAppAccess passing params", () => {
1508
+ const VERIFYAPPACCESS_URL =
1509
+ "https://www.arcgis.com/sharing/rest/oauth2/validateAppAccess";
1510
+ fetchMock.postOnce(VERIFYAPPACCESS_URL, {
1511
+ valid: true,
1512
+ viewOnlyUserTypeApp: false,
1513
+ });
1514
+ const session = new UserSession({
1515
+ clientId: "clientId",
1516
+ redirectUri: "https://example-app.com/redirect-uri",
1517
+ token: "FAKE-TOKEN",
1518
+ tokenExpires: TOMORROW,
1519
+ refreshToken: "refreshToken",
1520
+ refreshTokenExpires: TOMORROW,
1521
+ refreshTokenTTL: 1440,
1522
+ username: "jsmith",
1523
+ password: "123456",
1524
+ });
1525
+ return session
1526
+ .validateAppAccess("abc123")
1527
+ .then((response) => {
1528
+ const [url, options]: [string, RequestInit] =
1529
+ fetchMock.lastCall(VERIFYAPPACCESS_URL);
1530
+ expect(url).toEqual(VERIFYAPPACCESS_URL);
1531
+ expect(options.body).toContain("f=json");
1532
+ expect(options.body).toContain("token=FAKE-TOKEN");
1533
+ expect(options.body).toContain("client_id=abc123");
1534
+ expect(response.valid).toEqual(true);
1535
+ expect(response.viewOnlyUserTypeApp).toBe(false);
1536
+ })
1537
+ .catch((e) => fail(e));
1538
+ });
1539
+ });
1540
+
1541
+ it("should throw an unknown error if the url has no error or access_token", () => {
1542
+ const MockWindow = {
1543
+ location: {
1544
+ hash: "",
1545
+ },
1546
+ get opener() {
1547
+ return this;
1548
+ },
1549
+ };
1550
+
1551
+ expect(function () {
1552
+ UserSession.completeOAuth2(
1553
+ {
1554
+ clientId: "clientId",
1555
+ redirectUri: "https://example-app.com/redirect-uri",
1556
+ },
1557
+ MockWindow
1558
+ );
1559
+ }).toThrowError(ArcGISRequestError, "Unknown error");
1560
+ });
1561
+
1562
+ describe(".authorize()", () => {
1563
+ it("should redirect the request to the authorization page", (done) => {
1564
+ const spy = jasmine.createSpy("spy");
1565
+ const MockResponse: any = {
1566
+ writeHead: spy,
1567
+ end() {
1568
+ expect(spy.calls.mostRecent().args[0]).toBe(301);
1569
+ expect(spy.calls.mostRecent().args[1].Location).toBe(
1570
+ "https://arcgis.com/sharing/rest/oauth2/authorize?client_id=clientId&expiration=20160&response_type=code&redirect_uri=https%3A%2F%2Fexample-app.com%2Fredirect-uri"
1571
+ );
1572
+ done();
1573
+ },
1574
+ };
1575
+
1576
+ UserSession.authorize(
1577
+ {
1578
+ clientId: "clientId",
1579
+ redirectUri: "https://example-app.com/redirect-uri",
1580
+ },
1581
+ MockResponse
1582
+ );
1583
+ });
1584
+
1585
+ it("should redirect the request to the authorization page with custom expiration", (done) => {
1586
+ const spy = jasmine.createSpy("spy");
1587
+ const MockResponse: any = {
1588
+ writeHead: spy,
1589
+ end() {
1590
+ expect(spy.calls.mostRecent().args[0]).toBe(301);
1591
+ expect(spy.calls.mostRecent().args[1].Location).toBe(
1592
+ "https://arcgis.com/sharing/rest/oauth2/authorize?client_id=clientId&expiration=10000&response_type=code&redirect_uri=https%3A%2F%2Fexample-app.com%2Fredirect-uri"
1593
+ );
1594
+ done();
1595
+ },
1596
+ };
1597
+
1598
+ UserSession.authorize(
1599
+ {
1600
+ clientId: "clientId",
1601
+ redirectUri: "https://example-app.com/redirect-uri",
1602
+ expiration: 10000,
1603
+ },
1604
+ MockResponse
1605
+ );
1606
+ });
1607
+
1608
+ it("should redirect the request to the authorization page with custom duration (DEPRECATED)", (done) => {
1609
+ const spy = jasmine.createSpy("spy");
1610
+ const MockResponse: any = {
1611
+ writeHead: spy,
1612
+ end() {
1613
+ expect(spy.calls.mostRecent().args[0]).toBe(301);
1614
+ expect(spy.calls.mostRecent().args[1].Location).toBe(
1615
+ "https://arcgis.com/sharing/rest/oauth2/authorize?client_id=clientId&expiration=10001&response_type=code&redirect_uri=https%3A%2F%2Fexample-app.com%2Fredirect-uri"
1616
+ );
1617
+ done();
1618
+ },
1619
+ };
1620
+
1621
+ UserSession.authorize(
1622
+ {
1623
+ clientId: "clientId",
1624
+ redirectUri: "https://example-app.com/redirect-uri",
1625
+ duration: 10001,
1626
+ },
1627
+ MockResponse
1628
+ );
1629
+ });
1630
+ });
1631
+
1632
+ describe(".exchangeAuthorizationCode()", () => {
1633
+ let paramsSpy: jasmine.Spy;
1634
+
1635
+ beforeEach(() => {
1636
+ paramsSpy = spyOn(FormData.prototype, "append").and.callThrough();
1637
+ });
1638
+
1639
+ afterAll(() => {
1640
+ paramsSpy.calls.reset();
1641
+ });
1642
+
1643
+ it("should exchange an authorization code for a new UserSession", (done) => {
1644
+ fetchMock.postOnce("https://www.arcgis.com/sharing/rest/oauth2/token", {
1645
+ access_token: "token",
1646
+ expires_in: 1800,
1647
+ refresh_token: "refreshToken",
1648
+ username: "Casey",
1649
+ ssl: true,
1650
+ });
1651
+
1652
+ UserSession.exchangeAuthorizationCode(
1653
+ {
1654
+ clientId: "clientId",
1655
+ redirectUri: "https://example-app.com/redirect-uri",
1656
+ },
1657
+ "code"
1658
+ )
1659
+ .then((session) => {
1660
+ expect(session.token).toBe("token");
1661
+ expect(session.tokenExpires.getTime()).toBeGreaterThan(Date.now());
1662
+ expect(session.username).toBe("Casey");
1663
+ expect(session.refreshToken).toBe("refreshToken");
1664
+ expect(session.ssl).toBe(true);
1665
+ done();
1666
+ })
1667
+ .catch((e) => {
1668
+ fail(e);
1669
+ });
1670
+ });
1671
+
1672
+ it("should return a UserSession where refreshTokenExpires is 2 weeks from now (within 10 ms)", (done) => {
1673
+ fetchMock.postOnce("https://www.arcgis.com/sharing/rest/oauth2/token", {
1674
+ access_token: "token",
1675
+ refresh_token: "refreshToken",
1676
+ username: "Casey",
1677
+ ssl: true,
1678
+ });
1679
+
1680
+ UserSession.exchangeAuthorizationCode(
1681
+ {
1682
+ clientId: "clientId",
1683
+ redirectUri: "https://example-app.com/redirect-uri",
1684
+ },
1685
+ "code"
1686
+ )
1687
+ .then((session) => {
1688
+ const twoWeeksFromNow = new Date(
1689
+ Date.now() + (20160 - 1) * 60 * 1000
1690
+ );
1691
+ expect(session.refreshTokenExpires.getTime()).toBeGreaterThan(
1692
+ twoWeeksFromNow.getTime() - 10
1693
+ );
1694
+ expect(session.refreshTokenExpires.getTime()).toBeLessThan(
1695
+ twoWeeksFromNow.getTime() + 10
1696
+ );
1697
+ done();
1698
+ })
1699
+ .catch((e) => {
1700
+ fail(e);
1701
+ });
1702
+ });
1703
+ });
1704
+
1705
+ describe(".getUser()", () => {
1706
+ afterEach(fetchMock.restore);
1707
+
1708
+ it("should cache metadata about the user", (done) => {
1709
+ // we intentionally only mock one response
1710
+ fetchMock.once(
1711
+ "https://www.arcgis.com/sharing/rest/community/self?f=json&token=token",
1712
+ {
1713
+ username: "jsmith",
1714
+ fullName: "John Smith",
1715
+ role: "org_publisher",
1716
+ }
1717
+ );
1718
+
1719
+ const session = new UserSession({
1720
+ clientId: "clientId",
1721
+ redirectUri: "https://example-app.com/redirect-uri",
1722
+ token: "token",
1723
+ tokenExpires: TOMORROW,
1724
+ refreshToken: "refreshToken",
1725
+ refreshTokenExpires: TOMORROW,
1726
+ refreshTokenTTL: 1440,
1727
+ username: "jsmith",
1728
+ password: "123456",
1729
+ });
1730
+
1731
+ session
1732
+ .getUser()
1733
+ .then((response) => {
1734
+ expect(response.role).toEqual("org_publisher");
1735
+ session
1736
+ .getUser()
1737
+ .then((cachedResponse) => {
1738
+ expect(cachedResponse.fullName).toEqual("John Smith");
1739
+ done();
1740
+ })
1741
+ .catch((e) => {
1742
+ fail(e);
1743
+ });
1744
+ })
1745
+ .catch((e) => {
1746
+ fail(e);
1747
+ });
1748
+ });
1749
+
1750
+ it("should never make more then 1 request", (done) => {
1751
+ // we intentionally only mock one response
1752
+ fetchMock.once(
1753
+ "https://www.arcgis.com/sharing/rest/community/self?f=json&token=token",
1754
+ {
1755
+ username: "jsmith",
1756
+ fullName: "John Smith",
1757
+ role: "org_publisher",
1758
+ }
1759
+ );
1760
+
1761
+ const session = new UserSession({
1762
+ clientId: "clientId",
1763
+ redirectUri: "https://example-app.com/redirect-uri",
1764
+ token: "token",
1765
+ tokenExpires: TOMORROW,
1766
+ refreshToken: "refreshToken",
1767
+ refreshTokenExpires: TOMORROW,
1768
+ refreshTokenTTL: 1440,
1769
+ username: "jsmith",
1770
+ password: "123456",
1771
+ });
1772
+
1773
+ Promise.all([session.getUser(), session.getUser()])
1774
+ .then(() => {
1775
+ done();
1776
+ })
1777
+ .catch((e) => {
1778
+ fail(e);
1779
+ });
1780
+ });
1781
+ });
1782
+
1783
+ describe(".getUsername()", () => {
1784
+ afterEach(fetchMock.restore);
1785
+
1786
+ it("should fetch the username via getUser()", (done) => {
1787
+ // we intentionally only mock one response
1788
+ fetchMock.once(
1789
+ "https://www.arcgis.com/sharing/rest/community/self?f=json&token=token",
1790
+ {
1791
+ username: "jsmith",
1792
+ }
1793
+ );
1794
+
1795
+ const session = new UserSession({
1796
+ token: "token",
1797
+ });
1798
+
1799
+ session
1800
+ .getUsername()
1801
+ .then((response) => {
1802
+ expect(response).toEqual("jsmith");
1803
+
1804
+ // also test getting it from the cache.
1805
+ session
1806
+ .getUsername()
1807
+ .then((username) => {
1808
+ done();
1809
+
1810
+ expect(username).toEqual("jsmith");
1811
+ })
1812
+ .catch((e) => {
1813
+ fail(e);
1814
+ });
1815
+ })
1816
+ .catch((e) => {
1817
+ fail(e);
1818
+ });
1819
+ });
1820
+
1821
+ it("should use a username if passed in the session", (done) => {
1822
+ const session = new UserSession({
1823
+ username: "jsmith",
1824
+ });
1825
+
1826
+ session
1827
+ .getUsername()
1828
+ .then((response) => {
1829
+ expect(response).toEqual("jsmith");
1830
+ done();
1831
+ })
1832
+ .catch((e) => {
1833
+ fail(e);
1834
+ });
1835
+ });
1836
+ });
1837
+
1838
+ describe("to/fromCredential()", () => {
1839
+ const MOCK_CREDENTIAL: ICredential = {
1840
+ expires: TOMORROW.getTime(),
1841
+ server: "https://www.arcgis.com",
1842
+ ssl: false,
1843
+ token: "token",
1844
+ userId: "jsmith",
1845
+ };
1846
+
1847
+ const MOCK_USER_SESSION = new UserSession({
1848
+ clientId: "clientId",
1849
+ redirectUri: "https://example-app.com/redirect-uri",
1850
+ token: "token",
1851
+ ssl: false,
1852
+ tokenExpires: TOMORROW,
1853
+ refreshToken: "refreshToken",
1854
+ refreshTokenExpires: TOMORROW,
1855
+ refreshTokenTTL: 1440,
1856
+ username: "jsmith",
1857
+ password: "123456",
1858
+ });
1859
+
1860
+ it("should create a credential object from a session", () => {
1861
+ const creds = MOCK_USER_SESSION.toCredential();
1862
+ expect(creds.userId).toEqual("jsmith");
1863
+ expect(creds.server).toEqual("https://www.arcgis.com/sharing/rest");
1864
+ expect(creds.ssl).toEqual(false);
1865
+ expect(creds.token).toEqual("token");
1866
+ expect(creds.expires).toEqual(TOMORROW.getTime());
1867
+ });
1868
+
1869
+ it("should create a UserSession from a credential", () => {
1870
+ const session = UserSession.fromCredential(MOCK_CREDENTIAL);
1871
+ expect(session.username).toEqual("jsmith");
1872
+ expect(session.portal).toEqual("https://www.arcgis.com/sharing/rest");
1873
+ expect(session.ssl).toEqual(false);
1874
+ expect(session.token).toEqual("token");
1875
+ expect(session.tokenExpires).toEqual(new Date(TOMORROW));
1876
+ });
1877
+
1878
+ it("should create a UserSession from a credential that came from a UserSession", () => {
1879
+ const creds = MOCK_USER_SESSION.toCredential();
1880
+ const credSession = UserSession.fromCredential(creds);
1881
+ expect(credSession.username).toEqual("jsmith");
1882
+ expect(credSession.portal).toEqual("https://www.arcgis.com/sharing/rest");
1883
+ expect(credSession.ssl).toEqual(false);
1884
+ expect(credSession.token).toEqual("token");
1885
+ expect(credSession.tokenExpires).toEqual(new Date(TOMORROW));
1886
+ });
1887
+ });
1888
+
1889
+ describe("fromCredential() when credential doesn't have an expiration date or ssl", () => {
1890
+ const MOCK_CREDENTIAL: ICredential = {
1891
+ expires: undefined,
1892
+ server: "https://www.arcgis.com",
1893
+ ssl: undefined,
1894
+ token: "token",
1895
+ userId: "jsmith",
1896
+ };
1897
+
1898
+ it("should create a UserSession from a credential", () => {
1899
+ jasmine.clock().install();
1900
+ jasmine.clock().mockDate();
1901
+
1902
+ const session = UserSession.fromCredential(MOCK_CREDENTIAL);
1903
+ expect(session.username).toEqual("jsmith");
1904
+ expect(session.portal).toEqual("https://www.arcgis.com/sharing/rest");
1905
+ expect(session.ssl).toBeTruthy();
1906
+ expect(session.token).toEqual("token");
1907
+ expect(session.tokenExpires).toEqual(
1908
+ new Date(Date.now() + 7200000 /* 2 hours */)
1909
+ );
1910
+
1911
+ jasmine.clock().uninstall();
1912
+ });
1913
+ });
1914
+
1915
+ describe("getServerRootUrl()", () => {
1916
+ it("should lowercase domain names", () => {
1917
+ const session = new UserSession({
1918
+ clientId: "id",
1919
+ token: "token",
1920
+ tokenExpires: TOMORROW,
1921
+ });
1922
+
1923
+ const root = session.getServerRootUrl(
1924
+ "https://PNP00035.esri.com/server/rest/services/Hosted/perimeters_dd83/FeatureServer"
1925
+ );
1926
+ expect(root).toEqual("https://pnp00035.esri.com/server");
1927
+ });
1928
+
1929
+ it("should not lowercase path names", () => {
1930
+ const session = new UserSession({
1931
+ clientId: "id",
1932
+ token: "token",
1933
+ tokenExpires: TOMORROW,
1934
+ });
1935
+
1936
+ const root = session.getServerRootUrl(
1937
+ "https://pnp00035.esri.com/tiles/LkFyxb9zDq7vAOAm/arcgis/rest/services/NB_Stereographic/VectorTileServer"
1938
+ );
1939
+ expect(root).toEqual(
1940
+ "https://pnp00035.esri.com/tiles/LkFyxb9zDq7vAOAm/arcgis"
1941
+ );
1942
+ });
1943
+
1944
+ it("should respect the original https/http protocol", () => {
1945
+ const session = new UserSession({
1946
+ clientId: "id",
1947
+ token: "token",
1948
+ tokenExpires: TOMORROW,
1949
+ });
1950
+
1951
+ const root = session.getServerRootUrl(
1952
+ "http://pnp00035.esri.com/tiles/LkFyxb9zDq7vAOAm/arcgis/rest/services/NB_Stereographic/VectorTileServer"
1953
+ );
1954
+ expect(root).toEqual(
1955
+ "http://pnp00035.esri.com/tiles/LkFyxb9zDq7vAOAm/arcgis"
1956
+ );
1957
+ });
1958
+ });
1959
+
1960
+ describe("non-federated server", () => {
1961
+ it("shouldnt fetch a fresh token if the current one isn't expired.", (done) => {
1962
+ const MOCK_USER_SESSION = new UserSession({
1963
+ username: "c@sey",
1964
+ password: "123456",
1965
+ token: "token",
1966
+ tokenExpires: TOMORROW,
1967
+ server: "https://fakeserver.com/arcgis",
1968
+ });
1969
+
1970
+ MOCK_USER_SESSION.getToken(
1971
+ "https://fakeserver.com/arcgis/rest/services/Fake/MapServer/"
1972
+ )
1973
+ .then((token) => {
1974
+ expect(token).toBe("token");
1975
+ done();
1976
+ })
1977
+ .catch((err) => {
1978
+ fail(err);
1979
+ });
1980
+ });
1981
+
1982
+ it("should fetch a fresh token if the current one is expired.", (done) => {
1983
+ const MOCK_USER_SESSION = new UserSession({
1984
+ username: "jsmith",
1985
+ password: "123456",
1986
+ token: "token",
1987
+ tokenExpires: YESTERDAY,
1988
+ server: "https://fakeserver.com/arcgis",
1989
+ });
1990
+
1991
+ fetchMock.postOnce("https://fakeserver.com/arcgis/rest/info", {
1992
+ currentVersion: 10.61,
1993
+ fullVersion: "10.6.1",
1994
+ authInfo: {
1995
+ isTokenBasedSecurity: true,
1996
+ tokenServicesUrl: "https://fakeserver.com/arcgis/tokens/",
1997
+ },
1998
+ });
1999
+
2000
+ fetchMock.postOnce("https://fakeserver.com/arcgis/tokens/", {
2001
+ token: "fresh-token",
2002
+ expires: TOMORROW.getTime(),
2003
+ username: " jsmith",
2004
+ });
2005
+
2006
+ MOCK_USER_SESSION.getToken(
2007
+ "https://fakeserver.com/arcgis/rest/services/Fake/MapServer/"
2008
+ )
2009
+ .then((token) => {
2010
+ expect(token).toBe("fresh-token");
2011
+ const [url, options]: [string, RequestInit] = fetchMock.lastCall(
2012
+ "https://fakeserver.com/arcgis/tokens/"
2013
+ );
2014
+ expect(options.method).toBe("POST");
2015
+ expect(options.body).toContain("f=json");
2016
+ expect(options.body).toContain("username=jsmith");
2017
+ expect(options.body).toContain("password=123456");
2018
+ expect(options.body).toContain("client=referer");
2019
+ done();
2020
+ })
2021
+ .catch((err) => {
2022
+ fail(err);
2023
+ });
2024
+ });
2025
+
2026
+ it("should trim down the server url if necessary.", (done) => {
2027
+ const MOCK_USER_SESSION = new UserSession({
2028
+ username: "jsmith",
2029
+ password: "123456",
2030
+ token: "token",
2031
+ tokenExpires: YESTERDAY,
2032
+ server: "https://fakeserver.com/arcgis/rest/services/blah/",
2033
+ });
2034
+
2035
+ fetchMock.postOnce("https://fakeserver.com/arcgis/rest/info", {
2036
+ currentVersion: 10.61,
2037
+ fullVersion: "10.6.1",
2038
+ authInfo: {
2039
+ isTokenBasedSecurity: true,
2040
+ tokenServicesUrl: "https://fakeserver.com/arcgis/tokens/",
2041
+ },
2042
+ });
2043
+
2044
+ fetchMock.postOnce("https://fakeserver.com/arcgis/tokens/", {
2045
+ token: "fresh-token",
2046
+ expires: TOMORROW.getTime(),
2047
+ username: " jsmith",
2048
+ });
2049
+
2050
+ MOCK_USER_SESSION.getToken(
2051
+ "https://fakeserver.com/arcgis/rest/services/Fake/MapServer/"
2052
+ )
2053
+ .then((token) => {
2054
+ expect(token).toBe("fresh-token");
2055
+ done();
2056
+ })
2057
+ .catch((err) => {
2058
+ fail(err);
2059
+ });
2060
+ });
2061
+
2062
+ it("should throw an error if the server isnt trusted.", (done) => {
2063
+ fetchMock.postOnce("https://fakeserver2.com/arcgis/rest/info", {
2064
+ currentVersion: 10.61,
2065
+ fullVersion: "10.6.1",
2066
+ authInfo: {
2067
+ isTokenBasedSecurity: true,
2068
+ tokenServicesUrl: "https://fakeserver2.com/arcgis/tokens/",
2069
+ },
2070
+ });
2071
+ const MOCK_USER_SESSION = new UserSession({
2072
+ username: "c@sey",
2073
+ password: "123456",
2074
+ token: "token",
2075
+ tokenExpires: TOMORROW,
2076
+ server: "https://fakeserver.com/arcgis",
2077
+ });
2078
+
2079
+ MOCK_USER_SESSION.getToken(
2080
+ "https://fakeserver2.com/arcgis/rest/services/Fake/MapServer/"
2081
+ )
2082
+ .then((token) => {
2083
+ fail(token);
2084
+ })
2085
+ .catch((err) => {
2086
+ expect(err.code).toBe("NOT_FEDERATED");
2087
+ expect(err.originalMessage).toEqual(
2088
+ "https://fakeserver2.com/arcgis/rest/services/Fake/MapServer/ is not federated with any portal and is not explicitly trusted."
2089
+ );
2090
+ done();
2091
+ });
2092
+ });
2093
+ });
2094
+
2095
+ describe(".getPortal()", () => {
2096
+ afterEach(fetchMock.restore);
2097
+
2098
+ it("should cache metadata about the portal", (done) => {
2099
+ // we intentionally only mock one response
2100
+ fetchMock.once(
2101
+ "https://www.arcgis.com/sharing/rest/portals/self?f=json&token=token",
2102
+ {
2103
+ authorizedCrossOriginDomains: ["gis.city.com"],
2104
+ }
2105
+ );
2106
+
2107
+ const session = new UserSession({
2108
+ clientId: "clientId",
2109
+ redirectUri: "https://example-app.com/redirect-uri",
2110
+ token: "token",
2111
+ tokenExpires: TOMORROW,
2112
+ refreshToken: "refreshToken",
2113
+ refreshTokenExpires: TOMORROW,
2114
+ refreshTokenTTL: 1440,
2115
+ username: "jsmith",
2116
+ password: "123456",
2117
+ });
2118
+
2119
+ session
2120
+ .getPortal()
2121
+ .then((response) => {
2122
+ expect(response.authorizedCrossOriginDomains).toEqual([
2123
+ "gis.city.com",
2124
+ ]);
2125
+ session
2126
+ .getPortal()
2127
+ .then((cachedResponse) => {
2128
+ expect(cachedResponse.authorizedCrossOriginDomains).toEqual([
2129
+ "gis.city.com",
2130
+ ]);
2131
+ done();
2132
+ })
2133
+ .catch((e) => {
2134
+ fail(e);
2135
+ });
2136
+ })
2137
+ .catch((e) => {
2138
+ fail(e);
2139
+ });
2140
+ });
2141
+
2142
+ it("should never make more then 1 request", (done) => {
2143
+ // we intentionally only mock one response
2144
+ fetchMock.once(
2145
+ "https://www.arcgis.com/sharing/rest/portals/self?f=json&token=token",
2146
+ {
2147
+ authorizedCrossOriginDomains: ["gis.city.com"],
2148
+ }
2149
+ );
2150
+
2151
+ const session = new UserSession({
2152
+ clientId: "clientId",
2153
+ redirectUri: "https://example-app.com/redirect-uri",
2154
+ token: "token",
2155
+ tokenExpires: TOMORROW,
2156
+ refreshToken: "refreshToken",
2157
+ refreshTokenExpires: TOMORROW,
2158
+ refreshTokenTTL: 1440,
2159
+ username: "jsmith",
2160
+ password: "123456",
2161
+ });
2162
+
2163
+ Promise.all([session.getPortal(), session.getPortal()])
2164
+ .then(() => {
2165
+ done();
2166
+ })
2167
+ .catch((e) => {
2168
+ fail(e);
2169
+ });
2170
+ });
2171
+ });
2172
+
2173
+ describe("fetchAuthorizedDomains/getDomainCredentials", () => {
2174
+ it("should default to same-origin credentials when no domains are listed in authorizedCrossOriginDomains", (done) => {
2175
+ const session = new UserSession({
2176
+ clientId: "id",
2177
+ token: "token",
2178
+ refreshToken: "refresh",
2179
+ tokenExpires: TOMORROW,
2180
+ portal: "https://gis.city.gov/sharing/rest",
2181
+ });
2182
+
2183
+ fetchMock.postOnce("https://gisservices.city.gov/public/rest/info", {
2184
+ currentVersion: 10.51,
2185
+ fullVersion: "10.5.1.120",
2186
+ owningSystemUrl: "https://gis.city.gov",
2187
+ authInfo: {
2188
+ isTokenBasedSecurity: true,
2189
+ tokenServicesUrl: "https://gis.city.gov/sharing/generateToken",
2190
+ },
2191
+ });
2192
+
2193
+ fetchMock.getOnce(
2194
+ "https://gis.city.gov/sharing/rest/portals/self?f=json&token=token",
2195
+ {
2196
+ authorizedCrossOriginDomains: [],
2197
+ }
2198
+ );
2199
+
2200
+ fetchMock.postOnce("https://gis.city.gov/sharing/rest/info", {
2201
+ owningSystemUrl: "http://gis.city.gov",
2202
+ authInfo: {
2203
+ tokenServicesUrl: "https://gis.city.gov/sharing/generateToken",
2204
+ isTokenBasedSecurity: true,
2205
+ },
2206
+ });
2207
+
2208
+ fetchMock.postOnce("https://gis.city.gov/sharing/generateToken", {
2209
+ token: "serverToken",
2210
+ expires: TOMORROW,
2211
+ });
2212
+
2213
+ fetchMock.post(
2214
+ "https://gisservices.city.gov/public/rest/services/trees/FeatureServer/0/query",
2215
+ {
2216
+ count: 123,
2217
+ }
2218
+ );
2219
+
2220
+ request(
2221
+ "https://gisservices.city.gov/public/rest/services/trees/FeatureServer/0/query",
2222
+ {
2223
+ authentication: session,
2224
+ }
2225
+ )
2226
+ .then((response) => {
2227
+ const { credentials } = fetchMock.lastOptions(
2228
+ "https://gisservices.city.gov/public/rest/services/trees/FeatureServer/0/query"
2229
+ );
2230
+ expect(credentials).toEqual("same-origin");
2231
+
2232
+ done();
2233
+ })
2234
+ .catch((e) => {
2235
+ fail(e);
2236
+ });
2237
+ });
2238
+
2239
+ it("should set the credentials option to include when a server is listed in authorizedCrossOriginDomains", (done) => {
2240
+ const session = new UserSession({
2241
+ clientId: "id",
2242
+ token: "token",
2243
+ refreshToken: "refresh",
2244
+ tokenExpires: TOMORROW,
2245
+ portal: "https://gis.city.gov/sharing/rest",
2246
+ });
2247
+
2248
+ fetchMock.postOnce("https://gisservices.city.gov/public/rest/info", {
2249
+ currentVersion: 10.51,
2250
+ fullVersion: "10.5.1.120",
2251
+ owningSystemUrl: "https://gis.city.gov",
2252
+ authInfo: {
2253
+ isTokenBasedSecurity: true,
2254
+ tokenServicesUrl: "https://gis.city.gov/sharing/generateToken",
2255
+ },
2256
+ });
2257
+
2258
+ fetchMock.getOnce(
2259
+ "https://gis.city.gov/sharing/rest/portals/self?f=json&token=token",
2260
+ {
2261
+ authorizedCrossOriginDomains: ["https://gisservices.city.gov"],
2262
+ }
2263
+ );
2264
+
2265
+ fetchMock.postOnce("https://gis.city.gov/sharing/rest/info", {
2266
+ owningSystemUrl: "http://gis.city.gov",
2267
+ authInfo: {
2268
+ tokenServicesUrl: "https://gis.city.gov/sharing/generateToken",
2269
+ isTokenBasedSecurity: true,
2270
+ },
2271
+ });
2272
+
2273
+ fetchMock.postOnce("https://gis.city.gov/sharing/generateToken", {
2274
+ token: "serverToken",
2275
+ expires: TOMORROW,
2276
+ });
2277
+
2278
+ fetchMock.post(
2279
+ "https://gisservices.city.gov/public/rest/services/trees/FeatureServer/0/query",
2280
+ {
2281
+ count: 123,
2282
+ }
2283
+ );
2284
+
2285
+ request(
2286
+ "https://gisservices.city.gov/public/rest/services/trees/FeatureServer/0/query",
2287
+ {
2288
+ authentication: session,
2289
+ }
2290
+ )
2291
+ .then((response) => {
2292
+ const { credentials } = fetchMock.lastOptions(
2293
+ "https://gisservices.city.gov/public/rest/services/trees/FeatureServer/0/query"
2294
+ );
2295
+ expect(credentials).toEqual("include");
2296
+
2297
+ done();
2298
+ })
2299
+ .catch((e) => {
2300
+ fail(e);
2301
+ });
2302
+ });
2303
+ });
2304
+
2305
+ it("should still send same-origin credentials even if another domain is listed in authorizedCrossOriginDomains", (done) => {
2306
+ const session = new UserSession({
2307
+ clientId: "id",
2308
+ token: "token",
2309
+ refreshToken: "refresh",
2310
+ tokenExpires: TOMORROW,
2311
+ portal: "https://gis.city.gov/sharing/rest",
2312
+ });
2313
+
2314
+ fetchMock.postOnce("https://gisservices.city.gov/public/rest/info", {
2315
+ currentVersion: 10.51,
2316
+ fullVersion: "10.5.1.120",
2317
+ owningSystemUrl: "https://gis.city.gov",
2318
+ authInfo: {
2319
+ isTokenBasedSecurity: true,
2320
+ tokenServicesUrl: "https://gis.city.gov/sharing/generateToken",
2321
+ },
2322
+ });
2323
+
2324
+ fetchMock.getOnce(
2325
+ "https://gis.city.gov/sharing/rest/portals/self?f=json&token=token",
2326
+ {
2327
+ authorizedCrossOriginDomains: ["https://other.city.gov"],
2328
+ }
2329
+ );
2330
+
2331
+ fetchMock.postOnce("https://gis.city.gov/sharing/rest/info", {
2332
+ owningSystemUrl: "http://gis.city.gov",
2333
+ authInfo: {
2334
+ tokenServicesUrl: "https://gis.city.gov/sharing/generateToken",
2335
+ isTokenBasedSecurity: true,
2336
+ },
2337
+ });
2338
+
2339
+ fetchMock.postOnce("https://gis.city.gov/sharing/generateToken", {
2340
+ token: "serverToken",
2341
+ expires: TOMORROW,
2342
+ });
2343
+
2344
+ fetchMock.post(
2345
+ "https://gisservices.city.gov/public/rest/services/trees/FeatureServer/0/query",
2346
+ {
2347
+ count: 123,
2348
+ }
2349
+ );
2350
+
2351
+ request(
2352
+ "https://gisservices.city.gov/public/rest/services/trees/FeatureServer/0/query",
2353
+ {
2354
+ authentication: session,
2355
+ }
2356
+ )
2357
+ .then((response) => {
2358
+ const { credentials } = fetchMock.lastOptions(
2359
+ "https://gisservices.city.gov/public/rest/services/trees/FeatureServer/0/query"
2360
+ );
2361
+ expect(credentials).toEqual("same-origin");
2362
+
2363
+ done();
2364
+ })
2365
+ .catch((e) => {
2366
+ fail(e);
2367
+ });
2368
+ });
2369
+
2370
+ it("should normalize optional protocols in authorizedCrossOriginDomains", (done) => {
2371
+ const session = new UserSession({
2372
+ clientId: "id",
2373
+ token: "token",
2374
+ refreshToken: "refresh",
2375
+ tokenExpires: TOMORROW,
2376
+ portal: "https://gis.city.gov/sharing/rest",
2377
+ });
2378
+
2379
+ fetchMock.getOnce(
2380
+ "https://gis.city.gov/sharing/rest/portals/self?f=json&token=token",
2381
+ {
2382
+ authorizedCrossOriginDomains: ["one.city.gov", "https://two.city.gov"],
2383
+ }
2384
+ );
2385
+
2386
+ (session as any)
2387
+ .fetchAuthorizedDomains()
2388
+ .then(() => {
2389
+ expect((session as any).trustedDomains).toEqual([
2390
+ "https://one.city.gov",
2391
+ "https://two.city.gov",
2392
+ ]);
2393
+ done();
2394
+ })
2395
+ .catch((e: Error) => {
2396
+ fail(e);
2397
+ });
2398
+ });
2399
+
2400
+ it("should not use domain credentials if portal is null", (done) => {
2401
+ const session = new UserSession({
2402
+ clientId: "id",
2403
+ token: "token",
2404
+ refreshToken: "refresh",
2405
+ tokenExpires: TOMORROW,
2406
+ portal: null,
2407
+ server: "https://fakeserver.com/arcgis",
2408
+ });
2409
+
2410
+ (session as any)
2411
+ .fetchAuthorizedDomains()
2412
+ .then(() => {
2413
+ done();
2414
+ })
2415
+ .catch((e: Error) => {
2416
+ fail(e);
2417
+ });
2418
+ });
2419
+
2420
+ it("should deprecate trustedServers", () => {
2421
+ const session = new UserSession({
2422
+ clientId: "id",
2423
+ token: "token",
2424
+ });
2425
+
2426
+ expect((session as any).trustedServers).toBe(
2427
+ (session as any).federatedServers
2428
+ );
2429
+ });
2430
+ });