Skip to content
This repository has been archived by the owner on Apr 4, 2023. It is now read-only.

Register GitHub Authentication provider for the vscode GitHub PR plugin #841

Merged
merged 4 commits into from
Oct 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { CheGithubMain } from '../common/che-protocol';
import { interfaces } from 'inversify';
import axios, { AxiosInstance } from 'axios';
import { OauthUtils } from '@eclipse-che/theia-remote-api/lib/browser/oauth-utils';
import { GithubUser } from '@eclipse-che/plugin';

export class CheGithubMainImpl implements CheGithubMain {
private axiosInstance: AxiosInstance = axios;
Expand Down Expand Up @@ -39,12 +40,23 @@ export class CheGithubMainImpl implements CheGithubMain {
}
}

async $getUser(): Promise<GithubUser> {
await this.fetchToken();
return this.getUser();
}

private async getUser(): Promise<GithubUser> {
const result = await this.axiosInstance.get<GithubUser>('https://api.github.com/user?access_token=' + this.token);
return result.data;
}

private async fetchToken(): Promise<void> {
if (!this.token) {
await this.updateToken();
} else {
try {
await this.axiosInstance.get('https://api.github.com/user?access_token=' + this.token);
// Validate the GitHub token.
await this.getUser();
} catch (e) {
await this.updateToken();
}
Expand All @@ -55,8 +67,10 @@ export class CheGithubMainImpl implements CheGithubMain {
const oAuthProvider = 'github';
try {
this.token = await this.oAuthUtils.getToken(oAuthProvider);
// Validate the GitHub token.
await this.getUser();
} catch (e) {
if (e.message.indexOf('Request failed with status code 401') > 0) {
if (e.message.indexOf('Request failed with status code 401') !== -1) {
await this.oAuthUtils.authenticate(oAuthProvider, ['write:public_key']);
this.token = await this.oAuthUtils.getToken(oAuthProvider);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,13 @@ export interface CheOpenshiftMain {
export interface CheGithub {
uploadPublicSshKey(publicKey: string): Promise<void>;
getToken(): Promise<string>;
getUser(): Promise<che.GithubUser>;
}

export interface CheGithubMain {
$uploadPublicSshKey(publicKey: string): Promise<void>;
$getToken(): Promise<string>;
$getUser(): Promise<che.GithubUser>;
}

export interface CheOauth {
Expand Down
3 changes: 3 additions & 0 deletions extensions/eclipse-che-theia-plugin-ext/src/plugin/che-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,9 @@ export function createAPIFactory(rpc: RPCProtocol): CheApiFactory {
},
getToken(): Promise<string> {
return cheGithubImpl.getToken();
},
getUser(): Promise<che.GithubUser> {
return cheGithubImpl.getUser();
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

import { RPCProtocol } from '@theia/plugin-ext/lib/common/rpc-protocol';
import { PLUGIN_RPC_CONTEXT, CheGithub, CheGithubMain } from '../common/che-protocol';
import { GithubUser } from '@eclipse-che/plugin';

export class CheGithubImpl implements CheGithub {

Expand All @@ -26,4 +27,8 @@ export class CheGithubImpl implements CheGithub {
getToken(): Promise<string> {
return this.githubMain.$getToken();
}

getUser(): Promise<GithubUser> {
return this.githubMain.$getUser();
}
}
8 changes: 8 additions & 0 deletions extensions/eclipse-che-theia-plugin/src/che-proposed.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,17 @@ declare module '@eclipse-che/plugin' {
export function createWorkspace(devfilePath: string): Promise<void>;
}

export interface GithubUser {
login: string,
id: number,
name: string,
email: string
}

export namespace github {
export function uploadPublicSshKey(publicKey: string): Promise<void>;
export function getToken(): Promise<string>;
export function getUser(): Promise<GithubUser>;
}

export namespace openshift {
Expand Down
62 changes: 47 additions & 15 deletions plugins/github-auth-plugin/src/github-auth-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,54 @@
import * as theia from '@theia/plugin';
import * as che from '@eclipse-che/plugin';

export function start(context: theia.PluginContext): void {
export async function start(context: theia.PluginContext): Promise<void> {
if (theia.plugins.getPlugin('github.vscode-pull-request-github')) {
const command = {
id: 'github-plugin-authenticate',
label: 'GitHub authenticate'
};
context.subscriptions.push(theia.commands.registerCommand(command, async () => {
const token = await che.github.getToken();
const conf = theia.workspace.getConfiguration();
await conf.update('githubPullRequests.hosts', [{
host: 'github.com',
token
}], theia.ConfigurationTarget.Global);
theia.window.showWarningMessage('GitHub token has been set to preferences. ' +
'Refresh the page to reinitialise the vscode GitHub pull-request plugin with the token');
}));
let session: theia.AuthenticationSession | undefined = context.workspaceState.get('session');
const onDidChangeSessions = new theia.EventEmitter<theia.AuthenticationProviderAuthenticationSessionsChangeEvent>();
theia.authentication.registerAuthenticationProvider({
id: 'github',
label: 'GitHub',
supportsMultipleAccounts: false,
onDidChangeSessions: onDidChangeSessions.event,
getSessions: async () => {
if (session) {
return [session];
} else {
return [];
}
},
login: async (scopes: string[]) => {
const githubUser = await che.github.getUser();
session = {
id: 'github-session',
accessToken: await che.github.getToken(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what happen on fresh install, I'm not sure che.github.getToken() or che.github.getUser() is returning something ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case the GitHub authentication page appears:
https://github.com/eclipse/che-theia/blob/2f11124e7de0e50feed25fddf91a9058c37a2a1b/extensions/eclipse-che-theia-plugin-ext/src/browser/oauth-utils.ts#L101-L117
Then if user authenticates it the GitHub token is setup and these functions work as expected.

account: {label: githubUser.login, id: githubUser.id.toString()},
scopes
};
context.workspaceState.update('session', session);
onDidChangeSessions.fire({ added: [session.id], removed: [], changed: [] });
return session;
},
logout: async (id: string) => {
session = undefined;
context.workspaceState.update('session', session);
onDidChangeSessions.fire({ added: [], removed: [id], changed: [] });
}
}
);
if (session) {
onDidChangeSessions.fire({ added: [session.id], removed: [], changed: [] });
// TODO Remove the notification when https://github.com/eclipse-theia/theia/issues/7178 is fixed.
} else {
const signIn = 'Sign in';
const result = await theia.window.showInformationMessage(
'In order to use the Pull Requests functionality, you must sign in to GitHub',
signIn);

if (result === signIn) {
theia.authentication.getSession('github', ['read:user', 'user:email', 'repo'], { createIfNone: true });
}
}
}
}

Expand Down