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

[ENG-5155] Pretend check addon auth credentials in mirage #2172

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 @@ -10,3 +10,7 @@
.repo-select {
width: 250px;
}

.connect-error {
color: $brand-danger;
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@
</label>
{{field.postText}}
{{/each}}
{{#if @manager.connectAccountError}}
<p local-class='connect-error'>
{{t 'addons.accountCreate.error'}}
</p>
{{/if}}
<Button
data-test-addon-connect-account-button
data-analytics-name='Connect Account'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ export default class AddonsServiceManagerComponent extends Component<Args> {
secretKey: '',
repo: '',
};
@tracked connectAccountError = false;

@action
filterByAddonType(type: FilterTypes) {
Expand Down Expand Up @@ -161,6 +162,7 @@ export default class AddonsServiceManagerComponent extends Component<Args> {
this.clearCredentials();
this.pageMode = PageMode.CONFIGURE;
} catch (e) {
this.connectAccountError = true;
const errorMessage = this.intl.t('addons.accountCreate.error');
captureException(e, { errorMessage });
this.toast.error(getApiErrorMessage(e), errorMessage);
Expand Down Expand Up @@ -192,6 +194,7 @@ export default class AddonsServiceManagerComponent extends Component<Args> {

@action
clearCredentials() {
this.connectAccountError = false;
this.credentialsObject = {
url: '',
username: '',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
chooseExistingAccount=this.chooseExistingAccount
createNewAccount=this.createNewAccount
connectAccount=this.connectAccount
connectAccountError=this.connectAccountError
credentialsObject=this.credentialsObject
onCredentialsInput=this.onCredentialsInput
confirmAccountSetup=this.confirmAccountSetup
Expand Down
3 changes: 3 additions & 0 deletions mirage/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -547,8 +547,11 @@ export default function(this: Server) {
this.get('/resource-references/:nodeGuid/configured-computing-addons',
addons.resourceConfiguredComputingAddonList);
this.resource('authorized-storage-accounts', { except: ['index'] });
this.post('authorized-storage-accounts', addons.createAuthorizedStorageAccount);
this.resource('authorized-citation-accounts', { except: ['index'] });
this.post('authorized-citation-accounts', addons.createAuthorizedCitationAccount);
this.resource('authorized-computing-accounts', { except: ['index'] });
this.post('authorized-computing-accounts', addons.createAuthorizedComputingAccount);
this.resource('configured-storage-addons', { only: ['show', 'update', 'delete'] });
this.resource('configured-citation-addons', { only: ['show', 'update', 'delete'] });
this.resource('configured-computing-addons', { only: ['show', 'update', 'delete'] });
Expand Down
98 changes: 97 additions & 1 deletion mirage/views/addons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,30 @@ import { HandlerContext, ModelInstance, NormalizedRequestAttrs, Request, Respons

import AuthorizedCitationAccountModel from 'ember-osf-web/models/authorized-citation-account';
import AuthorizedComputingAccountModel from 'ember-osf-web/models/authorized-computing-account';
import AuthorizedStorageAccountModel from 'ember-osf-web/models/authorized-storage-account';
import AuthorizedStorageAccountModel, { AddonCredentialFields } from 'ember-osf-web/models/authorized-storage-account';
import ExternalStorageServiceModel, { CredentialsFormat } from 'ember-osf-web/models/external-storage-service';
import ExternalCitationServiceModel from 'ember-osf-web/models/external-citation-service';
import ExternalComputingServiceModel from 'ember-osf-web/models/external-computing-service';
import FileProviderModel from 'ember-osf-web/models/file-provider';

import { MirageConfiguredComputingAddon } from '../serializers/configured-computing-addon';
import { MirageConfiguredCitationAddon } from '../serializers/configured-citation-addon';
import { MirageConfiguredStorageAddon } from '../serializers/configured-storage-addon';
import { filter, process } from './utils';

interface MirageAuthorizedStorageAccount extends AuthorizedStorageAccountModel {
configuringUserId: string;
storageProviderId: string;
}
interface MirageAuthorizedCitationAccount extends AuthorizedCitationAccountModel {
configuringUserId: string;
citationServiceId: string;
}
interface MirageAuthorizedComputingAccount extends AuthorizedComputingAccountModel {
configuringUserId: string;
computingServiceId: string;
}

// This is the handler for the unofficial node/addons endpoint
// It is only being used by the file-action-menu component to determine if a node has the BoA addon enabled
// It is not being used by the official OSF API
Expand Down Expand Up @@ -204,3 +220,83 @@ export function createConfiguredComputingAddon(this: HandlerContext, schema: Sch

return configuredComputingAddon;
}

export async function createAuthorizedStorageAccount(this: HandlerContext, schema: Schema) {
const attrs = this.normalizedRequestAttrs(
'authorized-storage-account',
) as NormalizedRequestAttrs<MirageAuthorizedStorageAccount>;
const externalService = schema.externalStorageServices
.find(attrs.storageProviderId) as ModelInstance<ExternalStorageServiceModel>;
try {
fakeCheckCredentials(attrs.credentials!, externalService.credentialsFormat);
} catch (e) {
return new Response(403, {}, {
errors: [{ detail: e.message }],
});
}
attrs.credentials = undefined;
return schema.authorizedStorageAccounts.create(attrs);
}

export function createAuthorizedCitationAccount(this: HandlerContext, schema: Schema) {
const attrs = this.normalizedRequestAttrs(
'authorized-citation-account',
) as NormalizedRequestAttrs<MirageAuthorizedCitationAccount>;
const externalService = schema.externalCitationServices
.find(attrs.citationServiceId) as ModelInstance<ExternalCitationServiceModel>;
try {
fakeCheckCredentials(attrs.credentials!, externalService.credentialsFormat);
} catch (e) {
return new Response(403, {}, {
errors: [{ detail: e.message }],
});
}
attrs.credentials = undefined;
return schema.authorizedCitationAccounts.create(attrs);
}

export function createAuthorizedComputingAccount(this: HandlerContext, schema: Schema) {
const attrs = this.normalizedRequestAttrs(
'authorized-computing-account',
) as NormalizedRequestAttrs<MirageAuthorizedComputingAccount>;
const externalService = schema.externalComputingServices
.find(attrs.computingServiceId) as ModelInstance<ExternalComputingServiceModel>;
try {
fakeCheckCredentials(attrs.credentials!, externalService.credentialsFormat);
} catch (e) {
return new Response(403, {}, {
errors: [{ detail: e.message }],
});
}
attrs.credentials = undefined;
return schema.authorizedComputingAccounts.create(attrs);
}

function fakeCheckCredentials(credentials: AddonCredentialFields, credentialsFormat: CredentialsFormat) {
switch (credentialsFormat) {
case CredentialsFormat.REPO_TOKEN:
if (!credentials.token || !credentials.repo) {
throw new Error('Token and repo is required');
}
break;
case CredentialsFormat.ACCESS_SECRET_KEYS:
if (!credentials.accessKey || !credentials.secretKey) {
throw new Error('Access key and secret key is required');
}
break;
case CredentialsFormat.USERNAME_PASSWORD:
if (!credentials.username || !credentials.password) {
throw new Error('Username and password are required');
}
break;
case CredentialsFormat.URL_USERNAME_PASSWORD:
if (!credentials.url || !credentials.username || !credentials.password) {
throw new Error('URL, username, and password are required');
}
if (credentials.url.indexOf('http') < 0) {
throw new Error('Invalid URL');
}
break;
default: // no-op on OAuth or OAuth2
}
}
Loading