"Fossies" - the Fresh Open Source Software Archive 
Member "cli-1.1260.0/src/lib/config/api-url.ts" (4 Dec 2023, 6187 Bytes) of package /linux/misc/snyk-cli-1.1260.0.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) TypeScript source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 /*
2 This file is trying to make sense from different Snyk API URLs configurations
3
4 API URL settings could be defined in a few ways:
5 - snyk config file with key "endpoint" (including override with SNYK_CFG_ENDPOINT envvar!)
6 - SNYK_API envvar
7 - Snyk REST API had their own envvars to be set
8
9 And API URL itself could (currently) point to multiple places
10 - https://snyk.io/api/v1 (old default)
11 - https://snyk.io/api
12 - https://app.snyk.io/api
13 - https://app.snyk.io/api/v1
14 - https://api.snyk.io/v1
15
16 For Snyk REST API it's a bit simpler:
17 - https://api.snyk.io/rest
18
19
20 There are also other URLs - one for the snyk auth command, one for Snyk Code Proxy
21
22 Idea is to configure a single URL and derive the rest from it.
23 This file handles an internal concept of a Base URL and logic needed to derive the other URLs
24 In a backwards compatible way.
25 */
26
27 import * as path from 'path';
28 import * as Debug from 'debug';
29 import { color } from '../theme';
30
31 const debug = Debug('snyk');
32
33 /**
34 * @description Get a Base URL for Snyk APIs
35 * @export
36 * @param {string} defaultUrl URL to default to, should be the one defined in the config.default.json file
37 * @param {(string | undefined)} envvarDefinedApiUrl if there is an URL defined in the SNYK_API envvar
38 * @param {(string | undefined)} configDefinedApiUrl if there is an URL defined in the 'endpoint' key of the config
39 * @returns {string} Returns a Base URL - without the /v1. Use this to construct derived URLs
40 */
41 export function getBaseApiUrl(
42 defaultUrl: string,
43 envvarDefinedApiUrl?: string,
44 configDefinedApiUrl?: string,
45 ): string {
46 const defaultBaseApiUrl = stripV1FromApiUrl(defaultUrl);
47 // Use SNYK_API envvar by default
48 if (envvarDefinedApiUrl) {
49 return validateUrlOrReturnDefault(
50 envvarDefinedApiUrl,
51 "'SNYK_API' environment variable",
52 defaultBaseApiUrl,
53 );
54 }
55
56 if (configDefinedApiUrl) {
57 return validateUrlOrReturnDefault(
58 configDefinedApiUrl,
59 "'endpoint' config option. See 'snyk config' command. The value of 'endpoint' is currently set as",
60 defaultBaseApiUrl,
61 );
62 }
63
64 return defaultBaseApiUrl; // Fallback to default
65 }
66
67 /**
68 * @description Macro to validate user-defined URL and fallback to default if needed
69 * @param {string} urlString "dirty" user defined string coming from config, envvar or a flag
70 * @param {string} optionName For formatting error messages
71 * @param {string} defaultUrl What to return if urlString does not pass
72 * @returns {string}
73 */
74 function validateUrlOrReturnDefault(
75 urlString: string,
76 optionName: string,
77 defaultUrl: string,
78 ): string {
79 const parsedEndpoint = parseURLWithoutThrowing(urlString);
80 // Endpoint option must be a valid URL including protocol
81 if (!parsedEndpoint || !parsedEndpoint.protocol || !parsedEndpoint.host) {
82 console.error(
83 color.status.error(
84 `Invalid ${optionName} '${urlString}'. Value must be a valid URL including protocol. Using default Snyk API URL '${defaultUrl}'`,
85 ),
86 );
87 return defaultUrl;
88 }
89 // TODO: this debug is not printed when using the --debug flag, because flags are parsed after config. Making it async works around this
90 setTimeout(
91 () => debug(`Using a custom Snyk API ${optionName} '${urlString}'`),
92 1,
93 );
94 return stripV1FromApiUrl(urlString);
95 }
96
97 function parseURLWithoutThrowing(urlString: string): URL | undefined {
98 try {
99 return new URL(urlString);
100 } catch (error) {
101 return undefined;
102 }
103 }
104
105 /**
106 * @description Removes /v1 suffix from URL if present
107 * @param {string} url
108 * @returns {string}
109 */
110 function stripV1FromApiUrl(url: string): string {
111 const parsedUrl = new URL(url);
112 if (/\/v1\/?$/.test(parsedUrl.pathname)) {
113 parsedUrl.pathname = parsedUrl.pathname.replace(/\/v1\/?$/, '/');
114 return parsedUrl.toString();
115 }
116 return url;
117 }
118
119 export function getV1ApiUrl(baseApiUrl: string): string {
120 const parsedBaseUrl = new URL(baseApiUrl);
121 parsedBaseUrl.pathname = path.join(parsedBaseUrl.pathname, 'v1');
122 return parsedBaseUrl.toString();
123 }
124
125 /**
126 * @description Return Snyk REST API URL
127 * @export
128 * @param {string} baseApiUrl
129 * @param {string} envvarDefinedRestApiUrl
130 * @param {string} envvarDefinedRestV3Url
131 * @returns {string}
132 */
133 export function getRestApiUrl(
134 baseApiUrl: string,
135 envvarDefinedRestApiUrl?: string,
136 envvarDefinedRestV3Url?: string,
137 ): string {
138 // REST API URL should always look like this: https://api.$DOMAIN/rest
139 const parsedBaseUrl = new URL(baseApiUrl);
140 parsedBaseUrl.pathname = '/rest';
141
142 if (parsedBaseUrl.host?.startsWith('app.')) {
143 // Rewrite app.snyk.io/ to api.snyk.io/rest
144 parsedBaseUrl.host = parsedBaseUrl.host.replace(/^app\./, 'api.');
145 } else if (
146 // Ignore localhosts and URLs with api. already defined
147 !parsedBaseUrl.host?.startsWith('localhost') &&
148 !parsedBaseUrl.host?.startsWith('api.')
149 ) {
150 // Otherwise add the api. subdomain
151 parsedBaseUrl.host = 'api.' + parsedBaseUrl.host;
152 }
153
154 const defaultRestApiUrl = parsedBaseUrl.toString();
155
156 // TODO: notify users they can set just the (SNYK_)API envvar
157 if (envvarDefinedRestV3Url) {
158 return validateUrlOrReturnDefault(
159 envvarDefinedRestV3Url,
160 "'SNYK_API_V3_URL' environment variable",
161 defaultRestApiUrl,
162 );
163 }
164
165 if (envvarDefinedRestApiUrl) {
166 return validateUrlOrReturnDefault(
167 envvarDefinedRestApiUrl,
168 "'SNYK_API_REST_URL' environment variable",
169 defaultRestApiUrl,
170 );
171 }
172
173 return defaultRestApiUrl; // Fallback to default
174 }
175
176 export function getHiddenApiUrl(restUrl: string): string {
177 const parsedBaseUrl = new URL(restUrl);
178
179 parsedBaseUrl.pathname = '/hidden';
180
181 return parsedBaseUrl.toString();
182 }
183
184 export function getRootUrl(apiUrlString: string): string {
185 // based on https://docs.snyk.io/snyk-processes/data-residency-at-snyk#what-regions-are-available the pattern is as follows
186 // https://app.[region.]snyk.io
187 // given an api url that starts with api means, that we can replace "api" by "app".
188
189 const apiUrl = new URL(apiUrlString);
190 apiUrl.host = apiUrl.host.replace(/^api\./, '');
191
192 const rootUrl = apiUrl.protocol + '//' + apiUrl.host;
193 return rootUrl;
194 }