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

Apply GitHub authentication plugin #604

Merged
merged 6 commits into from
Jan 29, 2020
Merged
Show file tree
Hide file tree
Changes from 3 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
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 @@ -429,6 +431,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 @@ -444,6 +447,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 @@ -116,6 +116,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 @@ -45,6 +45,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": "Manage Eclipse Che Telemetry Plugin",
vinokurig marked this conversation as resolved.
Show resolved Hide resolved
"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) 2019 Red Hat, Inc.
vinokurig marked this conversation as resolved.
Show resolved Hide resolved
*
* 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