feat: Support custom auth schemes for Github API (#1086)
This commit is contained in:
parent
dcdc49232d
commit
17b32f0902
@ -33,7 +33,7 @@ import {
|
|||||||
} from '@staticcms/core/lib/util/APIUtils';
|
} from '@staticcms/core/lib/util/APIUtils';
|
||||||
import { GitHubCommitStatusState, PullRequestState } from './types';
|
import { GitHubCommitStatusState, PullRequestState } from './types';
|
||||||
|
|
||||||
import type { DataFile, PersistOptions, UnpublishedEntry } from '@staticcms/core';
|
import type { AuthScheme, DataFile, PersistOptions, UnpublishedEntry } from '@staticcms/core';
|
||||||
import type { ApiRequest, FetchError } from '@staticcms/core/lib/util';
|
import type { ApiRequest, FetchError } from '@staticcms/core/lib/util';
|
||||||
import type AssetProxy from '@staticcms/core/valueObjects/AssetProxy';
|
import type AssetProxy from '@staticcms/core/valueObjects/AssetProxy';
|
||||||
import type { Semaphore } from 'semaphore';
|
import type { Semaphore } from 'semaphore';
|
||||||
@ -75,6 +75,7 @@ export const MOCK_PULL_REQUEST = -1;
|
|||||||
export interface Config {
|
export interface Config {
|
||||||
apiRoot?: string;
|
apiRoot?: string;
|
||||||
token?: string;
|
token?: string;
|
||||||
|
authScheme?: AuthScheme;
|
||||||
branch?: string;
|
branch?: string;
|
||||||
useOpenAuthoring?: boolean;
|
useOpenAuthoring?: boolean;
|
||||||
openAuthoringEnabled?: boolean;
|
openAuthoringEnabled?: boolean;
|
||||||
@ -162,6 +163,7 @@ export type Diff = {
|
|||||||
export default class API {
|
export default class API {
|
||||||
apiRoot: string;
|
apiRoot: string;
|
||||||
token: string;
|
token: string;
|
||||||
|
authScheme: AuthScheme;
|
||||||
branch: string;
|
branch: string;
|
||||||
useOpenAuthoring?: boolean;
|
useOpenAuthoring?: boolean;
|
||||||
openAuthoringEnabled?: boolean;
|
openAuthoringEnabled?: boolean;
|
||||||
@ -185,6 +187,7 @@ export default class API {
|
|||||||
constructor(config: Config) {
|
constructor(config: Config) {
|
||||||
this.apiRoot = config.apiRoot || 'https://api.github.com';
|
this.apiRoot = config.apiRoot || 'https://api.github.com';
|
||||||
this.token = config.token || '';
|
this.token = config.token || '';
|
||||||
|
this.authScheme = config.authScheme || 'token';
|
||||||
this.branch = config.branch || 'main';
|
this.branch = config.branch || 'main';
|
||||||
this.useOpenAuthoring = config.useOpenAuthoring;
|
this.useOpenAuthoring = config.useOpenAuthoring;
|
||||||
this.repo = config.repo || '';
|
this.repo = config.repo || '';
|
||||||
@ -242,7 +245,7 @@ export default class API {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (this.token) {
|
if (this.token) {
|
||||||
baseHeader.Authorization = `token ${this.token}`;
|
baseHeader.Authorization = `${this.authScheme} ${this.token}`;
|
||||||
return Promise.resolve(baseHeader);
|
return Promise.resolve(baseHeader);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,6 +103,35 @@ describe('github API', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should fetch url with authorization header using custom auth scheme', async () => {
|
||||||
|
const api = new API({
|
||||||
|
branch: 'gh-pages',
|
||||||
|
repo: 'my-repo',
|
||||||
|
token: 'token',
|
||||||
|
authScheme: 'Bearer',
|
||||||
|
squashMerges: false,
|
||||||
|
initialWorkflowStatus: WorkflowStatus.DRAFT,
|
||||||
|
cmsLabelPrefix: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
fetch.mockResolvedValue({
|
||||||
|
text: jest.fn().mockResolvedValue('some response'),
|
||||||
|
ok: true,
|
||||||
|
status: 200,
|
||||||
|
headers: { get: () => '' },
|
||||||
|
});
|
||||||
|
const result = await api.request('/some-path');
|
||||||
|
expect(result).toEqual('some response');
|
||||||
|
expect(fetch).toHaveBeenCalledTimes(1);
|
||||||
|
expect(fetch).toHaveBeenCalledWith('https://api.github.com/some-path', {
|
||||||
|
cache: 'no-cache',
|
||||||
|
headers: {
|
||||||
|
Authorization: 'Bearer token',
|
||||||
|
'Content-Type': 'application/json; charset=utf-8',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should throw error on not ok response', async () => {
|
it('should throw error on not ok response', async () => {
|
||||||
const api = new API({
|
const api = new API({
|
||||||
branch: 'gh-pages',
|
branch: 'gh-pages',
|
||||||
|
@ -25,6 +25,7 @@ import API, { API_NAME } from './API';
|
|||||||
import AuthenticationPage from './AuthenticationPage';
|
import AuthenticationPage from './AuthenticationPage';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
|
AuthScheme,
|
||||||
BackendClass,
|
BackendClass,
|
||||||
BackendEntry,
|
BackendEntry,
|
||||||
ConfigWithDefaults,
|
ConfigWithDefaults,
|
||||||
@ -75,6 +76,7 @@ export default class GitHub implements BackendClass {
|
|||||||
mediaFolder?: string;
|
mediaFolder?: string;
|
||||||
previewContext: string;
|
previewContext: string;
|
||||||
token: string | null;
|
token: string | null;
|
||||||
|
authScheme: AuthScheme;
|
||||||
squashMerges: boolean;
|
squashMerges: boolean;
|
||||||
cmsLabelPrefix: string;
|
cmsLabelPrefix: string;
|
||||||
_currentUserPromise?: Promise<GitHubUser>;
|
_currentUserPromise?: Promise<GitHubUser>;
|
||||||
@ -114,6 +116,7 @@ export default class GitHub implements BackendClass {
|
|||||||
this.branch = config.backend.branch?.trim() || 'main';
|
this.branch = config.backend.branch?.trim() || 'main';
|
||||||
this.apiRoot = config.backend.api_root || 'https://api.github.com';
|
this.apiRoot = config.backend.api_root || 'https://api.github.com';
|
||||||
this.token = '';
|
this.token = '';
|
||||||
|
this.authScheme = config.backend.auth_scheme || 'token';
|
||||||
this.squashMerges = config.backend.squash_merges || false;
|
this.squashMerges = config.backend.squash_merges || false;
|
||||||
this.cmsLabelPrefix = config.backend.cms_label_prefix || '';
|
this.cmsLabelPrefix = config.backend.cms_label_prefix || '';
|
||||||
this.mediaFolder = config.media_folder;
|
this.mediaFolder = config.media_folder;
|
||||||
@ -171,7 +174,7 @@ export default class GitHub implements BackendClass {
|
|||||||
let repoExists = false;
|
let repoExists = false;
|
||||||
while (!repoExists) {
|
while (!repoExists) {
|
||||||
repoExists = await fetch(`${this.apiRoot}/repos/${repo}`, {
|
repoExists = await fetch(`${this.apiRoot}/repos/${repo}`, {
|
||||||
headers: { Authorization: `token ${token}` },
|
headers: { Authorization: `${this.authScheme} ${token}` },
|
||||||
})
|
})
|
||||||
.then(() => true)
|
.then(() => true)
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
@ -194,7 +197,7 @@ export default class GitHub implements BackendClass {
|
|||||||
if (!this._currentUserPromise) {
|
if (!this._currentUserPromise) {
|
||||||
this._currentUserPromise = fetch(`${this.apiRoot}/user`, {
|
this._currentUserPromise = fetch(`${this.apiRoot}/user`, {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `token ${token}`,
|
Authorization: `${this.authScheme} ${token}`,
|
||||||
},
|
},
|
||||||
}).then(res => res.json());
|
}).then(res => res.json());
|
||||||
}
|
}
|
||||||
@ -215,7 +218,7 @@ export default class GitHub implements BackendClass {
|
|||||||
`${this.apiRoot}/repos/${this.originRepo}/collaborators/${username}/permission`,
|
`${this.apiRoot}/repos/${this.originRepo}/collaborators/${username}/permission`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `token ${token}`,
|
Authorization: `${this.authScheme} ${token}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@ -232,7 +235,7 @@ export default class GitHub implements BackendClass {
|
|||||||
const repo = await fetch(`${this.apiRoot}/repos/${currentUser.login}/${repoName}`, {
|
const repo = await fetch(`${this.apiRoot}/repos/${currentUser.login}/${repoName}`, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `token ${token}`,
|
Authorization: `${this.authScheme} ${token}`,
|
||||||
},
|
},
|
||||||
}).then(res => res.json());
|
}).then(res => res.json());
|
||||||
|
|
||||||
@ -276,7 +279,7 @@ export default class GitHub implements BackendClass {
|
|||||||
const fork = await fetch(`${this.apiRoot}/repos/${this.originRepo}/forks`, {
|
const fork = await fetch(`${this.apiRoot}/repos/${this.originRepo}/forks`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `token ${token}`,
|
Authorization: `${this.authScheme} ${token}`,
|
||||||
},
|
},
|
||||||
}).then(res => res.json());
|
}).then(res => res.json());
|
||||||
this.useOpenAuthoring = true;
|
this.useOpenAuthoring = true;
|
||||||
@ -289,6 +292,7 @@ export default class GitHub implements BackendClass {
|
|||||||
const apiCtor = API;
|
const apiCtor = API;
|
||||||
this.api = new apiCtor({
|
this.api = new apiCtor({
|
||||||
token: this.token,
|
token: this.token,
|
||||||
|
authScheme: this.authScheme,
|
||||||
branch: this.branch,
|
branch: this.branch,
|
||||||
repo: this.repo,
|
repo: this.repo,
|
||||||
originRepo: this.originRepo,
|
originRepo: this.originRepo,
|
||||||
|
@ -698,6 +698,8 @@ export interface SelectWidgetOptionObject {
|
|||||||
|
|
||||||
export type AuthScope = 'repo' | 'public_repo';
|
export type AuthScope = 'repo' | 'public_repo';
|
||||||
|
|
||||||
|
export type AuthScheme = 'token' | 'Bearer';
|
||||||
|
|
||||||
export type SlugEncoding = 'unicode' | 'ascii';
|
export type SlugEncoding = 'unicode' | 'ascii';
|
||||||
|
|
||||||
export type RenderedField<F extends BaseField = UnknownField> = F & {
|
export type RenderedField<F extends BaseField = UnknownField> = F & {
|
||||||
@ -1025,6 +1027,7 @@ export interface Backend {
|
|||||||
identity_url?: string;
|
identity_url?: string;
|
||||||
gateway_url?: string;
|
gateway_url?: string;
|
||||||
auth_scope?: AuthScope;
|
auth_scope?: AuthScope;
|
||||||
|
auth_scheme?: AuthScheme;
|
||||||
commit_messages?: {
|
commit_messages?: {
|
||||||
create?: string;
|
create?: string;
|
||||||
update?: string;
|
update?: string;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user