etincidunt 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 (226) hide show
  1. package/.prettierignore +2 -0
  2. package/.travis.yml +29 -0
  3. package/.vscode/launch.json +24 -0
  4. package/.vscode/settings.json +3 -0
  5. package/demos/ago-node-cli/README.md +29 -0
  6. package/demos/ago-node-cli/ago.js +32 -0
  7. package/demos/ago-node-cli/index.js +11 -0
  8. package/demos/ago-node-cli/lib/item-export-command.js +48 -0
  9. package/demos/ago-node-cli/lib/item-search-command.js +35 -0
  10. package/demos/ago-node-cli/package-lock.json +172 -0
  11. package/demos/ago-node-cli/package.json +30 -0
  12. package/demos/attachments/README.md +5 -0
  13. package/demos/attachments/index.html +164 -0
  14. package/demos/attachments/package-lock.json +182 -0
  15. package/demos/attachments/package.json +18 -0
  16. package/demos/batch-geocoder-node/NYC_Restaurant_Inspection_Results.csv +100 -0
  17. package/demos/batch-geocoder-node/README.md +14 -0
  18. package/demos/batch-geocoder-node/batch-geocode.js +112 -0
  19. package/demos/batch-geocoder-node/config-template.js +18 -0
  20. package/demos/batch-geocoder-node/package-lock.json +109 -0
  21. package/demos/batch-geocoder-node/package.json +37 -0
  22. package/demos/express/README.md +10 -0
  23. package/demos/express/config.json.template +3 -0
  24. package/demos/express/package-lock.json +388 -0
  25. package/demos/express/package.json +18 -0
  26. package/demos/express/server.js +28 -0
  27. package/demos/feature-service-browser/README.md +6 -0
  28. package/demos/feature-service-browser/index.html +122 -0
  29. package/demos/feature-service-browser/package-lock.json +182 -0
  30. package/demos/feature-service-browser/package.json +18 -0
  31. package/demos/geocoder-browser/README.md +10 -0
  32. package/demos/geocoder-browser/config.js.template +1 -0
  33. package/demos/geocoder-browser/index.html +131 -0
  34. package/demos/geocoder-browser/package-lock.json +163 -0
  35. package/demos/geocoder-browser/package.json +19 -0
  36. package/demos/geocoder-browser/post-sign-in.html +25 -0
  37. package/demos/jsapi-integration/README.md +8 -0
  38. package/demos/jsapi-integration/config.js +6 -0
  39. package/demos/jsapi-integration/index.html +79 -0
  40. package/demos/jsapi-integration/package-lock.json +184 -0
  41. package/demos/jsapi-integration/package.json +19 -0
  42. package/demos/oauth2-browser/README.md +12 -0
  43. package/demos/oauth2-browser/authenticate.html +32 -0
  44. package/demos/oauth2-browser/config.js.template +6 -0
  45. package/demos/oauth2-browser/index.html +202 -0
  46. package/demos/oauth2-browser/logo.svg +4 -0
  47. package/demos/oauth2-browser/package-lock.json +163 -0
  48. package/demos/oauth2-browser/package.json +18 -0
  49. package/demos/oauth2-browser/style.css +36 -0
  50. package/demos/vue/.babelrc +6 -0
  51. package/demos/vue/.env.example +8 -0
  52. package/demos/vue/README.md +17 -0
  53. package/demos/vue/index.html +21 -0
  54. package/demos/vue/package-lock.json +7236 -0
  55. package/demos/vue/package.json +39 -0
  56. package/demos/vue/src/assets/logo.svg +29 -0
  57. package/demos/vue/src/components/App.vue +302 -0
  58. package/demos/vue/src/components/Authenticate.vue +68 -0
  59. package/demos/vue/src/components/Loader.vue +216 -0
  60. package/demos/vue/src/main.js +75 -0
  61. package/demos/vue/webpack.config.js +84 -0
  62. package/docs/FAQ.md +28 -0
  63. package/docs/HISTORY.md +62 -0
  64. package/docs/acetate.config.js +214 -0
  65. package/docs/build-typedoc.js +301 -0
  66. package/docs/src/_layout.html +82 -0
  67. package/docs/src/api/_declaration.html +496 -0
  68. package/docs/src/api/_layout.html +127 -0
  69. package/docs/src/api/_package.html +13 -0
  70. package/docs/src/api/index.html +23 -0
  71. package/docs/src/guides/_layout.html +24 -0
  72. package/docs/src/guides/amd-requirejs-dojo.md +40 -0
  73. package/docs/src/guides/babel-and-rollup.md +30 -0
  74. package/docs/src/guides/babel-and-webpack.md +30 -0
  75. package/docs/src/guides/browser-authentication.md +9 -0
  76. package/docs/src/guides/browserify.md +9 -0
  77. package/docs/src/guides/cli-authentication.md +9 -0
  78. package/docs/src/guides/client-server-authentication.md +9 -0
  79. package/docs/src/guides/from-a-cdn.md +36 -0
  80. package/docs/src/guides/index.md +52 -0
  81. package/docs/src/guides/node.md +30 -0
  82. package/docs/src/guides/package-overview.md +8 -0
  83. package/docs/src/guides/server-authentication.md +9 -0
  84. package/docs/src/guides/typescript-and-webpack.md +9 -0
  85. package/docs/src/img/icons.png +0 -0
  86. package/docs/src/img/icons@2x.png +0 -0
  87. package/docs/src/index.html +12 -0
  88. package/docs/src/js/api-search.js +113 -0
  89. package/docs/src/js/index.js +1 -0
  90. package/docs/src/js/nav-toggle.js +41 -0
  91. package/docs/src/sass/_highlight.scss +96 -0
  92. package/docs/src/sass/_icons.scss +157 -0
  93. package/docs/src/sass/style.scss +169 -0
  94. package/jasmine.json +7 -0
  95. package/karma.conf.js +100 -0
  96. package/lerna.json +8 -0
  97. package/notes/README.md +88 -0
  98. package/package.json +91 -0
  99. package/packages/arcgis-rest-auth/README.md +64 -0
  100. package/packages/arcgis-rest-auth/package-lock.json +11 -0
  101. package/packages/arcgis-rest-auth/package.json +51 -0
  102. package/packages/arcgis-rest-auth/src/ApplicationSession.ts +91 -0
  103. package/packages/arcgis-rest-auth/src/UserSession.ts +829 -0
  104. package/packages/arcgis-rest-auth/src/authenticated-request-options.ts +21 -0
  105. package/packages/arcgis-rest-auth/src/fetch-token.ts +55 -0
  106. package/packages/arcgis-rest-auth/src/generate-token.ts +36 -0
  107. package/packages/arcgis-rest-auth/src/index.ts +5 -0
  108. package/packages/arcgis-rest-auth/test/ApplicationSession.test.ts +121 -0
  109. package/packages/arcgis-rest-auth/test/UserSession.test.ts +883 -0
  110. package/packages/arcgis-rest-auth/test/fetchToken.test.ts +76 -0
  111. package/packages/arcgis-rest-auth/test/generateToken.test.ts +36 -0
  112. package/packages/arcgis-rest-auth/test/utils.ts +11 -0
  113. package/packages/arcgis-rest-auth/tsconfig.json +6 -0
  114. package/packages/arcgis-rest-common-types/README.md +61 -0
  115. package/packages/arcgis-rest-common-types/package.json +38 -0
  116. package/packages/arcgis-rest-common-types/src/group.ts +51 -0
  117. package/packages/arcgis-rest-common-types/src/index.ts +467 -0
  118. package/packages/arcgis-rest-common-types/src/item.ts +45 -0
  119. package/packages/arcgis-rest-common-types/src/webmap.ts +1225 -0
  120. package/packages/arcgis-rest-common-types/tsconfig.json +11 -0
  121. package/packages/arcgis-rest-feature-service/README.md +70 -0
  122. package/packages/arcgis-rest-feature-service/package-lock.json +11 -0
  123. package/packages/arcgis-rest-feature-service/package.json +50 -0
  124. package/packages/arcgis-rest-feature-service/src/add.ts +82 -0
  125. package/packages/arcgis-rest-feature-service/src/addAttachment.ts +65 -0
  126. package/packages/arcgis-rest-feature-service/src/delete.ts +85 -0
  127. package/packages/arcgis-rest-feature-service/src/deleteAttachments.ts +68 -0
  128. package/packages/arcgis-rest-feature-service/src/getAttachments.ts +64 -0
  129. package/packages/arcgis-rest-feature-service/src/helpers.ts +77 -0
  130. package/packages/arcgis-rest-feature-service/src/index.ts +8 -0
  131. package/packages/arcgis-rest-feature-service/src/query.ts +174 -0
  132. package/packages/arcgis-rest-feature-service/src/update.ts +81 -0
  133. package/packages/arcgis-rest-feature-service/src/updateAttachment.ts +74 -0
  134. package/packages/arcgis-rest-feature-service/test/attachments.test.ts +179 -0
  135. package/packages/arcgis-rest-feature-service/test/features.test.ts +172 -0
  136. package/packages/arcgis-rest-feature-service/test/mocks/feature.ts +220 -0
  137. package/packages/arcgis-rest-feature-service/test/mocks/foo.txt +1 -0
  138. package/packages/arcgis-rest-feature-service/tsconfig.json +6 -0
  139. package/packages/arcgis-rest-geocoder/README.md +73 -0
  140. package/packages/arcgis-rest-geocoder/package-lock.json +11 -0
  141. package/packages/arcgis-rest-geocoder/package.json +52 -0
  142. package/packages/arcgis-rest-geocoder/src/bulk.ts +102 -0
  143. package/packages/arcgis-rest-geocoder/src/geocode.ts +117 -0
  144. package/packages/arcgis-rest-geocoder/src/helpers.ts +81 -0
  145. package/packages/arcgis-rest-geocoder/src/index.ts +4 -0
  146. package/packages/arcgis-rest-geocoder/src/reverse.ts +84 -0
  147. package/packages/arcgis-rest-geocoder/src/suggest.ts +72 -0
  148. package/packages/arcgis-rest-geocoder/test/geocoder.test.ts +510 -0
  149. package/packages/arcgis-rest-geocoder/test/mocks/responses.ts +588 -0
  150. package/packages/arcgis-rest-geocoder/tsconfig.json +6 -0
  151. package/packages/arcgis-rest-groups/README.md +64 -0
  152. package/packages/arcgis-rest-groups/package-lock.json +11 -0
  153. package/packages/arcgis-rest-groups/package.json +52 -0
  154. package/packages/arcgis-rest-groups/src/groups.ts +272 -0
  155. package/packages/arcgis-rest-groups/src/index.ts +1 -0
  156. package/packages/arcgis-rest-groups/test/groups.test.ts +280 -0
  157. package/packages/arcgis-rest-groups/test/mocks/responses.ts +137 -0
  158. package/packages/arcgis-rest-groups/tsconfig.json +6 -0
  159. package/packages/arcgis-rest-items/README.md +66 -0
  160. package/packages/arcgis-rest-items/package-lock.json +11 -0
  161. package/packages/arcgis-rest-items/package.json +52 -0
  162. package/packages/arcgis-rest-items/src/index.ts +1 -0
  163. package/packages/arcgis-rest-items/src/items.ts +498 -0
  164. package/packages/arcgis-rest-items/test/items.test.ts +1153 -0
  165. package/packages/arcgis-rest-items/test/mocks/foo.zip +0 -0
  166. package/packages/arcgis-rest-items/test/mocks/item.ts +30 -0
  167. package/packages/arcgis-rest-items/test/mocks/resources.ts +28 -0
  168. package/packages/arcgis-rest-items/test/mocks/search.ts +60 -0
  169. package/packages/arcgis-rest-items/tsconfig.json +6 -0
  170. package/packages/arcgis-rest-request/README.md +65 -0
  171. package/packages/arcgis-rest-request/package-lock.json +11 -0
  172. package/packages/arcgis-rest-request/package.json +42 -0
  173. package/packages/arcgis-rest-request/src/index.ts +10 -0
  174. package/packages/arcgis-rest-request/src/request.ts +259 -0
  175. package/packages/arcgis-rest-request/src/utils/ArcGISAuthError.ts +67 -0
  176. package/packages/arcgis-rest-request/src/utils/ArcGISRequestError.ts +73 -0
  177. package/packages/arcgis-rest-request/src/utils/ErrorTypes.ts +29 -0
  178. package/packages/arcgis-rest-request/src/utils/check-for-errors.ts +65 -0
  179. package/packages/arcgis-rest-request/src/utils/encode-form-data.ts +29 -0
  180. package/packages/arcgis-rest-request/src/utils/encode-query-string.ts +23 -0
  181. package/packages/arcgis-rest-request/src/utils/get-portal-url.ts +25 -0
  182. package/packages/arcgis-rest-request/src/utils/get-portal.ts +45 -0
  183. package/packages/arcgis-rest-request/src/utils/process-params.ts +99 -0
  184. package/packages/arcgis-rest-request/test/mocks/errors.ts +59 -0
  185. package/packages/arcgis-rest-request/test/mocks/geojson-feature-collection.ts +10 -0
  186. package/packages/arcgis-rest-request/test/mocks/portal.ts +109 -0
  187. package/packages/arcgis-rest-request/test/mocks/sharing-rest-info.ts +38 -0
  188. package/packages/arcgis-rest-request/test/mocks/webmap.ts +38 -0
  189. package/packages/arcgis-rest-request/test/request.test.ts +296 -0
  190. package/packages/arcgis-rest-request/test/utils/ArcGISAuthError.test.ts +167 -0
  191. package/packages/arcgis-rest-request/test/utils/ArcGISRequestError.test.ts +40 -0
  192. package/packages/arcgis-rest-request/test/utils/check-for-errors.test.ts +101 -0
  193. package/packages/arcgis-rest-request/test/utils/encode-form-data.test.ts +112 -0
  194. package/packages/arcgis-rest-request/test/utils/get-portal-url.test.ts +34 -0
  195. package/packages/arcgis-rest-request/test/utils/portal.test.ts +94 -0
  196. package/packages/arcgis-rest-request/test/utils/process-params.test.ts +190 -0
  197. package/packages/arcgis-rest-request/tsconfig.json +6 -0
  198. package/packages/arcgis-rest-sharing/README.md +67 -0
  199. package/packages/arcgis-rest-sharing/package-lock.json +11 -0
  200. package/packages/arcgis-rest-sharing/package.json +55 -0
  201. package/packages/arcgis-rest-sharing/src/access.ts +91 -0
  202. package/packages/arcgis-rest-sharing/src/group-sharing.ts +212 -0
  203. package/packages/arcgis-rest-sharing/src/helpers.ts +92 -0
  204. package/packages/arcgis-rest-sharing/src/index.ts +2 -0
  205. package/packages/arcgis-rest-sharing/test/access.test.ts +153 -0
  206. package/packages/arcgis-rest-sharing/test/group-sharing.test.ts +436 -0
  207. package/packages/arcgis-rest-sharing/test/mocks/sharing.ts +15 -0
  208. package/packages/arcgis-rest-sharing/tsconfig.json +6 -0
  209. package/packages/arcgis-rest-users/README.md +71 -0
  210. package/packages/arcgis-rest-users/package-lock.json +11 -0
  211. package/packages/arcgis-rest-users/package.json +51 -0
  212. package/packages/arcgis-rest-users/src/index.ts +1 -0
  213. package/packages/arcgis-rest-users/src/users.ts +70 -0
  214. package/packages/arcgis-rest-users/test/mocks/responses.ts +170 -0
  215. package/packages/arcgis-rest-users/test/users.test.ts +97 -0
  216. package/packages/arcgis-rest-users/tsconfig.json +6 -0
  217. package/support/FormData.d.ts +1 -0
  218. package/support/changelog.js +388 -0
  219. package/support/commit-template.txt +19 -0
  220. package/support/deploy-doc-site.js +16 -0
  221. package/support/publish.sh +40 -0
  222. package/support/test-helpers.js +8 -0
  223. package/tsconfig.json +69 -0
  224. package/tslint.json +14 -0
  225. package/umd-base-profile.js +82 -0
  226. package/umd-production-profile.js +13 -0
@@ -0,0 +1,829 @@
1
+ /* Copyright (c) 2017 Environmental Systems Research Institute, Inc.
2
+ * Apache-2.0 */
3
+
4
+ import * as http from "http";
5
+ import {
6
+ request,
7
+ ArcGISAuthError,
8
+ IAuthenticationManager
9
+ } from "@esri/arcgis-rest-request";
10
+ import { generateToken } from "./generate-token";
11
+ import { fetchToken, IFetchTokenResponse } from "./fetch-token";
12
+ import { IUser } from "@esri/arcgis-rest-common-types";
13
+
14
+ /**
15
+ * Internal utility for resolving a Promise from outside its constructor.
16
+ *
17
+ * See: http://lea.verou.me/2016/12/resolve-promises-externally-with-this-one-weird-trick/
18
+ */
19
+ interface IDeferred<T> {
20
+ promise: Promise<T>;
21
+ resolve: (v: T) => void;
22
+ reject: (v: any) => void;
23
+ }
24
+
25
+ export type AuthenticationProvider = "arcgis" | "facebook" | "google";
26
+
27
+ /**
28
+ * Represents a [credential]((https://developers.arcgis.com/javascript/latest/api-reference/esri-identity-Credential.html)) object used to access a secure ArcGIS resource.
29
+ */
30
+ export interface ICredential {
31
+ expires: number;
32
+ server: string;
33
+ ssl: boolean;
34
+ token: string;
35
+ userId: string;
36
+ }
37
+
38
+ function defer<T>(): IDeferred<T> {
39
+ const deferred: any = {
40
+ promise: null,
41
+ resolve: null,
42
+ reject: null
43
+ };
44
+
45
+ deferred.promise = new Promise((resolve, reject) => {
46
+ deferred.resolve = resolve;
47
+ deferred.reject = reject;
48
+ });
49
+
50
+ return deferred as IDeferred<T>;
51
+ }
52
+
53
+ /**
54
+ * Options for static OAuth 2.0 helper methods on `UserSession`.
55
+ */
56
+ export interface IOauth2Options {
57
+ /**
58
+ * Client ID of your application. Can be obtained by registering an application
59
+ * on [ArcGIS for Developers](https://developers.arcgis.com/documentation/core-concepts/security-and-authentication/signing-in-arcgis-online-users/#registering-your-application),
60
+ * [ArcGIS Online](http://doc.arcgis.com/en/arcgis-online/share-maps/add-items.htm#ESRI_SECTION1_0D1B620254F745AE84F394289F8AF44B) or on your instance of ArcGIS Enterprise.
61
+ */
62
+ clientId: string;
63
+
64
+ /**
65
+ * A valid URL to redirect to after a user authorizes your application. Can be set on [ArcGIS for Developers](https://developers.arcgis.com/documentation/core-concepts/security-and-authentication/signing-in-arcgis-online-users/#registering-your-application),
66
+ * [ArcGIS Online](http://doc.arcgis.com/en/arcgis-online/share-maps/add-items.htm#ESRI_SECTION1_0D1B620254F745AE84F394289F8AF44B) or on your instance of ArcGIS Enterprise.
67
+ */
68
+ redirectUri: string;
69
+
70
+ /**
71
+ * The ArcGIS Online or ArcGIS Enterprise portal you want to use for authentication. Defaults to `https://www.arcgis.com/sharing/rest` for the ArcGIS Online portal.
72
+ */
73
+ portal?: string;
74
+
75
+ /**
76
+ * ArcGIS Authentication is used by default. Specifying an alternative will take users directly to the corresponding provider's OAuth page.
77
+ */
78
+ provider?: AuthenticationProvider;
79
+
80
+ /**
81
+ * Duration (in minutes) that a token will be valid. Defaults to 20160 (two weeks).
82
+ */
83
+ duration?: number;
84
+
85
+ /**
86
+ * Determines whether to open the authorization window in a new tab/window or in the current window.
87
+ *
88
+ * @browserOnly
89
+ */
90
+ popup?: boolean;
91
+
92
+ /**
93
+ * Duration (in minutes) that a refresh token will be valid.
94
+ *
95
+ * @nodeOnly
96
+ */
97
+ refreshTokenTTL?: number;
98
+
99
+ /**
100
+ * The locale assumed to render the login page.
101
+ *
102
+ * @browserOnly
103
+ */
104
+ locale?: string;
105
+
106
+ /**
107
+ * Applications can specify an opaque value for this parameter to correlate the authorization request sent with the received response. By default, clientId is used.
108
+ *
109
+ * @browserOnly
110
+ */
111
+ state?: string;
112
+ }
113
+
114
+ /**
115
+ * Options for the `UserSession` constructor.
116
+ */
117
+ export interface IUserSessionOptions {
118
+ /**
119
+ * Client ID of your application. Can be obtained by registering an application
120
+ * on [ArcGIS for Developers](https://developers.arcgis.com/documentation/core-concepts/security-and-authentication/signing-in-arcgis-online-users/#registering-your-application),
121
+ * [ArcGIS Online](http://doc.arcgis.com/en/arcgis-online/share-maps/add-items.htm#ESRI_SECTION1_0D1B620254F745AE84F394289F8AF44B) or on your instance of ArcGIS Enterprise.
122
+ */
123
+ clientId?: string;
124
+
125
+ /**
126
+ * A valid URL to redirect to after a user authorizes your application. Can be set on [ArcGIS for Developers](https://developers.arcgis.com/documentation/core-concepts/security-and-authentication/signing-in-arcgis-online-users/#registering-your-application),
127
+ * [ArcGIS Online](http://doc.arcgis.com/en/arcgis-online/share-maps/add-items.htm#ESRI_SECTION1_0D1B620254F745AE84F394289F8AF44B) or on your instance of ArcGIS Enterprise.
128
+ */
129
+ redirectUri?: string;
130
+
131
+ /**
132
+ * OAuth 2.0 refresh token from a previous user session.
133
+ */
134
+ refreshToken?: string;
135
+
136
+ /**
137
+ * Expiration date of the `refreshToken`
138
+ */
139
+ refreshTokenExpires?: Date;
140
+
141
+ /**
142
+ * The authenticated user's username. Guaranteed to be unique across ArcGIS Online or your instance of ArcGIS Enterprise.
143
+ */
144
+ username?: string;
145
+
146
+ /**
147
+ * Password for this user. Used in CLI apps where users cannot do OAuth 2.0.
148
+ */
149
+ password?: string;
150
+
151
+ /**
152
+ * OAuth 2.0 access token from a previous user session.
153
+ */
154
+ token?: string;
155
+
156
+ /**
157
+ * Expiration date for the `token`
158
+ */
159
+ tokenExpires?: Date;
160
+
161
+ /**
162
+ * The ArcGIS Online or ArcGIS Enterprise portal you want to use for authentication. Defaults to `https://www.arcgis.com/sharing/rest` for the ArcGIS Online portal.
163
+ */
164
+ portal?: string;
165
+
166
+ /**
167
+ * ArcGIS Authentication is used by default. Specifying an alternative will take users directly to the corresponding provider's OAuth page.
168
+ */
169
+ provider?: AuthenticationProvider;
170
+
171
+ /**
172
+ * Duration of requested token validity in minutes. Used when requesting tokens with `username` and `password` or when validating the identity of unknown servers. Defaults to two weeks.
173
+ */
174
+ tokenDuration?: number;
175
+
176
+ /**
177
+ * Duration (in minutes) that a refresh token will be valid.
178
+ */
179
+ refreshTokenTTL?: number;
180
+ }
181
+
182
+ /**
183
+ * ```js
184
+ * const session = new UserSession({
185
+ * username: "jsmith",
186
+ * password: "123456"
187
+ * })
188
+ * ```
189
+ * Used to manage the authentication of ArcGIS Online and ArcGIS Enterprise users
190
+ * in `request`. This class also includes several
191
+ * helper methods for authenticating users with [OAuth 2.0](https://developers.arcgis.com/documentation/core-concepts/security-and-authentication/browser-based-user-logins/) in both browser and
192
+ * server applications.
193
+ *
194
+ */
195
+ export class UserSession implements IAuthenticationManager {
196
+ /**
197
+ * Client ID being used for authentication if provided in the `constructor`.
198
+ */
199
+ readonly clientId: string;
200
+
201
+ /**
202
+ * The currently authenticated user if provided in the `constructor`.
203
+ */
204
+ readonly username: string;
205
+
206
+ /**
207
+ * The currently authenticated user's password if provided in the `constructor`.
208
+ */
209
+ readonly password: string;
210
+
211
+ /**
212
+ * The current portal the user is authenticated with.
213
+ */
214
+ readonly portal: string;
215
+
216
+ /**
217
+ * The authentication provider to use.
218
+ */
219
+ readonly provider: AuthenticationProvider;
220
+
221
+ /**
222
+ * Determines how long new tokens requested are valid.
223
+ */
224
+ readonly tokenDuration: number;
225
+
226
+ /**
227
+ * A valid redirect URI for this application if provided in the `constructor`.
228
+ */
229
+ readonly redirectUri: string;
230
+
231
+ /**
232
+ * Duration of new OAuth 2.0 refresh token validity.
233
+ */
234
+ readonly refreshTokenTTL: number;
235
+
236
+ /**
237
+ * Hydrated by a call to [getUser()](#getUser-summary).
238
+ */
239
+ _user: IUser;
240
+
241
+ private _token: string;
242
+ private _tokenExpires: Date;
243
+ private _refreshToken: string;
244
+ private _refreshTokenExpires: Date;
245
+
246
+ /**
247
+ * Internal object to keep track of pending token requests. Used to prevent
248
+ * duplicate token requests.
249
+ */
250
+ private _pendingTokenRequests: {
251
+ [key: string]: Promise<string>;
252
+ };
253
+
254
+ /**
255
+ * Internal list of trusted 3rd party servers (federated servers) that have
256
+ * been validated with `generateToken`.
257
+ */
258
+ private trustedServers: {
259
+ [key: string]: {
260
+ token: string;
261
+ expires: Date;
262
+ };
263
+ };
264
+
265
+ /**
266
+ * The current ArcGIS Online or ArcGIS Enterprise `token`.
267
+ */
268
+ get token() {
269
+ return this._token;
270
+ }
271
+
272
+ /**
273
+ * The expiration time of the current `token`.
274
+ */
275
+ get tokenExpires() {
276
+ return this._tokenExpires;
277
+ }
278
+
279
+ /**
280
+ * The current token to ArcGIS Online or ArcGIS Enterprise.
281
+ */
282
+ get refreshToken() {
283
+ return this._refreshToken;
284
+ }
285
+
286
+ /**
287
+ * The expiration time of the current `refreshToken`.
288
+ */
289
+ get refreshTokenExpires() {
290
+ return this._refreshTokenExpires;
291
+ }
292
+
293
+ constructor(options: IUserSessionOptions) {
294
+ this.clientId = options.clientId;
295
+ this._refreshToken = options.refreshToken;
296
+ this._refreshTokenExpires = options.refreshTokenExpires;
297
+ this.username = options.username;
298
+ this.password = options.password;
299
+ this._token = options.token;
300
+ this._tokenExpires = options.tokenExpires;
301
+ this.portal = options.portal || "https://www.arcgis.com/sharing/rest";
302
+ this.provider = options.provider || "arcgis";
303
+ this.tokenDuration = options.tokenDuration || 20160;
304
+ this.redirectUri = options.redirectUri;
305
+ this.refreshTokenTTL = options.refreshTokenTTL || 1440;
306
+
307
+ this.trustedServers = {};
308
+ this._pendingTokenRequests = {};
309
+ }
310
+
311
+ /**
312
+ * Begins a new browser-based OAuth 2.0 sign in. If `options.popup` is true the
313
+ * authentication window will open in a new tab/window otherwise the user will
314
+ * be redirected to the authorization page in their current tab.
315
+ *
316
+ * @browserOnly
317
+ */
318
+ /* istanbul ignore next */
319
+ static beginOAuth2(options: IOauth2Options, win: any = window) {
320
+ const {
321
+ portal,
322
+ provider,
323
+ clientId,
324
+ duration,
325
+ redirectUri,
326
+ popup,
327
+ state,
328
+ locale
329
+ }: IOauth2Options = {
330
+ ...{
331
+ portal: "https://www.arcgis.com/sharing/rest",
332
+ provider: "arcgis",
333
+ duration: 20160,
334
+ popup: true,
335
+ state: options.clientId,
336
+ locale: ""
337
+ },
338
+ ...options
339
+ };
340
+ let url: string;
341
+ if (provider === "arcgis") {
342
+ url = `${portal}/oauth2/authorize?client_id=${clientId}&response_type=token&expiration=${duration}&redirect_uri=${encodeURIComponent(
343
+ redirectUri
344
+ )}&state=${state}&locale=${locale}`;
345
+ } else {
346
+ url = `${portal}/oauth2/social/authorize?client_id=${clientId}&socialLoginProviderName=${provider}&autoAccountCreateForSocial=true&response_type=token&expiration=${duration}&redirect_uri=${encodeURIComponent(
347
+ redirectUri
348
+ )}&state=${state}&locale=${locale}`;
349
+ }
350
+
351
+ if (!popup) {
352
+ win.location.href = url;
353
+ return undefined;
354
+ }
355
+
356
+ const session = defer<UserSession>();
357
+
358
+ win[`__ESRI_REST_AUTH_HANDLER_${clientId}`] = function(
359
+ errorString: any,
360
+ oauthInfoString: string
361
+ ) {
362
+ if (errorString) {
363
+ const error = JSON.parse(errorString);
364
+ session.reject(new ArcGISAuthError(error.errorMessage, error.error));
365
+ return;
366
+ }
367
+
368
+ if (oauthInfoString) {
369
+ const oauthInfo = JSON.parse(oauthInfoString);
370
+ session.resolve(
371
+ new UserSession({
372
+ clientId,
373
+ portal,
374
+ token: oauthInfo.token,
375
+ tokenExpires: new Date(oauthInfo.expires),
376
+ username: oauthInfo.username
377
+ })
378
+ );
379
+ }
380
+ };
381
+
382
+ win.open(
383
+ url,
384
+ "oauth-window",
385
+ "height=400,width=600,menubar=no,location=yes,resizable=yes,scrollbars=yes,status=yes"
386
+ );
387
+
388
+ return session.promise;
389
+ }
390
+
391
+ /**
392
+ * Completes a browser-based OAuth 2.0 sign if `options.popup` is true the user
393
+ * will be returned to the previous window. Otherwise a new `UserSession`
394
+ * will be returned.
395
+ *
396
+ * @browserOnly
397
+ */
398
+ /* istanbul ignore next */
399
+ static completeOAuth2(options: IOauth2Options, win: any = window) {
400
+ const { portal, clientId }: IOauth2Options = {
401
+ ...{ portal: "https://www.arcgis.com/sharing/rest" },
402
+ ...options
403
+ };
404
+
405
+ function completeSignIn(error: any, oauthInfo?: IFetchTokenResponse) {
406
+ if (win.opener && win.opener.parent) {
407
+ win.opener.parent[`__ESRI_REST_AUTH_HANDLER_${clientId}`](
408
+ error ? JSON.stringify(error) : undefined,
409
+ JSON.stringify(oauthInfo)
410
+ );
411
+ win.close();
412
+ return undefined;
413
+ }
414
+
415
+ if (win !== win.parent) {
416
+ win.parent[`__ESRI_REST_AUTH_HANDLER_${clientId}`](
417
+ error ? JSON.stringify(error) : undefined,
418
+ JSON.stringify(oauthInfo)
419
+ );
420
+ win.close();
421
+ return undefined;
422
+ }
423
+
424
+ if (error) {
425
+ throw new ArcGISAuthError(error.errorMessage, error.error);
426
+ }
427
+
428
+ return new UserSession({
429
+ clientId,
430
+ portal,
431
+ token: oauthInfo.token,
432
+ tokenExpires: oauthInfo.expires,
433
+ username: oauthInfo.username
434
+ });
435
+ }
436
+
437
+ const match = win.location.href.match(
438
+ /access_token=(.+)&expires_in=(.+)&username=([^&]+)/
439
+ );
440
+
441
+ if (!match) {
442
+ const errorMatch = win.location.href.match(
443
+ /error=(.+)&error_description=(.+)/
444
+ );
445
+
446
+ const error = errorMatch[1];
447
+ const errorMessage = decodeURIComponent(errorMatch[2]);
448
+
449
+ return completeSignIn({ error, errorMessage });
450
+ }
451
+
452
+ const token = match[1];
453
+ const expires = new Date(
454
+ Date.now() + parseInt(match[2], 10) * 1000 - 60 * 1000
455
+ );
456
+ const username = decodeURIComponent(match[3]);
457
+
458
+ return completeSignIn(undefined, {
459
+ token,
460
+ expires,
461
+ username
462
+ });
463
+ }
464
+
465
+ /**
466
+ * Begins a new server-based OAuth 2.0 sign in. This will redirect the user to
467
+ * the ArcGIS Online or ArcGIS Enterprise authorization page.
468
+ *
469
+ * @nodeOnly
470
+ */
471
+ static authorize(options: IOauth2Options, response: http.ServerResponse) {
472
+ const { portal, clientId, duration, redirectUri }: IOauth2Options = {
473
+ ...{ portal: "https://arcgis.com/sharing/rest", duration: 20160 },
474
+ ...options
475
+ };
476
+
477
+ response.writeHead(301, {
478
+ Location: `${portal}/oauth2/authorize?client_id=${clientId}&duration=${duration}&response_type=code&redirect_uri=${encodeURIComponent(
479
+ redirectUri
480
+ )}`
481
+ });
482
+
483
+ response.end();
484
+ }
485
+
486
+ /**
487
+ * Completes the server-based OAuth 2.0 sign in process by exchanging the `authorizationCode`
488
+ * for a `access_token`.
489
+ *
490
+ * @nodeOnly
491
+ */
492
+ static exchangeAuthorizationCode(
493
+ options: IOauth2Options,
494
+ authorizationCode: string
495
+ ): Promise<UserSession> {
496
+ const {
497
+ portal,
498
+ clientId,
499
+ duration,
500
+ redirectUri,
501
+ refreshTokenTTL
502
+ }: IOauth2Options = {
503
+ ...{
504
+ portal: "https://www.arcgis.com/sharing/rest",
505
+ duration: 20160,
506
+ refreshTokenTTL: 1440
507
+ },
508
+ ...options
509
+ };
510
+
511
+ return fetchToken(`${portal}/oauth2/token`, {
512
+ grant_type: "authorization_code",
513
+ client_id: clientId,
514
+ redirect_uri: redirectUri,
515
+ code: authorizationCode
516
+ }).then(response => {
517
+ return new UserSession({
518
+ clientId,
519
+ portal,
520
+ redirectUri,
521
+ refreshToken: response.refreshToken,
522
+ refreshTokenTTL,
523
+ refreshTokenExpires: new Date(
524
+ Date.now() + (refreshTokenTTL - 1) * 1000
525
+ ),
526
+ token: response.token,
527
+ tokenExpires: response.expires,
528
+ username: response.username
529
+ });
530
+ });
531
+ }
532
+
533
+ static deserialize(str: string) {
534
+ const options = JSON.parse(str);
535
+ return new UserSession({
536
+ clientId: options.clientId,
537
+ refreshToken: options.refreshToken,
538
+ refreshTokenExpires: new Date(options.refreshTokenExpires),
539
+ username: options.username,
540
+ password: options.password,
541
+ token: options.token,
542
+ tokenExpires: new Date(options.tokenExpires),
543
+ portal: options.portal,
544
+ tokenDuration: options.tokenDuration,
545
+ redirectUri: options.redirectUri,
546
+ refreshTokenTTL: options.refreshTokenTTL
547
+ });
548
+ }
549
+
550
+ /**
551
+ * Translates authentication from the format used in the [ArcGIS API for JavaScript](https://developers.arcgis.com/javascript/).
552
+ *
553
+ * ```js
554
+ * UserSession.fromCredential({
555
+ * userId: "jsmith",
556
+ * token: "secret"
557
+ * });
558
+ * ```
559
+ *
560
+ * @returns UserSession
561
+ */
562
+ static fromCredential(credential: ICredential) {
563
+ return new UserSession({
564
+ portal: credential.server + `/sharing/rest`,
565
+ token: credential.token,
566
+ username: credential.userId,
567
+ tokenExpires: new Date(credential.expires)
568
+ });
569
+ }
570
+
571
+ /**
572
+ * Returns authentication in a format useable in the [ArcGIS API for JavaScript](https://developers.arcgis.com/javascript/).
573
+ *
574
+ * ```js
575
+ * esriId.registerToken(session.toCredential());
576
+ * ```
577
+ *
578
+ * @returns ICredential
579
+ */
580
+ toCredential(): ICredential {
581
+ return {
582
+ expires: this.tokenExpires.getTime(),
583
+ server: this.portal,
584
+ ssl: true,
585
+ token: this.token,
586
+ userId: this.username
587
+ };
588
+ }
589
+
590
+ /**
591
+ * Returns information about the currently logged in [user](https://developers.arcgis.com/rest/users-groups-and-items/user.htm). Subsequent calls will *not* result in additional web traffic.
592
+ *
593
+ * ```js
594
+ * session.getUser()
595
+ * .then(response => {
596
+ * console.log(response.role); // "org_admin"
597
+ * })
598
+ * ```
599
+ *
600
+ * @returns A Promise that will resolve with the data from the response.
601
+ */
602
+ getUser(): Promise<IUser> {
603
+ if (this._user && this._user.username === this.username) {
604
+ return new Promise(resolve => resolve(this._user));
605
+ } else {
606
+ const url = `${this.portal}/community/users/${encodeURIComponent(
607
+ this.username
608
+ )}`;
609
+ return request(url, {
610
+ httpMethod: "GET",
611
+ authentication: this
612
+ }).then(response => {
613
+ this._user = response;
614
+ return response;
615
+ });
616
+ }
617
+ }
618
+
619
+ /**
620
+ * Gets an appropriate token for the given URL. If `portal` is ArcGIS Online and
621
+ * the request is to an ArcGIS Online domain `token` will be used. If the request
622
+ * is to the current `portal` the current `token` will also be used. However if
623
+ * the request is to an unknown server we will validate the server with a request
624
+ * to our current `portal`.
625
+ */
626
+ getToken(url: string) {
627
+ if (
628
+ /^https?:\/\/\S+\.arcgis\.com\/sharing\/rest/.test(this.portal) &&
629
+ /^https?:\/\/\S+\.arcgis\.com.+/.test(url)
630
+ ) {
631
+ return this.getFreshToken();
632
+ } else if (new RegExp(this.portal).test(url)) {
633
+ return this.getFreshToken();
634
+ } else {
635
+ return this.getTokenForServer(url);
636
+ }
637
+ }
638
+
639
+ toJSON(): IUserSessionOptions {
640
+ return {
641
+ clientId: this.clientId,
642
+ refreshToken: this.refreshToken,
643
+ refreshTokenExpires: this.refreshTokenExpires,
644
+ username: this.username,
645
+ password: this.password,
646
+ token: this.token,
647
+ tokenExpires: this.tokenExpires,
648
+ portal: this.portal,
649
+ tokenDuration: this.tokenDuration,
650
+ redirectUri: this.redirectUri,
651
+ refreshTokenTTL: this.refreshTokenTTL
652
+ };
653
+ }
654
+
655
+ serialize() {
656
+ return JSON.stringify(this);
657
+ }
658
+
659
+ /**
660
+ * Manually refreshes the current `token` and `tokenExpires`.
661
+ */
662
+ refreshSession(): Promise<UserSession> {
663
+ if (this.username && this.password) {
664
+ return this.refreshWithUsernameAndPassword();
665
+ }
666
+
667
+ if (this.clientId && this.refreshToken) {
668
+ return this.refreshWithRefreshToken();
669
+ }
670
+
671
+ return Promise.reject(new ArcGISAuthError("Unable to refresh token."));
672
+ }
673
+
674
+ /**
675
+ * Validates that a given URL is properly federated with our current `portal`.
676
+ * Attempts to use the internal `trustedServers` cache first.
677
+ */
678
+ private getTokenForServer(url: string) {
679
+ const [root] = url.split("/rest/services/");
680
+ const existingToken = this.trustedServers[root];
681
+
682
+ if (existingToken && existingToken.expires.getTime() > Date.now()) {
683
+ return Promise.resolve(existingToken.token);
684
+ }
685
+
686
+ if (this._pendingTokenRequests[root]) {
687
+ return this._pendingTokenRequests[root];
688
+ }
689
+
690
+ this._pendingTokenRequests[root] = request(`${root}/rest/info`)
691
+ .then((response: any) => {
692
+ return response.owningSystemUrl;
693
+ })
694
+ .then(owningSystemUrl => {
695
+ /**
696
+ * if this server is not owned by this portal or the stand-alone
697
+ * instance of ArcGIS Server doesn't advertise federation,
698
+ * bail out with an error since we know we wont
699
+ * be able to generate a token
700
+ */
701
+ if (
702
+ !owningSystemUrl ||
703
+ !new RegExp(owningSystemUrl).test(this.portal)
704
+ ) {
705
+ throw new ArcGISAuthError(
706
+ `${url} is not federated with ${this.portal}.`,
707
+ "NOT_FEDERATED"
708
+ );
709
+ }
710
+ return request(`${owningSystemUrl}/sharing/rest/info`);
711
+ })
712
+ .then((response: any) => {
713
+ return response.authInfo.tokenServicesUrl;
714
+ })
715
+ .then((tokenServicesUrl: string) => {
716
+ if (this.token) {
717
+ return generateToken(tokenServicesUrl, {
718
+ token: this.token,
719
+ serverUrl: url,
720
+ expiration: this.tokenDuration
721
+ });
722
+ // generate an entirely fresh token if necessary
723
+ } else {
724
+ return generateToken(tokenServicesUrl, {
725
+ username: this.username,
726
+ password: this.password,
727
+ expiration: this.tokenDuration
728
+ }).then((response: any) => {
729
+ this._token = response.token;
730
+ this._tokenExpires = new Date(response.expires);
731
+ return response;
732
+ });
733
+ }
734
+ })
735
+ .then(response => {
736
+ this.trustedServers[root] = {
737
+ expires: new Date(response.expires),
738
+ token: response.token
739
+ };
740
+ return response.token;
741
+ });
742
+
743
+ return this._pendingTokenRequests[root];
744
+ }
745
+
746
+ /**
747
+ * Returns an unexpired token for the current `portal`.
748
+ */
749
+ private getFreshToken() {
750
+ if (
751
+ this.token &&
752
+ this.tokenExpires &&
753
+ this.tokenExpires.getTime() > Date.now()
754
+ ) {
755
+ return Promise.resolve(this.token);
756
+ }
757
+
758
+ if (!this._pendingTokenRequests[this.portal]) {
759
+ this._pendingTokenRequests[this.portal] = this.refreshSession().then(
760
+ session => {
761
+ this._pendingTokenRequests[this.portal] = null;
762
+ return session.token;
763
+ }
764
+ );
765
+ }
766
+
767
+ return this._pendingTokenRequests[this.portal];
768
+ }
769
+
770
+ /**
771
+ * Refreshes the current `token` and `tokenExpires` with `username` and
772
+ * `password`.
773
+ */
774
+ private refreshWithUsernameAndPassword() {
775
+ return generateToken(`${this.portal}/generateToken`, {
776
+ username: this.username,
777
+ password: this.password,
778
+ expiration: this.tokenDuration
779
+ }).then((response: any) => {
780
+ this._token = response.token;
781
+ this._tokenExpires = new Date(response.expires);
782
+ return this;
783
+ });
784
+ }
785
+
786
+ /**
787
+ * Refreshes the current `token` and `tokenExpires` with `refreshToken`.
788
+ */
789
+ private refreshWithRefreshToken() {
790
+ if (
791
+ this.refreshToken &&
792
+ this.refreshTokenExpires &&
793
+ this.refreshTokenExpires.getTime() < Date.now()
794
+ ) {
795
+ return this.refreshRefreshToken();
796
+ }
797
+
798
+ return fetchToken(`${this.portal}/oauth2/token`, {
799
+ client_id: this.clientId,
800
+ refresh_token: this.refreshToken,
801
+ grant_type: "refresh_token"
802
+ }).then(response => {
803
+ this._token = response.token;
804
+ this._tokenExpires = response.expires;
805
+ return this;
806
+ });
807
+ }
808
+
809
+ /**
810
+ * Exchanges an expired `refreshToken` for a new one also updates `token` and
811
+ * `tokenExpires`.
812
+ */
813
+ private refreshRefreshToken() {
814
+ return fetchToken(`${this.portal}/oauth2/token`, {
815
+ client_id: this.clientId,
816
+ refresh_token: this.refreshToken,
817
+ redirect_uri: this.redirectUri,
818
+ grant_type: "exchange_refresh_token"
819
+ }).then(response => {
820
+ this._token = response.token;
821
+ this._tokenExpires = response.expires;
822
+ this._refreshToken = response.refreshToken;
823
+ this._refreshTokenExpires = new Date(
824
+ Date.now() + (this.refreshTokenTTL - 1) * 60 * 1000
825
+ );
826
+ return this;
827
+ });
828
+ }
829
+ }