Skip to content

Commit

Permalink
feat: access for private repo
Browse files Browse the repository at this point in the history
  • Loading branch information
HananoshikaYomaru committed Jan 10, 2024
1 parent 4d5ad78 commit d86a6af
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 14 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
# npm
node_modules
package-lock.json
bun.lockb

# build
build
*.js.map

# other
**/.DS_Store
**/.DS_Store
27 changes: 22 additions & 5 deletions src/features/BetaPlugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,16 +66,24 @@ export default class BetaPlugins {
const manifestJson = await grabManifestJsonFromRepository(
repositoryPath,
!getBetaManifest,
this.plugin.settings.debuggingMode
this.plugin.settings.debuggingMode,
this.plugin.settings.personalAccessToken
);
if (!manifestJson) {
// this is a plugin with a manifest json, try to see if there is a beta version
if (reportIssues)
if (reportIssues) {
toastMessage(
this.plugin,
`${repositoryPath}\nThis does not seem to be an obsidian plugin, as there is no manifest.json file.`,
noticeTimeout
);
console.error(
'BRAT: validateRepository',
repositoryPath,
getBetaManifest,
reportIssues
);
}
return null;
}
// Test that the mainfest has some key elements, like ID and version
Expand Down Expand Up @@ -123,27 +131,32 @@ export default class BetaPlugins {
// if we have version specified, we always want to get the remote manifest file.
const reallyGetManifestOrNot = getManifest || specifyVersion !== '';

console.log({ reallyGetManifestOrNot, version });

return {
mainJs: await grabReleaseFileFromRepository(
repositoryPath,
version,
'main.js',
this.plugin.settings.debuggingMode
this.plugin.settings.debuggingMode,
this.plugin.settings.personalAccessToken
),
manifest:
reallyGetManifestOrNot ?
await grabReleaseFileFromRepository(
repositoryPath,
version,
'manifest.json',
this.plugin.settings.debuggingMode
this.plugin.settings.debuggingMode,
this.plugin.settings.personalAccessToken
)
: '',
styles: await grabReleaseFileFromRepository(
repositoryPath,
version,
'styles.css',
this.plugin.settings.debuggingMode
this.plugin.settings.debuggingMode,
this.plugin.settings.personalAccessToken
),
};
}
Expand Down Expand Up @@ -253,6 +266,8 @@ export default class BetaPlugins {
}
}

// now the user must be able to access the repo

interface ErrnoType {
errno: number;
}
Expand All @@ -265,6 +280,8 @@ export default class BetaPlugins {
usingBetaManifest,
specifyVersion
);

console.log('rFiles', rFiles);
// if beta, use that manifest, or if there is no manifest in release, use the primaryManifest
if (usingBetaManifest || rFiles.manifest === '')
rFiles.manifest = JSON.stringify(primaryManifest);
Expand Down
108 changes: 100 additions & 8 deletions src/features/githubUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,30 @@ import { request } from 'obsidian';

const GITHUB_RAW_USERCONTENT_PATH = 'https://raw.githubusercontent.com/';

const isPrivateRepo = async (
repository: string,
debugLogging = true,
personalAccessToken = ''
): Promise<boolean> => {
const URL = `https://api.github.com/repos/${repository}`;
try {
const response = await request({
url: URL,
headers:
personalAccessToken ?
{
Authorization: `Token ${personalAccessToken}`,
}
: {},
});
const data = await JSON.parse(response);
return data.private;
} catch (e) {
if (debugLogging) console.log('error in isPrivateRepo', URL, e);
return false;
}
};

/**
* pulls from github a release file by its version number
*
Expand All @@ -16,14 +40,73 @@ export const grabReleaseFileFromRepository = async (
repository: string,
version: string,
fileName: string,
debugLogging = true
debugLogging = true,
personalAccessToken = ''
): Promise<string | null> => {
const URL = `https://github.com/${repository}/releases/download/${version}/${fileName}`;
try {
const download = await request({ url: URL });
return download === 'Not Found' || download === `{"error":"Not Found"}` ?
null
: download;
// check if the repo is a private repo
const isPrivate = await isPrivateRepo(repository, debugLogging, personalAccessToken);

if (isPrivate) {
type Release = {
url: string;
tag_name: string;
assets: {
name: string;
url: string;
}[];
};

// get the asset id
// fetch https://api.github.com/repos/{repos}/releases , parse the response
// this will return an array of releases, find the release with the version number by tag_name
// in the release object, get assets and find the correct asset by name
// then fetch the url

const URL = `https://api.github.com/repos/${repository}/releases`;
const response = await request({
url: URL,
headers: {
Authorization: `Token ${personalAccessToken}`,
},
});
const data = await JSON.parse(response);
const release = data.find((release: Release) => release.tag_name === version);
if (!release) {
return null;
}
const asset = release.assets.find(
(asset: { name: string }) => asset.name === fileName
);
if (!asset) {
return null;
}
const download = await request({
url: asset.url,
headers: {
Authorization: `Token ${personalAccessToken}`,
Accept: 'application/octet-stream',
},
});
return download === 'Not Found' || download === `{"error":"Not Found"}` ?
null
: download;
} else {
const URL = `https://github.com/${repository}/releases/download/${version}/${fileName}`;
const download = await request({
url: URL,
headers:
personalAccessToken ?
{
Authorization: `Token ${personalAccessToken}`,
}
: {},
});

return download === 'Not Found' || download === `{"error":"Not Found"}` ?
null
: download;
}
} catch (error) {
if (debugLogging) console.log('error in grabReleaseFileFromRepository', URL, error);
return null;
Expand All @@ -41,7 +124,8 @@ export const grabReleaseFileFromRepository = async (
export const grabManifestJsonFromRepository = async (
repositoryPath: string,
rootManifest = true,
debugLogging = true
debugLogging = true,
personalAccessToken = ''
): Promise<PluginManifest | null> => {
const manifestJsonPath =
GITHUB_RAW_USERCONTENT_PATH +
Expand All @@ -50,7 +134,15 @@ export const grabManifestJsonFromRepository = async (
if (debugLogging)
console.log('grabManifestJsonFromRepository manifestJsonPath', manifestJsonPath);
try {
const response: string = await request({ url: manifestJsonPath });
const response: string = await request({
url: manifestJsonPath,
headers:
personalAccessToken ?
{
Authorization: `Token ${personalAccessToken}`,
}
: {},
});
if (debugLogging) console.log('grabManifestJsonFromRepository response', response);
return response === '404: Not Found' ? null : (
((await JSON.parse(response)) as PluginManifest)
Expand Down
2 changes: 2 additions & 0 deletions src/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export interface Settings {
loggingVerboseEnabled: boolean;
debuggingMode: boolean;
notificationsEnabled: boolean;
personalAccessToken?: string;
}

export const DEFAULT_SETTINGS: Settings = {
Expand All @@ -38,6 +39,7 @@ export const DEFAULT_SETTINGS: Settings = {
loggingVerboseEnabled: false,
debuggingMode: false,
notificationsEnabled: true,
personalAccessToken: '',
};

/**
Expand Down
15 changes: 15 additions & 0 deletions src/ui/SettingsTab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -240,5 +240,20 @@ export class BratSettingsTab extends PluginSettingTab {
await this.plugin.saveSettings();
});
});

new Setting(containerEl)
.setName('Personal Access Token')
.setDesc(
'If you need to access private repository, enter the personal access token here.'
)
.addText((text) => {
text
.setPlaceholder('Enter your personal access token')
.setValue(this.plugin.settings.personalAccessToken ?? '')
.onChange(async (value: string) => {
this.plugin.settings.personalAccessToken = value;
await this.plugin.saveSettings();
});
});
}
}

0 comments on commit d86a6af

Please sign in to comment.