Files
GitLite/src/lib/credentials.ts
T

58 lines
1.8 KiB
TypeScript

import type { StoredCredential } from "./types";
/**
* Derives a credential key from a remote URL, scoped to host + organisation —
* the same granularity Azure DevOps / GitHub use. Examples:
* https://github.com/owner/repo.git -> github.com/owner
* https://dev.azure.com/org/project/_git/repo -> dev.azure.com/org
* git@github.com:owner/repo.git -> github.com/owner
* ssh://git@host:2222/owner/repo -> host/owner
* Returns null when nothing usable can be parsed.
*/
export function orgKeyFromUrl(raw: string): string | null {
const url = raw.trim();
if (!url) return null;
let host = "";
let path = "";
// scp-like syntax: user@host:owner/repo.git (no scheme, single colon segment)
const scp = url.match(/^[^@/]+@([^:/]+):(.+)$/);
if (scp && !url.includes("://")) {
host = scp[1];
path = scp[2];
} else {
try {
const parsed = new URL(url);
host = parsed.host; // host:port, without userinfo
path = parsed.pathname;
} catch {
return null;
}
}
host = host.toLowerCase();
const org = path.replace(/^\/+/, "").split("/").filter(Boolean)[0] ?? "";
if (!host) return null;
return org ? `${host}/${org}` : host;
}
/** A stored credential is expired only if it carries a past expiry date. */
export function isCredentialExpired(cred: StoredCredential): boolean {
if (!cred.expiresAt) return false;
const time = new Date(cred.expiresAt).getTime();
return !Number.isNaN(time) && time < Date.now();
}
const AUTH_PREFIX = "AUTH_FAILED:";
export function isAuthError(message: string): boolean {
return message.startsWith(AUTH_PREFIX);
}
export function stripAuthPrefix(message: string): string {
return message.startsWith(AUTH_PREFIX)
? message.slice(AUTH_PREFIX.length).trim()
: message;
}