Configure a default API base URL per git provider (github/gitlab/gitea) in settings.json gitProviders, with GitHub Enterprise support (Octokit baseUrl + device-flow web origin derived from the API base), and replace the client-side custom-domains list with server-persisted detection URL chips (SSH/HTTPS forms normalized to hosts). The configured API base host auto-counts as a detection host. Settings round-trip through the existing /api/config/settings sanitizer; the UI store hydrates from server settings with a one-time localStorage migration.
53 lines
1.7 KiB
JavaScript
53 lines
1.7 KiB
JavaScript
const DEVICE_GRANT_TYPE = 'urn:ietf:params:oauth:grant-type:device_code';
|
|
const DEFAULT_WEB_ORIGIN = 'https://github.com';
|
|
|
|
const encodeForm = (params) => {
|
|
const body = new URLSearchParams();
|
|
for (const [key, value] of Object.entries(params)) {
|
|
if (value == null) continue;
|
|
body.set(key, String(value));
|
|
}
|
|
return body.toString();
|
|
};
|
|
|
|
async function postForm(url, params) {
|
|
const response = await fetch(url, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
Accept: 'application/json',
|
|
},
|
|
body: encodeForm(params),
|
|
});
|
|
|
|
const payload = await response.json().catch(() => null);
|
|
if (!response.ok) {
|
|
const message = payload?.error_description || payload?.error || response.statusText;
|
|
const error = new Error(message || 'GitHub request failed');
|
|
error.status = response.status;
|
|
error.payload = payload;
|
|
throw error;
|
|
}
|
|
return payload;
|
|
}
|
|
|
|
const deviceCodeUrl = (webOrigin) => `${(webOrigin || DEFAULT_WEB_ORIGIN).replace(/\/+$/, '')}/login/device/code`;
|
|
const accessTokenUrl = (webOrigin) => `${(webOrigin || DEFAULT_WEB_ORIGIN).replace(/\/+$/, '')}/login/oauth/access_token`;
|
|
|
|
export async function startDeviceFlow({ clientId, scope, webOrigin }) {
|
|
return postForm(deviceCodeUrl(webOrigin), {
|
|
client_id: clientId,
|
|
scope,
|
|
});
|
|
}
|
|
|
|
export async function exchangeDeviceCode({ clientId, deviceCode, webOrigin }) {
|
|
// GitHub returns 200 with {error: 'authorization_pending'|...} for non-success states.
|
|
const payload = await postForm(accessTokenUrl(webOrigin), {
|
|
client_id: clientId,
|
|
device_code: deviceCode,
|
|
grant_type: DEVICE_GRANT_TYPE,
|
|
});
|
|
return payload;
|
|
}
|