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

Commit

Permalink
Apply GitHub authentication plugin (#604)
Browse files Browse the repository at this point in the history
Add a plugin that authenticates vscode GitHub PR plugin launched in Che-Theia
The plugin calls Che oAuth API service to get the GitHub token. Then it injects it to the user preferences. When the browser page is refreshed the vscode GitHub PR plugin fetches the token and cleans the token from the preferences file.
  • Loading branch information
vinokurig committed Jan 29, 2020
1 parent 770973c commit 83efca5
Show file tree
Hide file tree
Showing 14 changed files with 172 additions and 25 deletions.
1 change: 1 addition & 0 deletions che-theia-init-sources.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ sources:
- plugins/welcome-plugin
- plugins/ssh-plugin
- plugins/telemetry-plugin
- plugins/github-auth-plugin
checkoutTo: master
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/

import { CheGithubMain } from '../common/che-protocol';
import { CheApiService, CheGithubMain } from '../common/che-protocol';
import { interfaces } from 'inversify';
import { EnvVariablesServer } from '@theia/core/lib/common/env-variables';
import axios, { AxiosInstance } from 'axios';
Expand All @@ -18,9 +18,11 @@ export class CheGithubMainImpl implements CheGithubMain {
private axiosInstance: AxiosInstance = axios;
private apiUrl: string;
private token: string | undefined;
private readonly cheApiService: CheApiService;

constructor(container: interfaces.Container) {
this.envVariableServer = container.get(EnvVariablesServer);
this.cheApiService = container.get(CheApiService);
this.envVariableServer.getValue('CHE_API').then(variable => {
if (variable && variable.value) {
this.apiUrl = variable.value;
Expand All @@ -36,6 +38,15 @@ export class CheGithubMainImpl implements CheGithubMain {
});
}

async $getToken(): Promise<string> {
await this.fetchToken();
if (this.token) {
return this.token;
} else {
throw new Error('Failed to get GitHub authentication token');
}
}

private async fetchToken(): Promise<void> {
if (!this.token) {
await this.updateToken();
Expand All @@ -49,17 +60,17 @@ export class CheGithubMainImpl implements CheGithubMain {
}

private async updateToken(): Promise<void> {
this.token = await this.getToken();
this.token = await this.cheApiService.getOAuthToken('github');
if (!this.token) {
await this.authenticate();
this.token = await this.getToken();
this.token = await this.cheApiService.getOAuthToken('github');
}
}

private authenticate(): Promise<void> {
return new Promise(async (resolve, reject) => {
const redirectUrl = window.location.href;
const url = `${this.apiUrl}/oauth/authenticate?oauth_provider=github&userId=${await this.getUserId()}` +
const url = `${this.apiUrl}/oauth/authenticate?oauth_provider=github&userId=${await this.cheApiService.getUserId()}` +
`&scope=write:public_key&redirect_after_login=${redirectUrl}`;
const popupWindow = window.open(url, 'popup');
const popup_close_handler = async () => {
Expand All @@ -85,18 +96,4 @@ export class CheGithubMainImpl implements CheGithubMain {
const popupCloseHandlerIntervalId = window.setInterval(popup_close_handler, 80);
});
}

private async getToken(): Promise<string | undefined> {
try {
const result = await this.axiosInstance.get<{ token: string }>(`${this.apiUrl}/oauth/token?oauth_provider=github`);
return result.data.token;
} catch (e) {
return undefined;
}
}

private async getUserId(): Promise<string | undefined> {
const result = await this.axiosInstance.get<{ id: string }>(`${this.apiUrl}/user`);
return result.data.id;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,6 @@ export interface CheFactoryMain {
export interface CheDevfile {
}

export interface CheGithub {
uploadPublicSshKey(publicKey: string): Promise<void>;
}

export interface CheDevfileMain {
$createWorkspace(devfilePath: string): Promise<void>;
}
Expand All @@ -65,8 +61,14 @@ export interface CheSshMain {
$deleteKey(service: string, name: string): Promise<void>;
}

export interface CheGithub {
uploadPublicSshKey(publicKey: string): Promise<void>;
getToken(): Promise<string>;
}

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

/**
Expand Down Expand Up @@ -433,6 +435,7 @@ export interface CheApiService {

getFactoryById(factoryId: string): Promise<cheApi.factory.Factory>;

getUserId(): Promise<string>;
getUserPreferences(): Promise<Preferences>;
getUserPreferences(filter: string | undefined): Promise<Preferences>;
updateUserPreferences(update: Preferences): Promise<Preferences>;
Expand All @@ -448,6 +451,7 @@ export interface CheApiService {
getAllSshKey(service: string): Promise<cheApi.ssh.SshPair[]>;
submitTelemetryEvent(id: string, ownerId: string, ip: string, agent: string, resolution: string, properties: [string, string][]): Promise<void>;
submitTelemetryActivity(): Promise<void>;
getOAuthToken(oAuthProvider: string): Promise<string | undefined>;
}

export const CHE_TASK_SERVICE_PATH = '/che-task-service';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ export class CheApiServiceImpl implements CheApiService {
return process.env.CHE_API_INTERNAL;
}

async getUserId(): Promise<string> {
const cheApiClient = await this.getCheApiClient();
const user = await cheApiClient.getCurrentUser();
return user.id;
}

async getUserPreferences(filter?: string): Promise<Preferences> {
const cheApiClient = await this.getCheApiClient();
return cheApiClient.getUserPreferences(filter);
Expand Down Expand Up @@ -282,6 +288,15 @@ export class CheApiServiceImpl implements CheApiService {
}
}

async getOAuthToken(oAuthProvider: string): Promise<string | undefined> {
const cheApiClient = await this.getCheApiClient();
try {
return await cheApiClient.getOAuthToken(oAuthProvider);
} catch (e) {
return undefined;
}
}

private getWorkspaceTelemetryClient(): TelemetryClient | undefined {

if (!this.telemetryClient) {
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 @@ -120,6 +120,9 @@ export function createAPIFactory(rpc: RPCProtocol): CheApiFactory {
const github: typeof che.github = {
uploadPublicSshKey(publicKey: string): Promise<void> {
return cheGithubImpl.uploadPublicSshKey(publicKey);
},
getToken(): Promise<string> {
return cheGithubImpl.getToken();
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,8 @@ export class CheGithubImpl implements CheGithub {
uploadPublicSshKey(publicKey: string): Promise<void> {
return this.githubMain.$uploadPublicSshKey(publicKey);
}

getToken(): Promise<string> {
return this.githubMain.$getToken();
}
}
1 change: 1 addition & 0 deletions extensions/eclipse-che-theia-plugin/src/che-proposed.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ declare module '@eclipse-che/plugin' {

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

export namespace ssh {
Expand Down
3 changes: 3 additions & 0 deletions plugins/github-auth-plugin/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
lib/
node_modules/
*.theia
9 changes: 9 additions & 0 deletions plugins/github-auth-plugin/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Theia - vscode Github pull-request plugin authenticator

The plugin calls Che oAuth API service to get the GitHub token.
Then it injects it to the user preferences. When the browser page is refreshed,
the vscode GitHub PR plugin fetches the token and cleans the token from the preferences file.

## License

[EPL-2.0](http://www.eclipse.org/legal/epl-2.0)
42 changes: 42 additions & 0 deletions plugins/github-auth-plugin/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"name": "@eclipse-che/github-auth-plugin",
"version": "0.0.1",
"publisher": "Eclipse Che",
"keywords": [
"theia-plugin"
],
"description": "Authenticates the vscode Github pull-request plugin",
"license": "EPL-2.0",

"files": [
"src"
],
"activationEvents": [
"*"
],
"devDependencies": {
"@theia/plugin": "next",
"@theia/plugin-packager": "latest",
"@eclipse-che/plugin": "0.0.1",
"rimraf": "2.6.2",
"typescript-formatter": "7.2.2",
"typescript": "2.9.2",
"ts-loader": "^4.1.0"
},
"scripts": {
"prepare": "yarn run clean && yarn run build",
"clean": "rimraf lib",
"format": "tsfmt -r --useTsfmt ../../configs/tsfmt.json",
"lint": "tslint -c ../../configs/tslint.json --project tsconfig.json",
"lint:fix": "tslint -c ../../configs/tslint.json --fix --project .",
"compile": "tsc",
"build": "yarn lint:fix && concurrently -n \"format,lint,compile\" -c \"red,green,blue\" \"yarn format\" \"yarn lint\" \"yarn compile\" && theia-plugin pack",
"watch": "tsc -w"
},
"engines": {
"theiaPlugin": "next"
},
"theiaPlugin": {
"backend": "lib/github-auth-plugin.js"
}
}
35 changes: 35 additions & 0 deletions plugins/github-auth-plugin/src/github-auth-plugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*********************************************************************
* Copyright (c) 2020 Red Hat, Inc.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/

import * as theia from '@theia/plugin';
import * as che from '@eclipse-che/plugin';

export function start(context: theia.PluginContext) {
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 = await 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');
}));
}
}

export function stop() {

}
15 changes: 15 additions & 0 deletions plugins/github-auth-plugin/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"extends": "../../configs/base.tsconfig",
"compilerOptions": {
"skipLibCheck": true,
"lib": [
"es6",
"webworker"
],
"rootDir": "src",
"outDir": "lib"
},
"include": [
"src"
]
}
18 changes: 18 additions & 0 deletions plugins/github-auth-plugin/tsfmt.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"baseIndentSize": 0,
"newLineCharacter": "\n",
"indentSize": 4,
"tabSize": 4,
"indentStyle": 4,
"convertTabsToSpaces": true,
"insertSpaceAfterCommaDelimiter": true,
"insertSpaceAfterSemicolonInForStatements": true,
"insertSpaceBeforeAndAfterBinaryOperators": true,
"insertSpaceAfterKeywordsInControlFlowStatements": true,
"insertSpaceAfterFunctionKeywordForAnonymousFunctions": false,
"insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": false,
"insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": false,
"insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": false,
"placeOpenBraceOnNewLineForFunctions": false,
"placeOpenBraceOnNewLineForControlBlocks": false
}
6 changes: 3 additions & 3 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@
"@eclipse-che/api" latest

"@eclipse-che/workspace-client@latest":
version "0.0.1-1574171760"
resolved "https://registry.yarnpkg.com/@eclipse-che/workspace-client/-/workspace-client-0.0.1-1574171760.tgz#e4066030fe4cb35f21a82e173e37633d37c76520"
integrity sha512-lCnrrb9jKkxbO9QSmFERHvDxrN+8j1X/3RypESu7n7nrG53ubEqnnquTbU+vEgrMHyg1x0ctLRiUBQarM8dslg==
version "0.0.1-1579077578"
resolved "https://registry.yarnpkg.com/@eclipse-che/workspace-client/-/workspace-client-0.0.1-1579077578.tgz#0fc322b536eb46bf271effc3f00a0435038b5966"
integrity sha512-j3hPUaMcld6cw0wuqQd/EjjUAkkq7J5iri8MCJYJf2eSylLnjYRabNfnfVS4REgj3b02VXLx3kuDGmNPLacSEw==
dependencies:
"@eclipse-che/api" "^7.0.0-beta-4.0"
axios "0.19.0"
Expand Down

0 comments on commit 83efca5

Please sign in to comment.