Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: secure proxy servers may not be hosted, so we should return false #1642

Merged
merged 9 commits into from
Sep 11, 2024
6 changes: 5 additions & 1 deletion packages/common/src/content/hostedServiceUtils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { IFeatureServiceDefinition } from "@esri/arcgis-rest-feature-layer";
import { IItem } from "@esri/arcgis-rest-portal";
import { IHubEditableContent } from "../core/types/IHubEditableContent";
import { isAGOHostedService } from "./isAGOHostedService";

/**
* DEPRECATED: This will be removed in the next breaking version. Use "isHostedFeatureServiceMainItem" instead.
abp6318 marked this conversation as resolved.
Show resolved Hide resolved
Expand Down Expand Up @@ -85,8 +86,11 @@ function isHostedFeatureServiceMain(
export function isAGOFeatureServiceUrl(url: string): boolean {
// TODO: we should really centralize this regex somewhere
const FEATURE_SERVICE_URL_REGEX = /(feature)server(\/|\/(\d+))?$/i;

// NOTE: if this is the URL of a proxied service it will fail the "is hosted" check
// even if the proxy points to a hosted service (which should be rare)
return (
!!url && url.includes("arcgis.com") && FEATURE_SERVICE_URL_REGEX.test(url)
!!url && isAGOHostedService(url) && FEATURE_SERVICE_URL_REGEX.test(url)
);
}

Expand Down
1 change: 1 addition & 0 deletions packages/common/src/content/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ export * from "./slugs";
export * from "./types";
export * from "./hostedServiceUtils";
export * from "./fetchItemJobRecords";
export * from "./isAGOHostedService";
35 changes: 35 additions & 0 deletions packages/common/src/content/isAGOHostedService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
function getHostname(url: string): string {
const urlObj = new URL(url);
return urlObj.hostname;
}

/**
* Used to determine if a service is hosted on ArcGIS Online
*
* Includes exlusion logic that prevents (secured) proxied services from returning true
* as we can't be sure if they are hosted or not
* @param url
* @returns true if the url is an ArcGIS Online hosted service
*/
/* istanbul ignore next - fn copied from another location that has tests */
export function isAGOHostedService(url: string): boolean {
let origin = getHostname(url); // -> www.esri.com

if (!origin) {
return false;
}

origin = origin.toLowerCase();

// This function will return _true_ if the url points to a hosted service in ArcGIS Online.
// It will return _false_ for proxy services (i.e., a proxy set up by AGO to access secure
// services that require credentials).
// NOTE: Even if a proxy is delegating to hosted feature service, this util will return false.
// We have no way of identifying what kind of service a proxy represents.
return (
origin.endsWith(".arcgis.com") &&
(origin.startsWith("services") ||
origin.startsWith("tiles") ||
origin.startsWith("features"))
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ describe("getDownloadFlow", () => {

it("should return the appropriate create replica download flow", () => {
const entity: IHubEditableContent = {
url: "https://www.arcgis.com/arcgis/rest/services/Hosted/FeatureServer/0",
url: "https://services.arcgis.com/arcgis/rest/services/Hosted/FeatureServer/0",
serverExtractCapability: true,
} as any;
const result = getDownloadFlow(entity);
Expand Down
Loading