All files / src/oauth instance-app.ts

100% Statements 26/26
100% Branches 12/12
100% Functions 4/4
100% Lines 25/25

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65                  226x 226x   226x     47x 47x 20x   47x             226x 47x 47x 47x   47x 51x 51x 51x 6x             45x 40x     47x             226x       28x 28x 2x   26x 29x    
/**
 * Instances a user can sign in to
 *
 * Only operator-configured instances are offered: the default GITLAB_API_URL application
 * and every registered instance with its own OAuth application. A URL supplied in a request
 * selects one of them or nothing, so credentials never go to a host the operator did not
 * configure.
 */
 
import { InstanceRegistry } from '../services/InstanceRegistry';
import { normalizeInstanceUrl } from '../utils/url';
import type { OAuthConfig } from './config';
import { defaultOAuthApp, type GitLabOAuthApp } from './oauth-app';
 
async function loadedRegistry(): Promise<InstanceRegistry> {
  const registry = InstanceRegistry.getInstance();
  if (!registry.isInitialized()) {
    await registry.initialize();
  }
  return registry;
}
 
/**
 * Applications a user may sign in with, default instance first. A registered instance's
 * own OAuth application takes precedence over OAUTH_CLIENT_ID for the same URL.
 */
export async function selectableOAuthApps(config: OAuthConfig): Promise<GitLabOAuthApp[]> {
  const registry = await loadedRegistry();
  const fallback = defaultOAuthApp(config);
  const apps = new Map<string, GitLabOAuthApp>([[fallback.baseUrl, fallback]]);
 
  for (const url of registry.getUrls()) {
    const instance = registry.getConfig(url);
    const baseUrl = normalizeInstanceUrl(url);
    if (instance?.oauth) {
      apps.set(baseUrl, {
        baseUrl,
        label: instance.label,
        clientId: instance.oauth.clientId,
        clientSecret: instance.oauth.clientSecret,
        scopes: instance.oauth.scopes ?? config.gitlabScopes,
      });
    } else if (baseUrl === fallback.baseUrl && instance?.label) {
      apps.set(baseUrl, { ...fallback, label: instance.label });
    }
  }
  return [...apps.values()];
}
 
/**
 * Application for a chosen instance: the default when none was chosen, undefined when the
 * URL is not one of the selectable instances.
 */
export async function oauthAppFor(
  config: OAuthConfig,
  instanceUrl: string | undefined,
): Promise<GitLabOAuthApp | undefined> {
  const apps = await selectableOAuthApps(config);
  if (instanceUrl === undefined) {
    return apps[0];
  }
  const wanted = normalizeInstanceUrl(instanceUrl);
  return apps.find((app) => app.baseUrl === wanted);
}