etincidunt 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ }