Skip to content

Commit

Permalink
refactor(:lock:): allow passing a custom fetch to internal auth methods
Browse files Browse the repository at this point in the history
AFFECTS PACKAGES:
@esri/arcgis-rest-auth
@esri/arcgis-rest-request
batch-geocoder
  • Loading branch information
jgravois committed Aug 7, 2018
1 parent 90f9e75 commit a50da42
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 54 deletions.
8 changes: 7 additions & 1 deletion demos/batch-geocoder-node/batch-geocode.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
require('isomorphic-fetch');
// const customFetch = require('node-fetch');

require('isomorphic-form-data');
const fs = require('fs');
const Papa = require('papaparse');
Expand Down Expand Up @@ -90,7 +92,11 @@ parseCsv(config.csv)

// Geocode
const promises = chunks.map(chunk =>
bulkGeocode({addresses: chunk, authentication: session})
bulkGeocode({
addresses: chunk,
authentication: session //,
// fetch: customFetch
})
);

// Resolve results and combine with CSV data
Expand Down
40 changes: 29 additions & 11 deletions demos/batch-geocoder-node/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions demos/batch-geocoder-node/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,8 @@
"isomorphic-fetch": "^2.2.1",
"isomorphic-form-data": "^1.0.0",
"papaparse": "^4.3.6"
},
"devDependencies": {
"node-fetch": "^2.2.0"
}
}
77 changes: 44 additions & 33 deletions packages/arcgis-rest-auth/src/UserSession.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
/* Copyright (c) 2017 Environmental Systems Research Institute, Inc.
/* Copyright (c) 2017-2018 Environmental Systems Research Institute, Inc.
* Apache-2.0 */

import * as http from "http";
import {
request,
ArcGISAuthError,
IAuthenticationManager
IAuthenticationManager,
IRequestOptions
} from "@esri/arcgis-rest-request";
import { generateToken } from "./generate-token";
import { fetchToken, IFetchTokenResponse } from "./fetch-token";
Expand Down Expand Up @@ -623,16 +624,16 @@ export class UserSession implements IAuthenticationManager {
* the request is to an unknown server we will validate the server with a request
* to our current `portal`.
*/
getToken(url: string) {
getToken(url: string, requestOptions?: IRequestOptions) {
if (
/^https?:\/\/\S+\.arcgis\.com\/sharing\/rest/.test(this.portal) &&
/^https?:\/\/\S+\.arcgis\.com.+/.test(url)
) {
return this.getFreshToken();
return this.getFreshToken(requestOptions);
} else if (new RegExp(this.portal).test(url)) {
return this.getFreshToken();
return this.getFreshToken(requestOptions);
} else {
return this.getTokenForServer(url);
return this.getTokenForServer(url, requestOptions);
}
}

Expand All @@ -659,9 +660,9 @@ export class UserSession implements IAuthenticationManager {
/**
* Manually refreshes the current `token` and `tokenExpires`.
*/
refreshSession(): Promise<UserSession> {
refreshSession(requestOptions?: IRequestOptions): Promise<UserSession> {
if (this.username && this.password) {
return this.refreshWithUsernameAndPassword();
return this.refreshWithUsernameAndPassword(requestOptions);
}

if (this.clientId && this.refreshToken) {
Expand All @@ -675,7 +676,7 @@ export class UserSession implements IAuthenticationManager {
* Validates that a given URL is properly federated with our current `portal`.
* Attempts to use the internal `trustedServers` cache first.
*/
private getTokenForServer(url: string) {
private getTokenForServer(url: string, requestOptions: IRequestOptions) {
const [root] = url.split("/rest/services/");
const existingToken = this.trustedServers[root];

Expand Down Expand Up @@ -707,24 +708,28 @@ export class UserSession implements IAuthenticationManager {
"NOT_FEDERATED"
);
}
return request(`${owningSystemUrl}/sharing/rest/info`);
return request(`${owningSystemUrl}/sharing/rest/info`, requestOptions);
})
.then((response: any) => {
return response.authInfo.tokenServicesUrl;
})
.then((tokenServicesUrl: string) => {
if (this.token) {
return generateToken(tokenServicesUrl, {
token: this.token,
serverUrl: url,
expiration: this.tokenDuration
params: {
token: this.token,
serverUrl: url,
expiration: this.tokenDuration
}
});
// generate an entirely fresh token if necessary
} else {
return generateToken(tokenServicesUrl, {
username: this.username,
password: this.password,
expiration: this.tokenDuration
params: {
username: this.username,
password: this.password,
expiration: this.tokenDuration
}
}).then((response: any) => {
this._token = response.token;
this._tokenExpires = new Date(response.expires);
Expand All @@ -746,7 +751,7 @@ export class UserSession implements IAuthenticationManager {
/**
* Returns an unexpired token for the current `portal`.
*/
private getFreshToken() {
private getFreshToken(requestOptions?: IRequestOptions) {
if (
this.token &&
this.tokenExpires &&
Expand All @@ -756,12 +761,12 @@ export class UserSession implements IAuthenticationManager {
}

if (!this._pendingTokenRequests[this.portal]) {
this._pendingTokenRequests[this.portal] = this.refreshSession().then(
session => {
this._pendingTokenRequests[this.portal] = null;
return session.token;
}
);
this._pendingTokenRequests[this.portal] = this.refreshSession(
requestOptions
).then(session => {
this._pendingTokenRequests[this.portal] = null;
return session.token;
});
}

return this._pendingTokenRequests[this.portal];
Expand All @@ -771,16 +776,22 @@ export class UserSession implements IAuthenticationManager {
* Refreshes the current `token` and `tokenExpires` with `username` and
* `password`.
*/
private refreshWithUsernameAndPassword() {
return generateToken(`${this.portal}/generateToken`, {
username: this.username,
password: this.password,
expiration: this.tokenDuration
}).then((response: any) => {
this._token = response.token;
this._tokenExpires = new Date(response.expires);
return this;
});
private refreshWithUsernameAndPassword(requestOptions?: IRequestOptions) {
const options = {
params: {
username: this.username,
password: this.password,
expiration: this.tokenDuration
},
...requestOptions
};
return generateToken(`${this.portal}/generateToken`, options).then(
(response: any) => {
this._token = response.token;
this._tokenExpires = new Date(response.expires);
return this;
}
);
}

/**
Expand Down
16 changes: 10 additions & 6 deletions packages/arcgis-rest-auth/src/generate-token.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* Copyright (c) 2017 Environmental Systems Research Institute, Inc.
/* Copyright (c) 2017-2018 Environmental Systems Research Institute, Inc.
* Apache-2.0 */

import { request, IParams } from "@esri/arcgis-rest-request";
import { request, IParams, IRequestOptions } from "@esri/arcgis-rest-request";

export interface IGenerateTokenParams extends IParams {
username?: string;
Expand All @@ -11,6 +11,10 @@ export interface IGenerateTokenParams extends IParams {
serverUrl?: string;
}

export interface IGenerateTokenRequestOptions extends IRequestOptions {
params: IGenerateTokenParams;
}

export interface IGenerateTokenResponse {
token: string;
expires: number;
Expand All @@ -19,18 +23,18 @@ export interface IGenerateTokenResponse {

export function generateToken(
url: string,
params: IGenerateTokenParams
requestOptions: IGenerateTokenRequestOptions
): Promise<IGenerateTokenResponse> {
/* istanbul ignore else */
if (
typeof window !== "undefined" &&
window.location &&
window.location.host
) {
params.referer = window.location.host;
requestOptions.params.referer = window.location.host;
} else {
params.referer = "@esri.arcgis-rest-auth";
requestOptions.params.referer = "@esri.arcgis-rest-auth";
}

return request(url, { params });
return request(url, requestOptions);
}
11 changes: 8 additions & 3 deletions packages/arcgis-rest-request/src/request.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Copyright (c) 2017 Environmental Systems Research Institute, Inc.
/* Copyright (c) 2017-2018 Environmental Systems Research Institute, Inc.
* Apache-2.0 */

import { checkForErrors } from "./utils/check-for-errors";
Expand All @@ -25,7 +25,7 @@ export interface IAuthenticationManager {
* Defaults to 'https://www.arcgis.com/sharing/rest'.
*/
portal: string;
getToken(url: string): Promise<string>;
getToken(url: string, requestOptions?: IRequestOptions): Promise<string>;
}

/**
Expand Down Expand Up @@ -173,7 +173,12 @@ export function request(
credentials: "same-origin"
};

return (authentication ? authentication.getToken(url) : Promise.resolve(""))
return (authentication
? authentication.getToken(url, {
fetch: options.fetch
})
: Promise.resolve("")
)
.then(token => {
if (token.length) {
params.token = token;
Expand Down

0 comments on commit a50da42

Please sign in to comment.