Commit fdd469a6 authored by Chris Hines's avatar Chris Hines
Browse files

Merge branch 'dev' into 'test'

Dev

See merge request !94
parents 2d6dc3c0 8b5ca7a3
Pipeline #17877 passed with stages
in 9 minutes and 18 seconds
......@@ -44,22 +44,12 @@
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"fileReplacements": [
"assets": [
"src/assets",
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
},
{
"replace": "src/assets/config/apiservers.json",
"with": "src/assets/config/apiservers.prod.json"
},
{
"replace": "src/assets/config/computesites.json",
"with": "src/assets/config/computesites.prod.json"
},
{
"replace": "src/assets/config/authservers.json",
"with": "src/assets/config/authservers.prod.json"
"input": "src/deployments/prod/assets/config",
"output": "assets/config",
"glob": "*.json"
}
]
},
......@@ -79,22 +69,12 @@
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
},
{
"replace": "src/assets/config/apiservers.json",
"with": "src/assets/config/apiservers.prod.json"
},
"assets": [
"src/assets",
{
"replace": "src/assets/config/computesites.json",
"with": "src/assets/config/computesites.prod.json"
},
{
"replace": "src/assets/config/authservers.json",
"with": "src/assets/config/authservers.prod.json"
"input": "src/deployments/prod/assets/config",
"output": "assets/config",
"glob": "*.json"
}
]
},
......@@ -105,14 +85,12 @@
"maximumWarning": "6kb"
}
],
"fileReplacements": [
{
"replace": "src/assets/config/apiservers.json",
"with": "src/assets/config/apiservers.test.json"
},
{
"replace": "src/assets/config/computesites.json",
"with": "src/assets/config/computesites.test.json"
"assets": [
"src/assets",
{
"input": "src/deployments/test/assets/config",
"output": "assets/config",
"glob": "*.json"
}
]
},
......@@ -123,14 +101,12 @@
"maximumWarning": "6kb"
}
],
"fileReplacements": [
{
"replace": "src/assets/config/apiservers.json",
"with": "src/assets/config/apiservers.dev.json"
},
"assets": [
"src/assets",
{
"replace": "src/assets/config/computesites.json",
"with": "src/assets/config/computesites.dev.json"
"input": "src/deployments/dev/assets/config",
"output": "assets/config",
"glob": "*.json"
}
]
}
......
import { app, BrowserWindow, screen, ipcMain, IpcMainEvent } from 'electron';
import * as path from 'path';
import * as url from 'url';
import * as fs from 'fs';
import * as YAML from 'yaml';
import * as child from 'child_process';
import * as temp from 'tmp';
let win: BrowserWindow = null;
const args = process.argv.slice(1),
serve = args.some(val => val === '--serve');
let lastUrl: string = null;
console.log('resources path', __dirname );
var config: any;
let configPath = path.join(app.getPath('userData'),'localConfig.yml');
try {
config = YAML.parse(fs.readFileSync(configPath).toString());
} catch {
console.log(`please create a config file at ${configPath}`)
}
//let config = YAML.parse(fs.readFileSync(path.join(__dirname,'localConfig.yml')).toString())
//var aafds: string = "https://ds.aaf.edu.au/discovery/aaf/9DrjGhkyXjXsPm45rqpCXA?entityID=https%3A%2F%2Fcentral.aaf.edu.au%2Fshibboleth&return=https%3A%2F%2Fcentral.aaf.edu.au%2FShibboleth.sso%2FLogin%3FSAMLDS%3D1%26identity%3D1%26target%3Dhttps%253A%252F%252Fcentral.aaf.edu.au%252Fresolvers%252Fsaml_federation%252Freceive%253Fibr%253D19a58192-de47-4580-a272-cc61c60e4f47%2526pib%253D0a206a4e-e6eb-4d18-b46d-e475ec8d09b5"
function createWindow(): BrowserWindow {
const electronScreen = screen;
const size = electronScreen.getPrimaryDisplay().workAreaSize;
// Create the browser window.
win = new BrowserWindow({
x: 0,
y: 0,
width: size.width,
height: size.height,
webPreferences: {
nodeIntegration: false,
allowRunningInsecureContent: (serve) ? true : false,
contextIsolation: true, // false if you want to run 2e2 test with Spectron
enableRemoteModule : false, // true if you want to run 2e2 test with Spectron or use remote module in renderer context (ie. Angular)
preload: path.join(__dirname, "preload.js")
},
});
if (serve) {
win.webContents.openDevTools();
require('electron-reload')(__dirname, {
electron: require(`${__dirname}/node_modules/electron`)
});
win.loadURL('http://localhost:4200');
} else {
win.loadURL(url.format({
pathname: path.join(__dirname, 'dist/index.html'),
protocol: 'file:',
slashes: true
}));
}
// Emitted when the window is closed.
win.on('closed', () => {
// Dereference the window object, usually you would store window
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
win = null;
});
const redirectUri = 'http://localhost:4200/sshauthz_callback'
const filter = {
urls: [redirectUri + '*']
};
win.webContents.session.webRequest.onBeforeRequest(filter, function(details, callback) {
win.loadURL(url.format({
pathname: path.join(__dirname, 'dist/index.html'),
protocol: 'file:',
slashes: true
}));
win.webContents.on('did-finish-load', () => {
if (lastUrl != details.url) {
console.log('sending oauth2-redirect with ',details.url);
console.log(details);
win.webContents.send('oauth2-redirect',details.url);
lastUrl = details.url;
}
})
callback({ cancel: false });
});
return win;
}
try {
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
// Added 400 ms to fix the black background issue while using transparent window. More detais at https://github.com/electron/electron/issues/15947
app.on('ready', () => setTimeout(createWindow, 400));
// Quit when all windows are closed.
app.on('window-all-closed', () => {
// On OS X it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit();
}
});
ipcMain.on('addCert', async (event: IpcMainEvent,data: any) => await addCert(event, data))
console.log('ipcMain on set');
app.on('activate', () => {
// On OS X it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (win === null) {
createWindow();
}
});
} catch (e) {
// Catch Error
// throw e;
}
async function addCert(event: IpcMainEvent, data: any) {
console.log('adding Cert', data)
let tmpfile = temp.fileSync();
let path = tmpfile.path;
fs.writeFileSync(`${path}`,data.key, {encoding: 'utf8', mode: 0o600 });
fs.writeFileSync(`${path}-cert.pub`,data.cert, {encoding: 'utf8', mode: 0o600 });
let sa = child.execSync(`${config['ssh-add']} ${path}`);
event.reply('addCertResponse',null);
fs.unlinkSync(`${path}`);
fs.unlinkSync(`${path}-cert.pub`);
}
This diff is collapsed.
{
"name": "angular-electron",
"name": "strudel2",
"version": "9.0.4",
"description": "Angular 11 with Electron (Typescript + SASS + Hot Reload)",
"homepage": "https://github.com/maximegris/angular-electron",
"description": "Strudel2",
"homepage": "https://gitlab.erc.monash.edu.au/hpc-team/strudelv2_spa",
"author": {
"name": "Maxime GRIS",
"email": "maxime.gris@gmail.com"
"name": "Chris Hines",
"email": "chris.hines@monash.edu"
},
"keywords": [
"angular",
......@@ -46,11 +46,14 @@
"@angular/flex-layout": "11.0.0-beta.33",
"@angular/material": "11.2.3",
"buffer": "6.0.3",
"child_process": "^1.0.2",
"jwk-to-ssh": "1.2.0",
"keypair": "1.0.2",
"node-forge": "0.10.0",
"rxjs-compat": "6.6.6",
"web-ext": "5.5.0"
"tmp": "^0.0.33",
"web-ext": "5.5.0",
"yaml": "^1.10.2"
},
"devDependencies": {
"@angular-builders/custom-webpack": "11.0.0",
......@@ -83,7 +86,7 @@
"conventional-changelog-cli": "2.1.1",
"core-js": "3.6.5",
"cross-env": "7.0.3",
"electron": "11.2.0",
"electron": "^11.4.2",
"electron-builder": "22.9.1",
"electron-reload": "1.5.0",
"eslint": "7.20.0",
......@@ -104,7 +107,7 @@
"ts-node": "9.1.1",
"tslib": "2.1.0",
"typescript": "4.0.5",
"wait-on": "5.0.1",
"wait-on": "^5.3.0",
"webdriver-manager": "12.1.8",
"zone.js": "0.10.3"
},
......@@ -113,5 +116,21 @@
},
"browserslist": [
"chrome 83"
]
],
"build": {
"extraResources": [
{
"from": "./resources/",
"to": "",
"filter": [
"**/*"
]
}
],
"files": [
"main.js",
"./dist/**/*",
"./public/electron.js"
]
}
}
// All of the Node.js APIs are available in the preload process.
// It has the same sandbox as a Chrome extension.
import { contextBridge, IpcRenderer } from 'electron';
const ipcRenderer: IpcRenderer = require('electron').ipcRenderer;
contextBridge.exposeInMainWorld(
'electronApi',
{
addCert: (data: any, fn: () => void): void => { addCert(data, fn) },
register_oauth2_redirect: (fn: (arg0: string) => void): void => {register_oauth2_redirect(fn)}
}
)
function addCert(data: any, fn: any): void {
ipcRenderer.once('addCertResponse', (event, ...args) => fn() )
ipcRenderer.send('addCert', (data));
}
function register_oauth2_redirect(fn: (arg0: string) => void ): void {
ipcRenderer.once('oauth2-redirect',(event, url) => fn(url));
}
......@@ -52,14 +52,17 @@ export class AppComponent {
this.authService.loggedOutAuthZ.pipe(
isdefined
).subscribe((v) => { this.loggedout = (<[]>v).length } );
this.ipcService.once('oauth2-redirect',(event, ...args: any[]) => this.route_to_keygen(event, args));
console.log('call ipcService once for oauth2-redirect');
this.ipcService.register_oauth2_redirect((url) => { this.route_to_keygen(url)} );
//this.ipcService.once('oauth2-redirect',(event, ...args: any[]) => this.route_to_keygen(event, args));
}
route_to_keygen(event, ... args: any[]) {
console.log('calling back from oauth', args);
var url: string = args[0][0];
route_to_keygen(url: string) {
//console.log('calling back from oauth', args);
//var url: string = args[0][0][0];
console.log('url is', url);
let fragment = "#" + url.split('#')[1];
console.log('app.component is updating fragment');
console.log('app.component is updating fragment',fragment);
this.authService.updateFragment(fragment);
this.router.navigate(['/sshauthz_callback']);
}
......
......@@ -365,7 +365,7 @@ public getKeys(id?: Identity) {
let state = statematch[1];
let tuple = JSON.parse(sessionStorage.getItem('authservice'));
if (tuple[1] != state) {
throw new Error('callback state parameter does not match');
throw new Error('callback state parameter does not match'+frag+tuple);
}
return new AuthToken(tokenmatch[1],tuple[0]);
......@@ -401,13 +401,21 @@ public getKeys(id?: Identity) {
return this.sshAdd(keyCert,apiserver);
}
public sshAdd(keyCert: KeyCert, apiserver) {
public sshAdd(keyCert: KeyCert, apiserver): Observable<any> {
let headers = new HttpHeaders();
let options = { headers: headers, withCredentials: true};
var anyvar: any;
let data = {'key': keyCert.key, 'cert': keyCert.cert};
console.log('in authService.sshAdd, adding to',apiserver);
return this.http.post<any>(apiserver.tes+'/sshagent',data,options)
let remoteAddCert = this.http.post<any>(apiserver.tes+'/sshagent',data,options);
if (this.ipcService.useIpc) {
var localAddCert: Observable<any> = this.ipcService.addCert(data);
console.log('sshAdd using IPC and API server');
return combineLatest([localAddCert,remoteAddCert]).pipe(map(([_,remote]) => { return remote }));
} else {
console.log('sshAdd using API server only');
return remoteAddCert;
}
//return localAddCert;
}
storeKey(keyCert: KeyCert) {
......
import { Injectable } from '@angular/core';
import { IpcRenderer } from 'electron';
import { Observable, Observer } from 'rxjs';
//import {Window} from './global';
declare global {
interface Window {
"electronApi": {
addCert: (data: any, callback: any) => void;
register_oauth2_redirect: (fn: any) => void;
}
}
}
@Injectable({
providedIn: 'root'
})
export class IpcService {
private _ipc: IpcRenderer | undefined;
public useIpc: boolean = false;
constructor() {
constructor() {
if (window.electronApi) {
this.useIpc = true;
} else {
console.log('window electronAPI is not defined');
}
}
public addCert(data): Observable<any> {
return new Observable<any>( (observer: Observer<any>) => { window.electronApi.addCert(data, () => { observer.next(true) } ) } )
}
public register_oauth2_redirect(fn: (arg0: string) => void) {
window.electronApi.register_oauth2_redirect(fn);
}
}
/* constructor() {
if (window.require) {
try {
this._ipc = window.require('electron').ipcRenderer;
this.useIpc = true;
} catch (e) {
throw e;
}
......@@ -40,3 +67,4 @@ export class IpcService {
this._ipc.send(channel, ...args);
}
}
*/
\ No newline at end of file
......@@ -20,7 +20,7 @@ export class KeygenComponent implements OnInit, OnDestroy {
console.log('entered keygen component');
console.log(this.route);
//this.initPipelines();
this.route.fragment.pipe(filter((v) => v !== null)).subscribe((v) => { console.log('keygen is updating fragment',v) ; this.authService.updateFragment(v)});
this.route.fragment.pipe(filter((v) => ( v !== null && v !== undefined ))).subscribe((v) => { console.log('keygen is updating fragment',v) ; this.authService.updateFragment(v)});
}
ngOnDestroy() {
......
......@@ -58,13 +58,7 @@ export class LoginComponent implements OnInit {
this.subscriptions = []
this.subscriptions.push(this.authService.sshAuthzServers.subscribe(o => {this.updateSshAuthZServers(o)}));
console.log('using the ipservice to ping');
this.ipcService.send('ping','hello');
console.log('ping sent');
this.subscriptions.push(this.authService.sshAuthzServers.subscribe(o => {this.updateSshAuthZServers(o)}));
}
updateSshAuthZServers(o) {
......
......@@ -11,17 +11,4 @@
"scope": "user:email",
"cafingerprint": "ECDSA SHA256:6wVXdokvvlTNcXPMc9KyvIXA8a8XNfLuhBfNOYeeMdg",
"desc": "<div>The Characterisation Virtual Laboratory remote desktop services are available here. The service provides software, data and compute for researchers in the Characterisation research community. For CVL desktop researchers from MASSIVE see <a href=https://www.massive.org.au>https://www.massive.org.au</a> for more information. For CVL desktop users from other infrastructures see <a href=https://www.cvl.org.au>https://www.cvl.org.au</a></div>"
},
{
"authorise": "http://localhost:5000/oauth2/oauth/authorize/choose",
"base": "http://localhost:5000/oauth2/",
"client_id": "Q96kt2Vtw6S78dpORktM81DH",
"sign": "http://localhost:5000/sign/monash_hpcid/api/v1/sign_key",
"logout": "http://localhost:5000/oauth2/logout",
"name": "Localhost",
"icon": null,
"scope": "user:email",
"cafingerprint": "RSA SHA256:cmDxHrZQSPlBMUUcI/BWmruXho1XOzfXPDHSqVTwV2I",
"desc": "<div>The Characterisation Virtual Laboratory remote desktop services are available here. The service provides software, data and compute for researchers in the Characterisation research community. For CVL desktop researchers from MASSIVE see <a href=https://www.massive.org.au>https://www.massive.org.au</a> for more information. For CVL desktop users from other infrastructures see <a href=https://www.cvl.org.au>https://www.cvl.org.au</a></div>"
}
]
}]
[
{
"name": "Dev",
"tes": "https://strudel2-api-dev.cloud.cvl.org.au/tes",
"tws": "https://strudel2-api-dev.cloud.cvl.org.au"
},
{
"name": "Beta",
"tes": "https://beta-api.desktop.massive.org.au/tes",
"tws": "https://beta-api.desktop.massive.org.au"
},
{
"name": "Dev - Pawsey",
"tes": "https://strudel2-api-dev-pawsey.cloud.cvl.org.au/tes",
"tws": "https://strudel2-api-dev-pawsey.cloud.cvl.org.au"
},
{
"name": "localhost",
"tes": "http://localhost:8080",
"tws": "http://localhost:8090"
}
]
[
{
"url": "https://strudel2-api-dev.cloud.cvl.org.au/m3/",
"name": "M3",
"host": "m3.massive.org.au",
"dtn": "m3-dtn1.massive.org.au",
"cafingerprint": "ECDSA SHA256:6wVXdokvvlTNcXPMc9KyvIXA8a8XNfLuhBfNOYeeMdg",
"appCatalog": [],
"appCatalogCmd": "/usr/local/strudel2_cluster/latest/bin/getapps-dev",
"cancelcmd": "/usr/local/strudel2_cluster/latest/bin/s2cancel {jobid}",
"statcmd": "/usr/local/strudel2_cluster/latest/bin/s2stat",
"userhealth": "/usr/local/clusterinfo/0.0.6/bin/uijson",
"cacheturis": ["/assets/config/incidents.json"],
"contact": "<MASSIVE Support> help@massive.org.au"
},
{
"url": "https://strudel2-api-dev.cloud.cvl.org.au/m3/",
"name": "OzStar",
"host": "ozstar.swin.edu.au",
"dtn": "ozstar.swin.edu.au",
"cafingerprint": "RSA SHA256:gK5t29EO9zIbWartnIFIpzewWQcPWpj2D9nZ9HOS29Y",
"appCatalog": [],
"appCatalogCmd": "cat /dagg/strudel/dev/apps.json",
"cancelcmd": "/dagg/strudel/dev/bin/s2cancel {jobid}",
"statcmd": "/dagg/strudel/dev/bin/s2stat",
"userhealth": "/dagg/strudel/dev/bin/uijson",
"cacheturis": [],
"contact": "<OzStar Support> hpc-support@swin.edu.au"
}
]
[
{ "url": null,
"name": "Desktop",
"startscript": "#!/bin/bash\n/usr/local/sv2/desktop/desktop.slurm\n ",
"paramscmd": "/usr/local/sv2/desktop/params.py",
"client": {"cmd": null, "redir": "vnc.html?password={password}" },
"localbind": true,
"applist": null
},
{
"url": null,
"name": "Jupyter Lab",
"startscript": "#!/bin/bash\n/usr/local/sv2/jupyter/jupyter.slurm\n",
"paramscmd": "/usr/local/sv2/jupyter/jupyter_params.py",
"client": {"cmd": null, "redir": "?token={token}"},
"localbind": true,
"applist": null
},
{
"url": null,
"name": "R Studio Server",
"startscript": "#!/bin/bash\n/usr/local/sv2/rstudioserver/run.sh\n",
"paramscmd": "/usr/local/sv2/rstudioserver/params.py",
"client": {"cmd": null, "redir": ""},
"localbind": true,
"applist": null
},
{ "url": "transfer",
"name": "Transfer files",
"startscript": "#!/bin/bash\n echo '{appparams}' > ft.json",
"paramscmd": "/usr/local/sv2/copytool.py",
"client": {"cmd": null, "redir": null },
"localbind": true,
"applist": null
}
]
[
{ "name": "divider"},
{ "url": null,
"name": "Desktop",
"startscript": "#!/bin/bash\n/usr/local/sv2/dev/desktop/desktop.slurm\n ",
"appactions": [
],
"instactions": [
{
"name": "Connect",