Removed defunct Ghost OAuth code (#848)
refs https://github.com/TryGhost/Ghost/issues/8958 - Ghost OAuth isn't coming back, time for the code to disappear and simply all the things - fixes the `Usage of router is deprecated` notices that flood the console/test logs when testing
This commit is contained in:
parent
7f03fa62c2
commit
6cb04e4c41
|
@ -1,40 +0,0 @@
|
|||
import Oauth2Authenticator from './oauth2';
|
||||
import RSVP from 'rsvp';
|
||||
import {assign} from '@ember/polyfills';
|
||||
import {isEmpty} from '@ember/utils';
|
||||
import {run} from '@ember/runloop';
|
||||
import {makeArray as wrap} from '@ember/array';
|
||||
|
||||
export default Oauth2Authenticator.extend({
|
||||
// TODO: all this is doing is changing the `data` structure, we should
|
||||
// probably create our own token auth, maybe look at
|
||||
// https://github.com/jpadilla/ember-simple-auth-token
|
||||
authenticate(identification, password, scope = []) {
|
||||
return new RSVP.Promise((resolve, reject) => {
|
||||
// const data = { 'grant_type': 'password', username: identification, password };
|
||||
let data = identification;
|
||||
let serverTokenEndpoint = this.get('serverTokenEndpoint');
|
||||
let scopesString = wrap(scope).join(' ');
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
data.grant_type = 'authorization_code';
|
||||
|
||||
if (!isEmpty(scopesString)) {
|
||||
data.scope = scopesString;
|
||||
}
|
||||
|
||||
this.makeRequest(serverTokenEndpoint, data).then((response) => {
|
||||
run(() => {
|
||||
let expiresAt = this._absolutizeExpirationTime(response.expires_in);
|
||||
this._scheduleAccessTokenRefresh(response.expires_in, expiresAt, response.refresh_token);
|
||||
if (!isEmpty(expiresAt)) {
|
||||
response = assign(response, {'expires_at': expiresAt});
|
||||
}
|
||||
resolve(response);
|
||||
});
|
||||
}, (error) => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
|
@ -15,7 +15,6 @@ export default ModalComponent.extend(ValidationEngine, {
|
|||
config: injectService(),
|
||||
notifications: injectService(),
|
||||
session: injectService(),
|
||||
torii: injectService(),
|
||||
|
||||
identification: computed('session.user.email', function () {
|
||||
return this.get('session.user.email');
|
||||
|
@ -69,38 +68,8 @@ export default ModalComponent.extend(ValidationEngine, {
|
|||
});
|
||||
},
|
||||
|
||||
_oauthConfirm() {
|
||||
// TODO: remove duplication between signin/signup/re-auth
|
||||
let authStrategy = 'authenticator:oauth2-ghost';
|
||||
|
||||
this.toggleProperty('submitting');
|
||||
this.set('authenticationError', '');
|
||||
|
||||
return this.get('torii')
|
||||
.open('ghost-oauth2', {type: 'signin'})
|
||||
.then((authentication) => {
|
||||
this.get('session').set('skipAuthSuccessHandler', true);
|
||||
|
||||
this.get('session').authenticate(authStrategy, authentication).finally(() => {
|
||||
this.get('session').set('skipAuthSuccessHandler', undefined);
|
||||
|
||||
this.toggleProperty('submitting');
|
||||
this.get('notifications').closeAlerts();
|
||||
this.send('closeModal');
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
this.toggleProperty('submitting');
|
||||
this.set('authenticationError', 'Authentication with Ghost.org denied or failed');
|
||||
});
|
||||
},
|
||||
|
||||
reauthenticate: task(function* () {
|
||||
if (this.get('config.ghostOAuth')) {
|
||||
return yield this._oauthConfirm();
|
||||
} else {
|
||||
return yield this._passwordConfirm();
|
||||
}
|
||||
return yield this._passwordConfirm();
|
||||
}).drop(),
|
||||
|
||||
actions: {
|
||||
|
|
|
@ -16,7 +16,6 @@ export default Controller.extend(ValidationEngine, {
|
|||
notifications: injectService(),
|
||||
session: injectService(),
|
||||
settings: injectService(),
|
||||
torii: injectService(),
|
||||
|
||||
// ValidationEngine settings
|
||||
validationType: 'setup',
|
||||
|
@ -30,33 +29,9 @@ export default Controller.extend(ValidationEngine, {
|
|||
password: null,
|
||||
|
||||
setup: task(function* () {
|
||||
if (this.get('config.ghostOAuth')) {
|
||||
return yield this._oauthSetup();
|
||||
} else {
|
||||
return yield this._passwordSetup();
|
||||
}
|
||||
return yield this._passwordSetup();
|
||||
}),
|
||||
|
||||
// TODO: remove duplication with controllers/signin
|
||||
authenticateWithGhostOrg: task(function* () {
|
||||
let authStrategy = 'authenticator:oauth2-ghost';
|
||||
|
||||
this.set('flowErrors', '');
|
||||
|
||||
try {
|
||||
let authentication = yield this.get('torii')
|
||||
.open('ghost-oauth2', {type: 'setup'});
|
||||
|
||||
yield this.get('authenticate').perform(authStrategy, [authentication]);
|
||||
|
||||
return true;
|
||||
|
||||
} catch (error) {
|
||||
this.set('flowErrors', 'Authentication with Ghost.org denied or failed');
|
||||
throw error;
|
||||
}
|
||||
}).drop(),
|
||||
|
||||
authenticate: task(function* (authStrategy, authentication) {
|
||||
// we don't want to redirect after sign-in during setup
|
||||
this.set('session.skipAuthSuccessHandler', true);
|
||||
|
@ -166,41 +141,6 @@ export default Controller.extend(ValidationEngine, {
|
|||
});
|
||||
},
|
||||
|
||||
// NOTE: for OAuth ghost is in the "setup completed" step as soon
|
||||
// as a user has been authenticated so we need to use the standard settings
|
||||
// update to set the blog title before redirecting
|
||||
_oauthSetup() {
|
||||
let blogTitle = this.get('blogTitle');
|
||||
let config = this.get('config');
|
||||
|
||||
this.get('hasValidated').addObjects(['blogTitle', 'session']);
|
||||
|
||||
return this.validate().then(() => {
|
||||
return this.get('settings').fetch()
|
||||
.then((settings) => {
|
||||
settings.set('title', blogTitle);
|
||||
|
||||
return settings.save()
|
||||
.then((settings) => {
|
||||
// update the config so that the blog title shown in
|
||||
// the nav bar is also updated
|
||||
config.set('blogTitle', settings.get('title'));
|
||||
|
||||
// this.blogCreated is used by step 3 to check if step 2
|
||||
// has been completed
|
||||
this.set('blogCreated', true);
|
||||
return this._afterAuthentication(settings);
|
||||
})
|
||||
.catch((error) => {
|
||||
this._handleSaveError(error);
|
||||
});
|
||||
})
|
||||
.finally(() => {
|
||||
this.set('session.skipAuthSuccessHandler', undefined);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
_handleSaveError(resp) {
|
||||
if (isInvalidError(resp)) {
|
||||
this.set('flowErrors', resp.errors[0].message);
|
||||
|
|
|
@ -20,7 +20,6 @@ export default Controller.extend(ValidationEngine, {
|
|||
notifications: injectService(),
|
||||
session: injectService(),
|
||||
settings: injectService(),
|
||||
torii: injectService(),
|
||||
|
||||
flowErrors: '',
|
||||
|
||||
|
@ -92,24 +91,6 @@ export default Controller.extend(ValidationEngine, {
|
|||
}
|
||||
}).drop(),
|
||||
|
||||
// TODO: remove duplication with controllers/setup/two
|
||||
authenticateWithGhostOrg: task(function* () {
|
||||
let authStrategy = 'authenticator:oauth2-ghost';
|
||||
|
||||
this.set('flowErrors', '');
|
||||
|
||||
try {
|
||||
let authentication = yield this.get('torii')
|
||||
.open('ghost-oauth2', {type: 'signin'});
|
||||
|
||||
return yield this.get('authenticate').perform(authStrategy, [authentication]);
|
||||
|
||||
} catch (error) {
|
||||
this.set('flowErrors', 'Authentication with Ghost.org denied or failed');
|
||||
throw error;
|
||||
}
|
||||
}).drop(),
|
||||
|
||||
forgotten: task(function* () {
|
||||
let email = this.get('model.identification');
|
||||
let forgottenUrl = this.get('ghostPaths.url').api('authentication', 'passwordreset');
|
||||
|
|
|
@ -5,7 +5,6 @@ import {
|
|||
VersionMismatchError,
|
||||
isVersionMismatchError
|
||||
} from 'ghost-admin/services/ajax';
|
||||
import {assign} from '@ember/polyfills';
|
||||
import {inject as injectService} from '@ember/service';
|
||||
import {isArray as isEmberArray} from '@ember/array';
|
||||
import {task} from 'ember-concurrency';
|
||||
|
@ -17,7 +16,6 @@ export default Controller.extend(ValidationEngine, {
|
|||
notifications: injectService(),
|
||||
session: injectService(),
|
||||
settings: injectService(),
|
||||
torii: injectService(),
|
||||
|
||||
// ValidationEngine settings
|
||||
validationType: 'signup',
|
||||
|
@ -70,27 +68,6 @@ export default Controller.extend(ValidationEngine, {
|
|||
}
|
||||
}).drop(),
|
||||
|
||||
authenticateWithGhostOrg: task(function* () {
|
||||
let authStrategy = 'authenticator:oauth2-ghost';
|
||||
let inviteToken = this.get('model.token');
|
||||
let email = this.get('model.email');
|
||||
|
||||
this.set('flowErrors', '');
|
||||
|
||||
try {
|
||||
let authentication = yield this.get('torii')
|
||||
.open('ghost-oauth2', {email, type: 'invite'});
|
||||
|
||||
authentication = assign(authentication, {inviteToken});
|
||||
|
||||
return yield this.get('authenticate').perform(authStrategy, [authentication]);
|
||||
|
||||
} catch (error) {
|
||||
this.set('flowErrors', 'Authentication with Ghost.org denied or failed');
|
||||
throw error;
|
||||
}
|
||||
}).drop(),
|
||||
|
||||
signup: task(function* () {
|
||||
let setupProperties = ['name', 'email', 'password', 'token'];
|
||||
let notifications = this.get('notifications');
|
||||
|
|
|
@ -36,10 +36,12 @@ export default Controller.extend({
|
|||
email: readOnly('model.email'),
|
||||
slugValue: boundOneWay('model.slug'),
|
||||
|
||||
isNotOwnersProfile: not('user.isOwner'),
|
||||
isAdminUserOnOwnerProfile: and('currentUser.isAdmin', 'user.isOwner'),
|
||||
canAssignRoles: or('currentUser.isAdmin', 'currentUser.isOwner'),
|
||||
canChangeEmail: not('isAdminUserOnOwnerProfile'),
|
||||
canChangePassword: not('isAdminUserOnOwnerProfile'),
|
||||
canMakeOwner: and('currentUser.isOwner', 'isNotOwnProfile', 'user.isAdmin'),
|
||||
isAdminUserOnOwnerProfile: and('currentUser.isAdmin', 'user.isOwner'),
|
||||
isNotOwnersProfile: not('user.isOwner'),
|
||||
rolesDropdownIsVisible: and('isNotOwnProfile', 'canAssignRoles', 'isNotOwnersProfile'),
|
||||
userActionsAreVisible: or('deleteUserActionIsVisible', 'canMakeOwner'),
|
||||
|
||||
|
@ -47,14 +49,6 @@ export default Controller.extend({
|
|||
return this.get('user.id') === this.get('currentUser.id');
|
||||
}),
|
||||
isNotOwnProfile: not('isOwnProfile'),
|
||||
showMyGhostLink: and('config.ghostOAuth', 'isOwnProfile'),
|
||||
|
||||
canChangeEmail: computed('config.ghostOAuth', 'isAdminUserOnOwnerProfile', function () {
|
||||
let ghostOAuth = this.get('config.ghostOAuth');
|
||||
let isAdminUserOnOwnerProfile = this.get('isAdminUserOnOwnerProfile');
|
||||
|
||||
return !ghostOAuth && !isAdminUserOnOwnerProfile;
|
||||
}),
|
||||
|
||||
deleteUserActionIsVisible: computed('currentUser', 'canAssignRoles', 'user', function () {
|
||||
if ((this.get('canAssignRoles') && this.get('isNotOwnProfile') && !this.get('user.isOwner'))
|
||||
|
@ -64,10 +58,6 @@ export default Controller.extend({
|
|||
}
|
||||
}),
|
||||
|
||||
canChangePassword: computed('config.ghostOAuth', 'isAdminUserOnOwnerProfile', function () {
|
||||
return !this.get('config.ghostOAuth') && !this.get('isAdminUserOnOwnerProfile');
|
||||
}),
|
||||
|
||||
// duplicated in gh-user-active -- find a better home and consolidate?
|
||||
userDefault: computed('ghostPaths', function () {
|
||||
return `${this.get('ghostPaths.assetRoot')}/img/user-image.png`;
|
||||
|
|
|
@ -17,11 +17,8 @@ export default Route.extend(styleBody, {
|
|||
beforeModel() {
|
||||
this._super(...arguments);
|
||||
|
||||
// with OAuth auth users are authenticated on step 2 so we
|
||||
// can't use the session.isAuthenticated shortcut
|
||||
if (!this.get('config.ghostOAuth') && this.get('session.isAuthenticated')) {
|
||||
this.transitionTo('posts');
|
||||
return;
|
||||
if (this.get('session.isAuthenticated')) {
|
||||
return this.transitionTo('posts');
|
||||
}
|
||||
|
||||
let authUrl = this.get('ghostPaths.url').api('authentication', 'setup');
|
||||
|
|
|
@ -3,7 +3,6 @@ import Service from '@ember/service';
|
|||
import {assign} from '@ember/polyfills';
|
||||
import {computed} from '@ember/object';
|
||||
import {inject as injectService} from '@ember/service';
|
||||
import {isBlank} from '@ember/utils';
|
||||
|
||||
// ember-cli-shims doesn't export _ProxyMixin
|
||||
const {_ProxyMixin} = Ember;
|
||||
|
@ -46,10 +45,6 @@ export default Service.extend(_ProxyMixin, {
|
|||
});
|
||||
}),
|
||||
|
||||
ghostOAuth: computed('ghostAuthId', function () {
|
||||
return !isBlank(this.get('ghostAuthId'));
|
||||
}),
|
||||
|
||||
blogDomain: computed('blogUrl', function () {
|
||||
let blogUrl = this.get('blogUrl');
|
||||
let blogDomain = blogUrl
|
||||
|
|
|
@ -5,18 +5,14 @@
|
|||
|
||||
<div class="modal-body {{if authenticationError 'error'}}">
|
||||
|
||||
{{#if config.ghostOAuth}}
|
||||
{{gh-task-button "Sign in with Ghost" task=reauthenticate class="login gh-btn gh-btn-blue gh-btn-block gh-btn-icon" tabindex="3" autoWidth="false"}}
|
||||
{{else}}
|
||||
<form id="login" class="login-form" method="post" novalidate="novalidate" {{action "confirm" on="submit"}}>
|
||||
{{#gh-validation-status-container class="password-wrap" errors=errors property="password" hasValidated=hasValidated}}
|
||||
{{gh-input password class="password" type="password" placeholder="Password" name="password" update=(action (mut password))}}
|
||||
{{/gh-validation-status-container}}
|
||||
<div>
|
||||
{{gh-task-button "Log in" task=reauthenticate class="gh-btn gh-btn-blue gh-btn-icon" type="submit"}}
|
||||
</div>
|
||||
</form>
|
||||
{{/if}}
|
||||
<form id="login" class="login-form" method="post" novalidate="novalidate" {{action "confirm" on="submit"}}>
|
||||
{{#gh-validation-status-container class="password-wrap" errors=errors property="password" hasValidated=hasValidated}}
|
||||
{{gh-input password class="password" type="password" placeholder="Password" name="password" update=(action (mut password))}}
|
||||
{{/gh-validation-status-container}}
|
||||
<div>
|
||||
{{gh-task-button "Log in" task=reauthenticate class="gh-btn gh-btn-blue gh-btn-icon" type="submit"}}
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{{#if authenticationError}}
|
||||
<p class="response">{{authenticationError}}</p>
|
||||
|
|
|
@ -1,55 +1,87 @@
|
|||
{{#if config.ghostOAuth}}
|
||||
<header>
|
||||
<h1>Setup your blog</h1>
|
||||
</header>
|
||||
<header>
|
||||
<h1>Create your account</h1>
|
||||
</header>
|
||||
|
||||
<form id="setup" class="gh-flow-create" {{action "setup" on="submit"}}>
|
||||
{{#gh-form-group errors=errors hasValidated=hasValidated property="session"}}
|
||||
{{#gh-task-button
|
||||
task=authenticateWithGhostOrg
|
||||
class="login gh-btn gh-btn-blue gh-btn-block gh-btn-icon"
|
||||
type="button"
|
||||
successClass=""
|
||||
as |task|
|
||||
}}
|
||||
{{#if task.isRunning}}
|
||||
<span>{{inline-svg "spinner" class="gh-icon-spinner gh-btn-icon-no-margin"}}</span>
|
||||
{{else}}
|
||||
{{#if session.isAuthenticated}}
|
||||
<span>Connected: {{session.user.email}}</span>
|
||||
{{else}}
|
||||
<span>Sign in with Ghost</span>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{/gh-task-button}}
|
||||
{{gh-error-message errors=errors property="session"}}
|
||||
{{/gh-form-group}}
|
||||
<form id="setup" class="gh-flow-create">
|
||||
{{!-- Horrible hack to prevent Chrome from incorrectly auto-filling inputs --}}
|
||||
<input style="display:none;" type="text" name="username"/>
|
||||
<input style="display:none;" type="password" name="password"/>
|
||||
|
||||
{{#gh-form-group errors=errors hasValidated=hasValidated property="blogTitle"}}
|
||||
<label for="blog-title">Blog title</label>
|
||||
<span class="gh-input-icon gh-icon-content">
|
||||
{{inline-svg "content"}}
|
||||
{{gh-input blogTitle
|
||||
tabindex="4"
|
||||
type="text"
|
||||
name="blog-title"
|
||||
placeholder="Eg. The Daily Awesome"
|
||||
autocorrect="off"
|
||||
focusOut=(action "preValidate" "blogTitle")
|
||||
update=(action (mut blogTitle))
|
||||
onenter=(action "setup")}}
|
||||
</span>
|
||||
{{gh-error-message errors=errors property="blogTitle"}}
|
||||
{{/gh-form-group}}
|
||||
</form>
|
||||
{{gh-profile-image email=email setImage=(action "setImage")}}
|
||||
|
||||
{{#gh-form-group errors=errors hasValidated=hasValidated property="blogTitle"}}
|
||||
<label for="blog-title">Blog title</label>
|
||||
<span class="gh-input-icon gh-icon-content">
|
||||
{{inline-svg "content"}}
|
||||
{{gh-trim-focus-input blogTitle
|
||||
tabindex="1"
|
||||
type="text"
|
||||
name="blog-title"
|
||||
placeholder="Eg. The Daily Awesome"
|
||||
autocorrect="off"
|
||||
focusOut=(action "preValidate" "blogTitle")
|
||||
update=(action (mut blogTitle))
|
||||
data-test-blog-title-input=true}}
|
||||
</span>
|
||||
{{gh-error-message errors=errors property="blogTitle"}}
|
||||
{{/gh-form-group}}
|
||||
|
||||
{{#gh-form-group errors=errors hasValidated=hasValidated property="name"}}
|
||||
<label for="name">Full name</label>
|
||||
<span class="gh-input-icon gh-icon-user">
|
||||
{{inline-svg "user-circle"}}
|
||||
{{gh-input name
|
||||
tabindex="2"
|
||||
type="text"
|
||||
name="name"
|
||||
placeholder="Eg. John H. Watson"
|
||||
autocorrect="off"
|
||||
focusOut=(action "preValidate" "name")
|
||||
update=(action (mut name))
|
||||
data-test-name-input=true}}
|
||||
</span>
|
||||
{{gh-error-message errors=errors property="name"}}
|
||||
{{/gh-form-group}}
|
||||
|
||||
{{#gh-form-group errors=errors hasValidated=hasValidated property="email"}}
|
||||
<label for="email">Email address</label>
|
||||
<span class="gh-input-icon gh-icon-mail">
|
||||
{{inline-svg "email"}}
|
||||
{{gh-input email
|
||||
tabindex="3"
|
||||
type="email"
|
||||
name="email"
|
||||
placeholder="Eg. john@example.com"
|
||||
autocorrect="off"
|
||||
focusOut=(action "preValidate" "email")
|
||||
update=(action (mut email))
|
||||
data-test-email-input=true}}
|
||||
</span>
|
||||
{{gh-error-message errors=errors property="email"}}
|
||||
{{/gh-form-group}}
|
||||
|
||||
{{#gh-form-group errors=errors hasValidated=hasValidated property="password"}}
|
||||
<label for="password">Password</label>
|
||||
<span class="gh-input-icon gh-icon-lock">
|
||||
{{inline-svg "lock"}}
|
||||
{{gh-input password
|
||||
tabindex="4"
|
||||
type="password"
|
||||
name="password"
|
||||
placeholder="At least 8 characters"
|
||||
autocorrect="off"
|
||||
focusOut=(action "preValidate" "password")
|
||||
update=(action (mut password))
|
||||
data-test-password-input=true}}
|
||||
</span>
|
||||
{{gh-error-message errors=errors property="password"}}
|
||||
{{/gh-form-group}}
|
||||
|
||||
{{#gh-task-button
|
||||
task=setup
|
||||
type="submit"
|
||||
tabindex="5"
|
||||
class="gh-btn gh-btn-green gh-btn-lg gh-btn-block gh-btn-icon"
|
||||
disabled=submitDisabled
|
||||
data-test-submit-button=true
|
||||
as |task|
|
||||
}}
|
||||
{{#if task.isRunning}}
|
||||
|
@ -58,101 +90,6 @@
|
|||
<span>Last step: Invite your team {{inline-svg "arrow-right-small" class="gh-btn-icon-right"}}</span>
|
||||
{{/if}}
|
||||
{{/gh-task-button}}
|
||||
{{else}}
|
||||
|
||||
<header>
|
||||
<h1>Create your account</h1>
|
||||
</header>
|
||||
|
||||
<form id="setup" class="gh-flow-create">
|
||||
{{!-- Horrible hack to prevent Chrome from incorrectly auto-filling inputs --}}
|
||||
<input style="display:none;" type="text" name="username"/>
|
||||
<input style="display:none;" type="password" name="password"/>
|
||||
|
||||
{{gh-profile-image email=email setImage=(action "setImage")}}
|
||||
|
||||
{{#gh-form-group errors=errors hasValidated=hasValidated property="blogTitle"}}
|
||||
<label for="blog-title">Blog title</label>
|
||||
<span class="gh-input-icon gh-icon-content">
|
||||
{{inline-svg "content"}}
|
||||
{{gh-trim-focus-input blogTitle
|
||||
tabindex="1"
|
||||
type="text"
|
||||
name="blog-title"
|
||||
placeholder="Eg. The Daily Awesome"
|
||||
autocorrect="off"
|
||||
focusOut=(action "preValidate" "blogTitle")
|
||||
update=(action (mut blogTitle))
|
||||
data-test-blog-title-input=true}}
|
||||
</span>
|
||||
{{gh-error-message errors=errors property="blogTitle"}}
|
||||
{{/gh-form-group}}
|
||||
|
||||
{{#gh-form-group errors=errors hasValidated=hasValidated property="name"}}
|
||||
<label for="name">Full name</label>
|
||||
<span class="gh-input-icon gh-icon-user">
|
||||
{{inline-svg "user-circle"}}
|
||||
{{gh-input name
|
||||
tabindex="2"
|
||||
type="text"
|
||||
name="name"
|
||||
placeholder="Eg. John H. Watson"
|
||||
autocorrect="off"
|
||||
focusOut=(action "preValidate" "name")
|
||||
update=(action (mut name))
|
||||
data-test-name-input=true}}
|
||||
</span>
|
||||
{{gh-error-message errors=errors property="name"}}
|
||||
{{/gh-form-group}}
|
||||
|
||||
{{#gh-form-group errors=errors hasValidated=hasValidated property="email"}}
|
||||
<label for="email">Email address</label>
|
||||
<span class="gh-input-icon gh-icon-mail">
|
||||
{{inline-svg "email"}}
|
||||
{{gh-input email
|
||||
tabindex="3"
|
||||
type="email"
|
||||
name="email"
|
||||
placeholder="Eg. john@example.com"
|
||||
autocorrect="off"
|
||||
focusOut=(action "preValidate" "email")
|
||||
update=(action (mut email))
|
||||
data-test-email-input=true}}
|
||||
</span>
|
||||
{{gh-error-message errors=errors property="email"}}
|
||||
{{/gh-form-group}}
|
||||
|
||||
{{#gh-form-group errors=errors hasValidated=hasValidated property="password"}}
|
||||
<label for="password">Password</label>
|
||||
<span class="gh-input-icon gh-icon-lock">
|
||||
{{inline-svg "lock"}}
|
||||
{{gh-input password
|
||||
tabindex="4"
|
||||
type="password"
|
||||
name="password"
|
||||
placeholder="At least 8 characters"
|
||||
autocorrect="off"
|
||||
focusOut=(action "preValidate" "password")
|
||||
update=(action (mut password))
|
||||
data-test-password-input=true}}
|
||||
</span>
|
||||
{{gh-error-message errors=errors property="password"}}
|
||||
{{/gh-form-group}}
|
||||
|
||||
{{#gh-task-button
|
||||
task=setup
|
||||
type="submit"
|
||||
tabindex="5"
|
||||
class="gh-btn gh-btn-green gh-btn-lg gh-btn-block gh-btn-icon"
|
||||
as |task|
|
||||
}}
|
||||
{{#if task.isRunning}}
|
||||
<span>{{inline-svg "spinner" class="gh-icon-spinner gh-btn-icon-no-margin"}}</span>
|
||||
{{else}}
|
||||
<span>Last step: Invite your team {{inline-svg "arrow-right-small" class="gh-btn-icon-right"}}</span>
|
||||
{{/if}}
|
||||
{{/gh-task-button}}
|
||||
</form>
|
||||
{{/if}}
|
||||
</form>
|
||||
|
||||
<p class="main-error">{{{flowErrors}}}</p>
|
||||
|
|
|
@ -1,66 +1,53 @@
|
|||
<div class="gh-flow">
|
||||
<div class="gh-flow-content-wrap">
|
||||
<section class="gh-flow-content">
|
||||
{{#if config.ghostOAuth}}
|
||||
<header>
|
||||
<h1>{{config.blogTitle}}</h1>
|
||||
</header>
|
||||
{{/if}}
|
||||
|
||||
<form id="login" method="post" class="gh-signin" novalidate="novalidate" {{action "authenticate" on="submit"}}>
|
||||
{{#if config.ghostOAuth}}
|
||||
{{gh-task-button "Sign in with Ghost"
|
||||
task=authenticateWithGhostOrg
|
||||
class="login gh-btn gh-btn-blue gh-btn-block gh-btn-icon"
|
||||
tabindex="3"}}
|
||||
{{else}}
|
||||
{{#gh-form-group errors=model.errors hasValidated=hasValidated property="identification"}}
|
||||
<span class="gh-input-icon gh-icon-mail">
|
||||
{{inline-svg "email"}}
|
||||
{{gh-trim-focus-input model.identification
|
||||
class="email"
|
||||
type="email"
|
||||
placeholder="Email Address"
|
||||
name="identification"
|
||||
autocapitalize="off"
|
||||
autocorrect="off"
|
||||
tabindex="1"
|
||||
focusOut=(action "validate" "identification")
|
||||
update=(action (mut model.identification))}}
|
||||
</span>
|
||||
{{/gh-form-group}}
|
||||
{{#gh-form-group errors=model.errors hasValidated=hasValidated property="password"}}
|
||||
<span class="gh-input-icon gh-icon-lock forgotten-wrap">
|
||||
{{inline-svg "lock"}}
|
||||
{{gh-input model.password
|
||||
class="password"
|
||||
type="password"
|
||||
placeholder="Password"
|
||||
name="password"
|
||||
tabindex="2"
|
||||
autocorrect="off"
|
||||
update=(action (mut model.password))}}
|
||||
{{#gh-form-group errors=model.errors hasValidated=hasValidated property="identification"}}
|
||||
<span class="gh-input-icon gh-icon-mail">
|
||||
{{inline-svg "email"}}
|
||||
{{gh-trim-focus-input model.identification
|
||||
class="email"
|
||||
type="email"
|
||||
placeholder="Email Address"
|
||||
name="identification"
|
||||
autocapitalize="off"
|
||||
autocorrect="off"
|
||||
tabindex="1"
|
||||
focusOut=(action "validate" "identification")
|
||||
update=(action (mut model.identification))}}
|
||||
</span>
|
||||
{{/gh-form-group}}
|
||||
{{#gh-form-group errors=model.errors hasValidated=hasValidated property="password"}}
|
||||
<span class="gh-input-icon gh-icon-lock forgotten-wrap">
|
||||
{{inline-svg "lock"}}
|
||||
{{gh-input model.password
|
||||
class="password"
|
||||
type="password"
|
||||
placeholder="Password"
|
||||
name="password"
|
||||
tabindex="2"
|
||||
autocorrect="off"
|
||||
update=(action (mut model.password))}}
|
||||
|
||||
{{#gh-task-button
|
||||
task=forgotten
|
||||
class="forgotten-link gh-btn gh-btn-link gh-btn-icon"
|
||||
tabindex="4"
|
||||
type="button"
|
||||
successClass=""
|
||||
failureClass=""
|
||||
as |task|
|
||||
}}
|
||||
<span>{{#if task.isRunning}}{{inline-svg "spinner" class="gh-spinner"}}{{else}}Forgot?{{/if}}</span>
|
||||
{{/gh-task-button}}
|
||||
</span>
|
||||
{{/gh-form-group}}
|
||||
{{#gh-task-button
|
||||
task=forgotten
|
||||
class="forgotten-link gh-btn gh-btn-link gh-btn-icon"
|
||||
tabindex="4"
|
||||
type="button"
|
||||
successClass=""
|
||||
failureClass=""
|
||||
as |task|
|
||||
}}
|
||||
<span>{{#if task.isRunning}}{{inline-svg "spinner" class="gh-spinner"}}{{else}}Forgot?{{/if}}</span>
|
||||
{{/gh-task-button}}
|
||||
</span>
|
||||
{{/gh-form-group}}
|
||||
|
||||
{{gh-task-button "Sign in"
|
||||
task=validateAndAuthenticate
|
||||
class="login gh-btn gh-btn-blue gh-btn-block gh-btn-icon"
|
||||
type="submit"
|
||||
tabindex="3"}}
|
||||
{{/if}}
|
||||
{{gh-task-button "Sign in"
|
||||
task=validateAndAuthenticate
|
||||
class="login gh-btn gh-btn-blue gh-btn-block gh-btn-icon"
|
||||
type="submit"
|
||||
tabindex="3"}}
|
||||
</form>
|
||||
|
||||
<p class="main-error">{{{if flowErrors flowErrors " "}}}</p>
|
||||
|
|
|
@ -2,89 +2,70 @@
|
|||
|
||||
<div class="gh-flow-content-wrap">
|
||||
<section class="gh-flow-content">
|
||||
{{#if config.ghostOAuth}}
|
||||
<header>
|
||||
<h1>{{config.blogTitle}}</h1>
|
||||
<p>
|
||||
{{!-- TODO: show invite creator's name/email --}}
|
||||
Accept your invite from <strong>{{model.invitedBy}}</strong>
|
||||
</p>
|
||||
</header>
|
||||
<header>
|
||||
<h1>Create your account</h1>
|
||||
</header>
|
||||
|
||||
<form id="signup" class="gh-signin" method="post" novalidate="novalidate">
|
||||
{{gh-task-button "Sign in with Ghost to accept"
|
||||
task=authenticateWithGhostOrg
|
||||
type="submit"
|
||||
class="login gh-btn gh-btn-blue gh-btn-block gh-btn-icon"
|
||||
tabindex="3"}}
|
||||
</form>
|
||||
<form id="signup" class="gh-flow-create" method="post" novalidate="novalidate">
|
||||
{{!-- Hack to stop Chrome's broken auto-fills --}}
|
||||
<input style="display:none;" type="text" name="fakeusernameremembered"/>
|
||||
<input style="display:none;" type="password" name="fakepasswordremembered"/>
|
||||
|
||||
{{else}}
|
||||
<header>
|
||||
<h1>Create your account</h1>
|
||||
</header>
|
||||
{{gh-profile-image email=model.email setImage=(action "setImage")}}
|
||||
|
||||
<form id="signup" class="gh-flow-create" method="post" novalidate="novalidate">
|
||||
{{!-- Hack to stop Chrome's broken auto-fills --}}
|
||||
<input style="display:none;" type="text" name="fakeusernameremembered"/>
|
||||
<input style="display:none;" type="password" name="fakepasswordremembered"/>
|
||||
{{#gh-form-group}}
|
||||
<label for="email-address">Email address</label>
|
||||
<span class="gh-input-icon gh-icon-mail">
|
||||
{{inline-svg "email"}}
|
||||
{{gh-input model.email
|
||||
type="email"
|
||||
name="email"
|
||||
placeholder="Eg. john@example.com"
|
||||
disabled="disabled"
|
||||
autocorrect="off"}}
|
||||
</span>
|
||||
{{/gh-form-group}}
|
||||
|
||||
{{gh-profile-image email=model.email setImage=(action "setImage")}}
|
||||
{{#gh-form-group errors=model.errors hasValidated=hasValidated property="name"}}
|
||||
<label for="full-name">Full name</label>
|
||||
<span class="gh-input-icon gh-icon-user">
|
||||
{{inline-svg "user-circle"}}
|
||||
{{gh-trim-focus-input model.name
|
||||
tabindex="1"
|
||||
type="text"
|
||||
name="name"
|
||||
placeholder="Eg. John H. Watson"
|
||||
autocorrect="off"
|
||||
onenter=(action "signup")
|
||||
focusOut=(action "validate" "name")
|
||||
update=(action (mut model.name))}}
|
||||
</span>
|
||||
{{gh-error-message errors=model.errors property="name"}}
|
||||
{{/gh-form-group}}
|
||||
|
||||
{{#gh-form-group}}
|
||||
<label for="email-address">Email address</label>
|
||||
<span class="gh-input-icon gh-icon-mail">
|
||||
{{inline-svg "email"}}
|
||||
{{gh-input model.email
|
||||
type="email"
|
||||
name="email"
|
||||
placeholder="Eg. john@example.com"
|
||||
disabled="disabled"
|
||||
autocorrect="off"}}
|
||||
</span>
|
||||
{{/gh-form-group}}
|
||||
{{#gh-form-group errors=model.errors hasValidated=hasValidated property="password"}}
|
||||
<label for="password">Password</label>
|
||||
<span class="gh-input-icon gh-icon-lock">
|
||||
{{inline-svg "lock"}}
|
||||
{{gh-input model.password
|
||||
tabindex="2"
|
||||
type="password"
|
||||
name="password"
|
||||
placeholder="At least 8 characters"
|
||||
onenter=(action "signup")
|
||||
autocorrect="off"
|
||||
focusOut=(action "validate" "password")
|
||||
update=(action (mut model.password))}}
|
||||
</span>
|
||||
{{gh-error-message errors=model.errors property="password"}}
|
||||
{{/gh-form-group}}
|
||||
</form>
|
||||
|
||||
{{#gh-form-group errors=model.errors hasValidated=hasValidated property="name"}}
|
||||
<label for="full-name">Full name</label>
|
||||
<span class="gh-input-icon gh-icon-user">
|
||||
{{inline-svg "user-circle"}}
|
||||
{{gh-trim-focus-input model.name
|
||||
tabindex="1"
|
||||
type="text"
|
||||
name="name"
|
||||
placeholder="Eg. John H. Watson"
|
||||
autocorrect="off"
|
||||
onenter=(action "signup")
|
||||
focusOut=(action "validate" "name")
|
||||
update=(action (mut model.name))}}
|
||||
</span>
|
||||
{{gh-error-message errors=model.errors property="name"}}
|
||||
{{/gh-form-group}}
|
||||
|
||||
{{#gh-form-group errors=model.errors hasValidated=hasValidated property="password"}}
|
||||
<label for="password">Password</label>
|
||||
<span class="gh-input-icon gh-icon-lock">
|
||||
{{inline-svg "lock"}}
|
||||
{{gh-input model.password
|
||||
tabindex="2"
|
||||
type="password"
|
||||
name="password"
|
||||
placeholder="At least 8 characters"
|
||||
onenter=(action "signup")
|
||||
autocorrect="off"
|
||||
focusOut=(action "validate" "password")
|
||||
update=(action (mut model.password))}}
|
||||
</span>
|
||||
{{gh-error-message errors=model.errors property="password"}}
|
||||
{{/gh-form-group}}
|
||||
</form>
|
||||
|
||||
{{gh-task-button "Create Account"
|
||||
runningText="Creating"
|
||||
task=signup
|
||||
class="gh-btn gh-btn-green gh-btn-lg gh-btn-block gh-btn-icon"
|
||||
tabindex="3"}}
|
||||
{{/if}}
|
||||
{{gh-task-button "Create Account"
|
||||
runningText="Creating"
|
||||
task=signup
|
||||
class="gh-btn gh-btn-green gh-btn-lg gh-btn-block gh-btn-icon"
|
||||
tabindex="3"}}
|
||||
|
||||
<p class="main-error">{{{if flowErrors flowErrors " "}}}</p>
|
||||
</section>
|
||||
|
|
|
@ -236,12 +236,5 @@
|
|||
</fieldset>
|
||||
</form> {{! change password form }}
|
||||
{{/if}}
|
||||
|
||||
{{!-- when using Ghost OAuth, users trying to change email/pass need to visit my.ghost.org --}}
|
||||
{{#if showMyGhostLink}}
|
||||
<div class="user-profile">
|
||||
<p class="gh-box gh-box-info">{{inline-svg "lock"}} To change your login details please visit <a href="https://my.ghost.org/account" target="_blank">https://my.ghost.org/account</a></p>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
import Oauth2 from 'torii/providers/oauth2-code';
|
||||
import ghostPaths from 'ghost-admin/utils/ghost-paths';
|
||||
import {computed} from '@ember/object';
|
||||
import {inject as injectService} from '@ember/service';
|
||||
|
||||
let GhostOauth2 = Oauth2.extend({
|
||||
|
||||
config: injectService(),
|
||||
|
||||
name: 'ghost-oauth2',
|
||||
baseUrl: computed(function () {
|
||||
return `${this.get('config.ghostAuthUrl')}/oauth2/authorize/`;
|
||||
}),
|
||||
apiKey: computed(function () {
|
||||
return this.get('config.ghostAuthId');
|
||||
}),
|
||||
|
||||
optionalUrlParams: ['type', 'email'],
|
||||
|
||||
responseParams: ['code'],
|
||||
|
||||
// we want to redirect to the ghost admin app by default
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
let adminPath = ghostPaths().adminRoot;
|
||||
let redirectUri = `${window.location.protocol}//${window.location.host}`;
|
||||
|
||||
redirectUri += adminPath;
|
||||
|
||||
this.set('redirectUri', redirectUri);
|
||||
},
|
||||
|
||||
open(options) {
|
||||
if (options.type) {
|
||||
this.set('type', options.type);
|
||||
}
|
||||
if (options.email) {
|
||||
this.set('email', options.email);
|
||||
}
|
||||
return this._super(...arguments);
|
||||
}
|
||||
});
|
||||
|
||||
export default GhostOauth2;
|
|
@ -4,23 +4,17 @@ export default BaseValidator.extend({
|
|||
properties: ['name', 'email', 'password'],
|
||||
|
||||
name(model) {
|
||||
let usingOAuth = model.get('config.ghostOAuth');
|
||||
let name = model.get('name');
|
||||
|
||||
if (!usingOAuth && !validator.isLength(name, 1)) {
|
||||
if (!validator.isLength(name, 1)) {
|
||||
model.get('errors').add('name', 'Please enter a name.');
|
||||
this.invalidate();
|
||||
}
|
||||
},
|
||||
|
||||
email(model) {
|
||||
let usingOAuth = model.get('config.ghostOAuth');
|
||||
let email = model.get('email');
|
||||
|
||||
if (usingOAuth) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (validator.empty(email)) {
|
||||
model.get('errors').add('email', 'Please enter an email.');
|
||||
this.invalidate();
|
||||
|
@ -31,10 +25,9 @@ export default BaseValidator.extend({
|
|||
},
|
||||
|
||||
password(model) {
|
||||
let usingOAuth = model.get('config.ghostOAuth');
|
||||
let password = model.get('password');
|
||||
|
||||
if (!usingOAuth && !validator.isLength(password, 8)) {
|
||||
if (!validator.isLength(password, 8)) {
|
||||
model.get('errors').add('password', 'Password must be at least 8 characters long');
|
||||
this.invalidate();
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import NewUserValidator from 'ghost-admin/validators/new-user';
|
||||
|
||||
export default NewUserValidator.create({
|
||||
properties: ['name', 'email', 'password', 'blogTitle', 'session'],
|
||||
properties: ['name', 'email', 'password', 'blogTitle'],
|
||||
|
||||
blogTitle(model) {
|
||||
let blogTitle = model.get('blogTitle');
|
||||
|
@ -10,16 +10,5 @@ export default NewUserValidator.create({
|
|||
model.get('errors').add('blogTitle', 'Please enter a blog title.');
|
||||
this.invalidate();
|
||||
}
|
||||
},
|
||||
|
||||
session(model) {
|
||||
let usingOAuth = model.get('config.ghostOAuth');
|
||||
let isAuthenticated = model.get('session.isAuthenticated');
|
||||
|
||||
if (usingOAuth && !isAuthenticated) {
|
||||
model.get('errors').add('session', 'Please connect a Ghost.org account before continuing');
|
||||
model.get('hasValidated').pushObject('session');
|
||||
this.invalidate();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -35,9 +35,7 @@ module.exports = function (environment) {
|
|||
|
||||
moment: {
|
||||
includeTimezone: 'all'
|
||||
},
|
||||
|
||||
torii: { }
|
||||
}
|
||||
};
|
||||
|
||||
if (environment === 'development') {
|
||||
|
|
|
@ -1,33 +1,16 @@
|
|||
/* eslint-disable camelcase */
|
||||
import $ from 'jquery';
|
||||
import {Response} from 'ember-cli-mirage';
|
||||
import {isBlank} from '@ember/utils';
|
||||
|
||||
export default function mockAuthentication(server) {
|
||||
server.post('/authentication/token', function ({roles, users}, {requestBody}) {
|
||||
let params = $.deparam(requestBody);
|
||||
|
||||
if (params.grant_type === 'authorization_code') {
|
||||
// OAuth sign-in
|
||||
if (!users.all().models.length) {
|
||||
let role = roles.findBy({name: 'Owner'});
|
||||
server.create('user', {email: 'oauthtest@example.com', roles: [role]});
|
||||
}
|
||||
|
||||
return {
|
||||
access_token: 'MirageAccessToken',
|
||||
expires_in: 172800,
|
||||
refresh_token: 'MirageRefreshToken'
|
||||
};
|
||||
} else {
|
||||
// Password sign-in
|
||||
return {
|
||||
access_token: 'MirageAccessToken',
|
||||
expires_in: 172800,
|
||||
refresh_token: 'MirageRefreshToken',
|
||||
token_type: 'Bearer'
|
||||
};
|
||||
}
|
||||
server.post('/authentication/token', function () {
|
||||
// Password sign-in
|
||||
return {
|
||||
access_token: 'MirageAccessToken',
|
||||
expires_in: 172800,
|
||||
refresh_token: 'MirageRefreshToken',
|
||||
token_type: 'Bearer'
|
||||
};
|
||||
});
|
||||
|
||||
server.post('/authentication/passwordreset', function (schema, request) {
|
||||
|
|
|
@ -4,9 +4,6 @@ export default [{
|
|||
clientId: 'ghost-admin',
|
||||
clientSecret: '1234ClientSecret',
|
||||
fileStorage: 'true',
|
||||
// these are valid attrs but we want password auth by default in tests
|
||||
// ghostAuthId: '1234GhostAuthId',
|
||||
// ghostAuthUrl: 'http://devauth.ghost.org:8080',
|
||||
internalTags: 'false',
|
||||
publicAPI: 'false',
|
||||
routeKeywords: {
|
||||
|
|
|
@ -119,7 +119,6 @@
|
|||
"simplemde": "https://github.com/kevinansfield/simplemde-markdown-editor.git#ghost",
|
||||
"testem": "1.18.4",
|
||||
"top-gh-contribs": "2.0.4",
|
||||
"torii": "0.8.2",
|
||||
"walk-sync": "0.3.2"
|
||||
},
|
||||
"ember-addon": {
|
||||
|
|
|
@ -5,12 +5,7 @@ import startApp from '../helpers/start-app';
|
|||
import {Response} from 'ember-cli-mirage';
|
||||
import {afterEach, beforeEach, describe, it} from 'mocha';
|
||||
import {authenticateSession, invalidateSession} from '../helpers/ember-simple-auth';
|
||||
import {enableGhostOAuth} from '../helpers/configuration';
|
||||
import {expect} from 'chai';
|
||||
import {
|
||||
stubFailedOAuthConnect,
|
||||
stubSuccessfulOAuthConnect
|
||||
} from '../helpers/oauth';
|
||||
|
||||
describe('Acceptance: Setup', function () {
|
||||
let application;
|
||||
|
@ -363,103 +358,4 @@ describe('Acceptance: Setup', function () {
|
|||
.to.equal(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('using Ghost OAuth', function () {
|
||||
beforeEach(function () {
|
||||
// mimic a new install
|
||||
server.get('/authentication/setup/', function () {
|
||||
return {
|
||||
setup: [
|
||||
{status: false}
|
||||
]
|
||||
};
|
||||
});
|
||||
|
||||
// ensure we have settings (to pass validation) and roles available
|
||||
enableGhostOAuth(server);
|
||||
server.loadFixtures('settings');
|
||||
server.loadFixtures('roles');
|
||||
});
|
||||
|
||||
it('displays the connect form and validates', async function () {
|
||||
invalidateSession(application);
|
||||
|
||||
await visit('/setup');
|
||||
|
||||
// it redirects to step one
|
||||
expect(
|
||||
currentURL(),
|
||||
'url after accessing /setup'
|
||||
).to.equal('/setup/one');
|
||||
|
||||
await click('.gh-btn-green');
|
||||
|
||||
expect(
|
||||
find('button.login').text().trim(),
|
||||
'login button text'
|
||||
).to.equal('Sign in with Ghost');
|
||||
|
||||
await click('.gh-btn-green');
|
||||
|
||||
let sessionFG = find('button.login').closest('.form-group');
|
||||
let titleFG = find('input[name="blog-title"]').closest('.form-group');
|
||||
|
||||
// session is validated
|
||||
expect(
|
||||
sessionFG.hasClass('error'),
|
||||
'session form group has error class'
|
||||
).to.be.true;
|
||||
|
||||
expect(
|
||||
sessionFG.find('.response').text().trim(),
|
||||
'session validation text'
|
||||
).to.match(/Please connect a Ghost\.org account/i);
|
||||
|
||||
// blog title is validated
|
||||
expect(
|
||||
titleFG.hasClass('error'),
|
||||
'title form group has error class'
|
||||
).to.be.true;
|
||||
|
||||
expect(
|
||||
titleFG.find('.response').text().trim(),
|
||||
'title validation text'
|
||||
).to.match(/please enter a blog title/i);
|
||||
|
||||
// TODO: test that connecting clears session validation error
|
||||
// TODO: test that typing in blog title clears validation error
|
||||
});
|
||||
|
||||
it('can connect and setup successfully', async function () {
|
||||
stubSuccessfulOAuthConnect(application);
|
||||
|
||||
await visit('/setup/two');
|
||||
await click('button.login');
|
||||
|
||||
expect(
|
||||
find('button.login').text().trim(),
|
||||
'login button text when connected'
|
||||
).to.equal('Connected: oauthtest@example.com');
|
||||
|
||||
await fillIn('input[name="blog-title"]', 'Ghostbusters');
|
||||
await click('[data-test-submit-button]');
|
||||
|
||||
expect(
|
||||
currentURL(),
|
||||
'url after submitting'
|
||||
).to.equal('/setup/three');
|
||||
});
|
||||
|
||||
it('handles failed connect', async function () {
|
||||
stubFailedOAuthConnect(application);
|
||||
|
||||
await visit('/setup/two');
|
||||
await click('button.login');
|
||||
|
||||
expect(
|
||||
find('.main-error').text().trim(),
|
||||
'error text after failed oauth connect'
|
||||
).to.match(/authentication with ghost\.org denied or failed/i);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -10,12 +10,7 @@ import {
|
|||
it
|
||||
} from 'mocha';
|
||||
import {authenticateSession, invalidateSession} from '../helpers/ember-simple-auth';
|
||||
import {enableGhostOAuth} from '../helpers/configuration';
|
||||
import {expect} from 'chai';
|
||||
import {
|
||||
stubFailedOAuthConnect,
|
||||
stubSuccessfulOAuthConnect
|
||||
} from '../helpers/oauth';
|
||||
|
||||
describe('Acceptance: Signin', function() {
|
||||
let application;
|
||||
|
@ -119,42 +114,4 @@ describe('Acceptance: Signin', function() {
|
|||
expect(currentURL(), 'currentURL').to.equal('/');
|
||||
});
|
||||
});
|
||||
|
||||
describe('using Ghost OAuth', function () {
|
||||
beforeEach(function () {
|
||||
enableGhostOAuth(server);
|
||||
});
|
||||
|
||||
it('can sign in successfully', async function () {
|
||||
server.loadFixtures('roles');
|
||||
stubSuccessfulOAuthConnect(application);
|
||||
|
||||
await visit('/signin');
|
||||
|
||||
expect(currentURL(), 'current url').to.equal('/signin');
|
||||
|
||||
expect(
|
||||
find('button.login').text().trim(),
|
||||
'login button text'
|
||||
).to.equal('Sign in with Ghost');
|
||||
|
||||
await click('button.login');
|
||||
|
||||
expect(currentURL(), 'url after connect').to.equal('/');
|
||||
});
|
||||
|
||||
it('handles a failed connect', async function () {
|
||||
stubFailedOAuthConnect(application);
|
||||
|
||||
await visit('/signin');
|
||||
await click('button.login');
|
||||
|
||||
expect(currentURL(), 'current url').to.equal('/signin');
|
||||
|
||||
expect(
|
||||
find('.main-error').text().trim(),
|
||||
'sign-in error'
|
||||
).to.match(/Authentication with Ghost\.org denied or failed/i);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -7,12 +7,7 @@ import {
|
|||
describe,
|
||||
it
|
||||
} from 'mocha';
|
||||
import {enableGhostOAuth} from '../helpers/configuration';
|
||||
import {expect} from 'chai';
|
||||
import {
|
||||
stubFailedOAuthConnect,
|
||||
stubSuccessfulOAuthConnect
|
||||
} from '../helpers/oauth';
|
||||
|
||||
describe('Acceptance: Signup', function() {
|
||||
let application;
|
||||
|
@ -130,55 +125,4 @@ describe('Acceptance: Signup', function() {
|
|||
it('redirects if already logged in');
|
||||
it('redirects with alert on invalid token');
|
||||
it('redirects with alert on non-existant or expired token');
|
||||
|
||||
describe('using Ghost OAuth', function () {
|
||||
beforeEach(function () {
|
||||
enableGhostOAuth(server);
|
||||
|
||||
let {invites, users} = server.schema;
|
||||
|
||||
let user = users.create({name: 'Test Invite Creator'});
|
||||
|
||||
invites.create({
|
||||
email: 'kevin+test2@ghost.org',
|
||||
createdBy: user.id
|
||||
});
|
||||
});
|
||||
|
||||
it('can sign up sucessfully', async function () {
|
||||
stubSuccessfulOAuthConnect(application);
|
||||
|
||||
// token details:
|
||||
// "1470346017929|kevin+test2@ghost.org|2cDnQc3g7fQTj9nNK4iGPSGfvomkLdXf68FuWgS66Ug="
|
||||
await visit('/signup/MTQ3MDM0NjAxNzkyOXxrZXZpbit0ZXN0MkBnaG9zdC5vcmd8MmNEblFjM2c3ZlFUajluTks0aUdQU0dmdm9ta0xkWGY2OEZ1V2dTNjZVZz0');
|
||||
|
||||
expect(currentPath()).to.equal('signup');
|
||||
|
||||
expect(
|
||||
find('.gh-flow-content header p').text().trim(),
|
||||
'form header text'
|
||||
).to.equal('Accept your invite from Test Invite Creator');
|
||||
|
||||
await click('button.login');
|
||||
|
||||
expect(currentPath()).to.equal('posts.index');
|
||||
});
|
||||
|
||||
it('handles failed connect', async function () {
|
||||
stubFailedOAuthConnect(application);
|
||||
|
||||
// token details:
|
||||
// "1470346017929|kevin+test2@ghost.org|2cDnQc3g7fQTj9nNK4iGPSGfvomkLdXf68FuWgS66Ug="
|
||||
await visit('/signup/MTQ3MDM0NjAxNzkyOXxrZXZpbit0ZXN0MkBnaG9zdC5vcmd8MmNEblFjM2c3ZlFUajluTks0aUdQU0dmdm9ta0xkWGY2OEZ1V2dTNjZVZz0');
|
||||
|
||||
await click('button.login');
|
||||
|
||||
expect(currentPath()).to.equal('signup');
|
||||
|
||||
expect(
|
||||
find('.main-error').text().trim(),
|
||||
'flow error text'
|
||||
).to.match(/authentication with ghost\.org denied or failed/i);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,7 +6,6 @@ import startApp from '../helpers/start-app';
|
|||
import {Response} from 'ember-cli-mirage';
|
||||
import {afterEach, beforeEach, describe, it} from 'mocha';
|
||||
import {authenticateSession, invalidateSession} from '../helpers/ember-simple-auth';
|
||||
import {enableGhostOAuth} from '../helpers/configuration';
|
||||
import {errorOverride, errorReset} from '../helpers/adapter-error';
|
||||
import {expect} from 'chai';
|
||||
|
||||
|
@ -715,34 +714,6 @@ describe('Acceptance: Team', function () {
|
|||
});
|
||||
});
|
||||
|
||||
describe('using Ghost OAuth', function () {
|
||||
beforeEach(function () {
|
||||
enableGhostOAuth(server);
|
||||
});
|
||||
|
||||
it('doesn\'t show the password reset form', async function () {
|
||||
await visit(`/team/${admin.slug}`);
|
||||
|
||||
// ensure that the normal form is displayed so we don't get
|
||||
// false positives
|
||||
expect(
|
||||
find('input#user-slug').length,
|
||||
'profile form is displayed'
|
||||
).to.equal(1);
|
||||
|
||||
// check that the password form is hidden
|
||||
expect(
|
||||
find('#password-reset').length,
|
||||
'presence of password reset form'
|
||||
).to.equal(0);
|
||||
|
||||
expect(
|
||||
find('#user-password-new').length,
|
||||
'presence of new password field'
|
||||
).to.equal(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('own user', function () {
|
||||
it('requires current password when changing password', async function () {
|
||||
await visit(`/team/${admin.slug}`);
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
import {isEmpty} from '@ember/utils';
|
||||
|
||||
export function enableGhostOAuth(server) {
|
||||
if (isEmpty(server.db.configurations)) {
|
||||
server.loadFixtures('configurations');
|
||||
}
|
||||
|
||||
server.db.configurations.update(1, {
|
||||
ghostAuthId: '6e0704b3-c653-4c12-8da7-584232b5c629',
|
||||
ghostAuthUrl: 'http://devauth.ghost.org:8080'
|
||||
});
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
import RSVP from 'rsvp';
|
||||
import {faker} from 'ember-cli-mirage';
|
||||
|
||||
let generateCode = function generateCode() {
|
||||
return faker.internet.password(32, false, /[a-zA-Z0-9]/);
|
||||
};
|
||||
|
||||
let generateSecret = function generateSecret() {
|
||||
return faker.internet.password(12, false, /[a-f0-9]/);
|
||||
};
|
||||
|
||||
const stubSuccessfulOAuthConnect = function stubSuccessfulOAuthConnect(application) {
|
||||
let provider = application.__container__.lookup('torii-provider:ghost-oauth2');
|
||||
|
||||
provider.open = function () {
|
||||
return RSVP.Promise.resolve({
|
||||
/* eslint-disable camelcase */
|
||||
authorizationCode: generateCode(),
|
||||
client_id: 'ghost-admin',
|
||||
client_secret: generateSecret(),
|
||||
provider: 'ghost-oauth2',
|
||||
redirectUrl: 'http://localhost:2368/ghost/'
|
||||
/* eslint-enable camelcase */
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
const stubFailedOAuthConnect = function stubFailedOAuthConnect(application) {
|
||||
let provider = application.__container__.lookup('torii-provider:ghost-oauth2');
|
||||
|
||||
provider.open = function () {
|
||||
return RSVP.Promise.reject();
|
||||
};
|
||||
};
|
||||
|
||||
export {
|
||||
stubSuccessfulOAuthConnect,
|
||||
stubFailedOAuthConnect
|
||||
};
|
11
yarn.lock
11
yarn.lock
|
@ -3017,7 +3017,7 @@ ember-cli-babel@6.8.2, ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.10, e
|
|||
clone "^2.0.0"
|
||||
ember-cli-version-checker "^2.0.0"
|
||||
|
||||
ember-cli-babel@^5.0.0, ember-cli-babel@^5.1.3, ember-cli-babel@^5.1.5, ember-cli-babel@^5.1.6, ember-cli-babel@^5.1.7:
|
||||
ember-cli-babel@^5.0.0, ember-cli-babel@^5.1.5, ember-cli-babel@^5.1.6, ember-cli-babel@^5.1.7:
|
||||
version "5.2.4"
|
||||
resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-5.2.4.tgz#5ce4f46b08ed6f6d21e878619fb689719d6e8e13"
|
||||
dependencies:
|
||||
|
@ -9038,15 +9038,6 @@ top-gh-contribs@2.0.4:
|
|||
lodash "^4.11.1"
|
||||
request "^2.72.0"
|
||||
|
||||
torii@0.8.2:
|
||||
version "0.8.2"
|
||||
resolved "https://registry.yarnpkg.com/torii/-/torii-0.8.2.tgz#60688b5ce0bc148dedf764df3c4c41f55da3f866"
|
||||
dependencies:
|
||||
broccoli-funnel "^1.0.1"
|
||||
broccoli-merge-trees "^1.1.1"
|
||||
broccoli-string-replace "^0.1.1"
|
||||
ember-cli-babel "^5.1.3"
|
||||
|
||||
tough-cookie@~2.3.0:
|
||||
version "2.3.2"
|
||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a"
|
||||
|
|
Loading…
Reference in New Issue