Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Client authentication #500

Merged
merged 34 commits into from
Mar 8, 2022
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
8932d4e
Initial client authentication integration
MaybeJustJames Oct 14, 2021
449d35c
Working on replacing legacy functionality
MaybeJustJames Oct 18, 2021
e42a9ce
Some cleanup
MaybeJustJames Oct 21, 2021
78361b1
Remove unnecessary SessionLoading component
MaybeJustJames Oct 21, 2021
bf5e6d8
Testing 1
MaybeJustJames Oct 22, 2021
07449ca
Get client tests passing for Auth effects
MaybeJustJames Nov 10, 2021
d78ccfb
Fix audited security problems on dependencies
MaybeJustJames Nov 10, 2021
648f93e
Lint fixes
MaybeJustJames Nov 10, 2021
8e34cfa
Formatting
MaybeJustJames Nov 10, 2021
6c91a4d
Attempt to address SemGrep issue: User controlled data in Redirect
MaybeJustJames Nov 10, 2021
51f00ee
Test AuthPanel and LoginModal
MaybeJustJames Nov 11, 2021
7dc5cdd
Implement the Fantasyland Chain spec for our Result type
MaybeJustJames Nov 12, 2021
2f22644
Start implementing a new sidebar
MaybeJustJames Nov 12, 2021
8dca6ab
Minor changes to the server
MaybeJustJames Nov 18, 2021
226a296
Test the auth API on the client
MaybeJustJames Nov 18, 2021
be92589
Remove react-cookie-consent dep and update react-csv-reader
MaybeJustJames Nov 18, 2021
4eab24c
Fix tests
MaybeJustJames Nov 18, 2021
b494df8
Stop duplicating error messages on receipt of a token
MaybeJustJames Nov 19, 2021
9fa5a06
Get dataset upload working
MaybeJustJames Nov 23, 2021
2a9e5ab
Migrate to react router v6
MaybeJustJames Nov 24, 2021
ba57bc2
Remove some unnecessary packages
MaybeJustJames Nov 24, 2021
67acfeb
Remove unused parts of the legacy API
MaybeJustJames Nov 24, 2021
e9102f9
Revert removal of the old sidebar
MaybeJustJames Dec 6, 2021
b3d5a6d
Get the app compiling
MaybeJustJames Dec 6, 2021
8039d18
Tests and lint pass
MaybeJustJames Dec 6, 2021
c4c6202
Make sure client builds
MaybeJustJames Dec 9, 2021
a1519a3
Do what codefactor tells me
MaybeJustJames Dec 9, 2021
8bfaffc
Fix semgrep complaints
MaybeJustJames Dec 9, 2021
612adab
Make the HTTP API Url optionally depend on Environment
MaybeJustJames Mar 8, 2022
d29146c
Update npm deps
MaybeJustJames Mar 8, 2022
5d752ff
Add forgotten file
MaybeJustJames Mar 8, 2022
f9559c1
Update numpy
MaybeJustJames Mar 8, 2022
89f8796
Remove duplicated error handling
MaybeJustJames Mar 8, 2022
c380741
Always display the "Annotations" button in the header
MaybeJustJames Mar 8, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 6 additions & 1 deletion client/config/webpack.dev.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ const common = require('./webpack.common');
const BundleAnalyzerPlugin =
require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

const SCOPE_SERVER_URL = process.env.SCOPE_SERVER_URL
? process.env.SCOPE_SERVER_URL
: 'http://localhost:8000';

module.exports = merge(common, {
mode: 'development',

Expand Down Expand Up @@ -45,7 +49,8 @@ module.exports = merge(common, {
client_id: 'APP-1QNL921F7P9FC3S4',
redirect_uri: 'http://127.0.0.1:55850/',
}),
API_PREFIX: JSON.stringify('http://localhost:8000/api/v1/'),
SERVER_URL: JSON.stringify(SCOPE_SERVER_URL),
API_PREFIX: JSON.stringify('/api/v1/'),
LOGIN_REDIRECT: JSON.stringify('/oidc_redirect'),
LOGOUT_REDIRECT: JSON.stringify('/'),
__TEST_ONLY__: false,
Expand Down
15 changes: 6 additions & 9 deletions client/config/webpack.prod.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ const common = require('./webpack.common');

const TerserPlugin = require('terser-webpack-plugin');

const SCOPE_SERVER_URL = process.env.SCOPE_SERVER_URL
? process.env.SCOPE_SERVER_URL
: 'https://scope.aertslab.org';

module.exports = merge(common, {
mode: 'production',
devtool: false,
Expand All @@ -24,10 +28,6 @@ module.exports = merge(common, {
new webpack.DefinePlugin({
DEBUG: true,
REVERSEPROXYON: true,
BITLY: JSON.stringify({
baseURL: 'http://scope.aertslab.org',
token: '8422dd882b60604d327939997448dd1b5c61f54e',
}),
BACKEND: JSON.stringify({
httpProtocol: 'https',
wsProtocol: 'wss',
Expand All @@ -41,11 +41,8 @@ module.exports = merge(common, {
wsProtocol: 'wss',
host: 'scope.aertslab.org',
}),
ORCID: JSON.stringify({
client_id: 'APP-1QNL921F7P9FC3S4',
redirect_uri: 'https://scope.aertslab.org/',
}),
API_PREFIX: JSON.stringify('https://scope.aertslab.org/api/v1/'),
SERVER_URL: JSON.stringify(SCOPE_SERVER_URL),
API_PREFIX: JSON.stringify('/api/v1/'),
LOGIN_REDIRECT: JSON.stringify('/oidc_redirect'),
LOGOUT_REDIRECT: JSON.stringify('/'),
__TEST_ONLY__: false,
Expand Down
517 changes: 403 additions & 114 deletions client/package-lock.json

Large diffs are not rendered by default.

22 changes: 6 additions & 16 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -152,10 +152,7 @@
"ecmaVersion": 2018,
"sourceType": "module"
},
"plugins": [
"react",
"@typescript-eslint"
],
"plugins": ["react", "@typescript-eslint"],
"rules": {
"prettier/prettier": "error",
"no-unused-vars": [
Expand All @@ -173,17 +170,9 @@
"no-var": "warn",
"react/prop-types": "off",
"react/jsx-key": "off",
"eqeqeq": [
"error",
"always"
],
"curly": [
"error",
"all"
],
"no-bitwise": [
"error"
]
"eqeqeq": ["error", "always"],
"curly": ["error", "all"],
"no-bitwise": ["error"]
},
"settings": {
"react": {
Expand All @@ -199,7 +188,8 @@
},
"globals": {
"__TEST_ONLY__": true,
"API_PREFIX": "http://localhost:8000/api/v1/"
"SERVER_URL": "http://localhost:8000",
"API_PREFIX": "/api/v1/"
},
"coverageThreshold": {
"global": {
Expand Down
4 changes: 4 additions & 0 deletions client/src/api/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
declare const SERVER_URL: string;
declare const API_PREFIX: string;

export const API_URL: string = SERVER_URL + API_PREFIX;
9 changes: 4 additions & 5 deletions client/src/api/auth.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import * as R from 'ramda';

declare const API_PREFIX: string;

import { Result, error, success, map, of } from '../result';
import { Project, DataSet, decodeProjects } from './project';
import { handleError } from './err';
import { API_URL } from './api';

const USER_ROLES = ['guest', 'user', 'admin'] as const;
export type UserRole = typeof USER_ROLES[number];
Expand Down Expand Up @@ -123,7 +122,7 @@ export async function requestAuthToken(
req: AuthTokenRequest
): Promise<Result<AuthTokenResponse, string>> {
try {
const response = await fetch(API_PREFIX + 'auth/authorize', {
const response = await fetch(API_URL + 'auth/authorize', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Expand All @@ -144,7 +143,7 @@ export async function requestGuestToken(): Promise<
Result<AuthTokenResponse, string>
> {
try {
const response = await fetch(API_PREFIX + 'user/new', {
const response = await fetch(API_URL + 'user/new', {
method: 'POST',
});
if (!response.ok) {
Expand Down Expand Up @@ -209,7 +208,7 @@ export async function requestAuthProviders(): Promise<
Result<Array<Provider>, string>
> {
try {
const response = await fetch(API_PREFIX + 'auth/loginurl');
const response = await fetch(API_URL + 'auth/loginurl');
if (!response.ok) {
return error(response.statusText);
}
Expand Down
16 changes: 12 additions & 4 deletions client/src/api/err.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
import { Result, error } from '../result';

export const handleError = <T>(
prefix: string,
prefix: string | undefined,
err: unknown
): Result<T, string> => {
const message = (msg: string): string => {
if (prefix) {
return `${prefix} ${msg}`;
} else {
return msg;
}
};

if (err === undefined) {
return error(prefix + ' undefined');
return error(message('undefined'));
}

if (
Expand All @@ -15,8 +23,8 @@ export const handleError = <T>(
typeof (err as { statusText: unknown }).statusText === 'string'
) {
const msg = (err as { statusText: string }).statusText;
return error(`${prefix} ${msg}`);
return error(message(msg));
}

return error(`${prefix} ${JSON.stringify(err)}`);
return error(message(JSON.stringify(err)));
};
12 changes: 2 additions & 10 deletions client/src/api/fetch.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Result, error, success } from '../result';
import { handleError } from './err';

export async function fetchJson<T>(url: string): Promise<Result<T, string>> {
try {
Expand All @@ -9,15 +10,6 @@ export async function fetchJson<T>(url: string): Promise<Result<T, string>> {
const data: T = await response.json();
return success(data);
} catch (err: unknown) {
if (typeof err === 'object') {
if (
err !== null &&
'statusText' in err &&
typeof (err as { statusText: unknown }).statusText === 'string'
) {
return error((err as { statusText: string }).statusText);
}
}
return error(`Unknown error: ${JSON.stringify(err)}`);
return handleError('', err);
}
}
5 changes: 2 additions & 3 deletions client/src/api/legacy.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
declare const API_PREFIX: string;

import { Result, error, success } from '../result';
import { API_URL } from './api';

export type LegacySession = {
uuid: string;
Expand Down Expand Up @@ -30,7 +29,7 @@ export async function requestDecodePermalink(
sessiondata: string
): Promise<Result<LegacySession, string>> {
try {
const response = await fetch(API_PREFIX + 'legacy/permalink', {
const response = await fetch(API_URL + 'legacy/permalink', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Expand Down
7 changes: 3 additions & 4 deletions client/src/api/project.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import * as R from 'ramda';

declare const API_PREFIX: string;

import { Result, of, success, error } from '../result';
import { API_URL } from './api';

export type DataSet = {
id: number;
Expand Down Expand Up @@ -143,7 +142,7 @@ export async function myProjects(
token: string
): Promise<Result<[Array<Project>, Array<DataSet>], string>> {
try {
const response = await fetch(API_PREFIX + 'user/', {
const response = await fetch(API_URL + 'user/', {
headers: {
Accept: 'application/json',
Authorization: `Bearer ${token}`,
Expand All @@ -166,7 +165,7 @@ export async function makeProject(
name: string
): Promise<Result<Project, string>> {
try {
const url = new URL(API_PREFIX + 'project/new');
const url = new URL(API_URL + 'project/new');
url.search = new URLSearchParams({ name }).toString();
const response = await fetch(url.toString(), {
method: 'POST',
Expand Down
13 changes: 1 addition & 12 deletions client/src/components/AppHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,6 @@ export const AppHeader: React.FC<{}> = () => {
const { pathname } = useLocation();
const loom = '*';

// TODO: Hacky implementation. To be refactored/reviewed properly
const countAnnotations = (metadata) => {
let count = 0;
for (const clustering of metadata['cellMetaData']['clusterings']) {
for (const cluster of clustering['clusters']) {
count += cluster['cell_type_annotation'].length;
}
}
return count;
};

const metadata =
loom !== undefined ? LegacyAPI.getLoomMetadata(loom) : null;

Expand All @@ -46,7 +35,7 @@ export const AppHeader: React.FC<{}> = () => {
icon: false,
},
{
display: metadata && countAnnotations(metadata) > 0 ? true : false,
display: metadata ? true : false,
path: '/annotations',
title: 'All Annotations',
icon: false,
Expand Down
3 changes: 2 additions & 1 deletion client/src/redux/sagas/scope/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import * as A from '../../actions';

import * as AuthSelectors from '../../../components/Auth/selectors';

declare const SERVER_URL: string;
declare const API_PREFIX: string;

export function* createNewProject(action: T.NewProjectAction) {
Expand Down Expand Up @@ -75,7 +76,7 @@ export function* uploadFile(endpoint: string, project: string, file: File) {
}

export function* uploadRequest(action: T.UploadRequest) {
const url = new URL(API_PREFIX + 'project/dataset');
const url = new URL(SERVER_URL + API_PREFIX + 'project/dataset');
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could this not use the API_URL from api.ts?

url.search = new URLSearchParams({
name: action.payload.name,
project: action.payload.project,
Expand Down