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

Save target url in SessionStorage for post-auth redirect; Add EmberSimpleAuth types #20

Merged
merged 2 commits into from
Feb 3, 2023
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
21 changes: 2 additions & 19 deletions web/app/controllers/authenticate.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,17 @@
import Controller from "@ember/controller";
import { inject as service } from "@ember/service";
import { action } from "@ember/object";
import RouterService from "@ember/routing/router-service";
import Transition from "@ember/routing/transition";
import SessionService from "hermes/services/session";

export default class AuthenticateController extends Controller {
@service declare router: RouterService;
@service declare session: any;

previousTransition: Transition | null = null;
@service declare session: SessionService;

protected get currentYear(): number {
return new Date().getFullYear();
}

@action protected authenticate(): void {
this.session.authenticate("authenticator:torii", "google-oauth2-bearer");

// Capture the previousTransition locally if it exists
let _previousTransition = this.previousTransition;

if (_previousTransition) {
// Clear the previousTransition class property
this.previousTransition = null;

// Retry the initial transition
_previousTransition.retry();
} else {
this.router.transitionTo("authenticated.dashboard");
}
}
}

Expand Down
3 changes: 2 additions & 1 deletion web/app/routes/authenticate.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import Route from "@ember/routing/route";
import { inject as service } from "@ember/service";
import SessionService from "hermes/services/session";

export default class AuthenticateRoute extends Route {
@service declare session: any;
@service declare session: SessionService;

beforeModel() {
this.session.prohibitAuthentication("/");
Expand Down
32 changes: 18 additions & 14 deletions web/app/routes/authenticated.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,38 @@
import Route from "@ember/routing/route";
import { inject as service } from "@ember/service";
import ConfigService from "hermes/services/config";
import AuthenticateController from "hermes/controllers/authenticate";
import AuthenticatedUserService from "hermes/services/authenticated-user";
import Transition from "@ember/routing/transition";
import window from "ember-window-mock";
import SessionService from "hermes/services/session";

export default class AuthenticatedRoute extends Route {
@service declare session: any;
@service declare session: SessionService;
@service declare authenticatedUser: AuthenticatedUserService;
@service("config") declare configSvc: ConfigService;

async afterModel(): Promise<void> {
// Load user info
await this.authenticatedUser.loadInfo.perform();
}

async beforeModel(transition: Transition): Promise<void> {
// Check if the request requires authentication and if so, preserve the URL
async beforeModel(transition: any): Promise<void> {
// If the user isn't authenticated, transition to the auth screen
let requireAuthentication = this.session.requireAuthentication(
transition,
"authenticate"
);

if (!requireAuthentication && transition.to.name != "authenticated.index") {
let authenticateController = this.controllerFor(
"authenticate"
) as AuthenticateController;
let target = window.sessionStorage.getItem(
this.session.SESSION_STORAGE_KEY
);
if (
!target &&
!requireAuthentication &&
transition.to.name != "authenticated"
) {
// ember-simple-auth uses this value to set cookies when fastboot is enabled: https://github.com/mainmatter/ember-simple-auth/blob/a7e583cf4d04d6ebc96b198a8fa6dde7445abf0e/packages/ember-simple-auth/addon/-internals/routing.js#L12

// Set previous transition to preserve URL
authenticateController.previousTransition = transition;
window.sessionStorage.setItem(
this.session.SESSION_STORAGE_KEY,
transition.intent.url
);
}
}
}
5 changes: 3 additions & 2 deletions web/app/services/algolia.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { assert } from "@ember/debug";
import ConfigService from "./config";
import { FacetOption, FacetRecord, FacetRecords } from "hermes/types/facets";
import FetchService from "./fetch";
import SessionService from "./session";

export const HITS_PER_PAGE = 12;
export const MAX_VALUES_PER_FACET = 100;
Expand All @@ -26,9 +27,9 @@ export type AlgoliaFacetsObject = NonNullable<SearchResponse["facets"]>;
export default class AlgoliaService extends Service {
@service("config") declare configSvc: ConfigService;
@service("fetch") declare fetchSvc: FetchService;
@service declare session: SessionService;
@service declare authenticatedUser: AuthenticatedUserService;
// TODO: use actual type.
@service session: any;


/**
* A shorthand getter for the authenticatedUser's email.
Expand Down
3 changes: 2 additions & 1 deletion web/app/services/authenticated-user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import Store from "@ember-data/store";
import { assert } from "@ember/debug";
import { task } from "ember-concurrency";
import FetchService from "hermes/services/fetch";
import SessionService from "./session";

export interface AuthenticatedUser {
email: string;
Expand All @@ -25,8 +26,8 @@ enum SubscriptionType {

export default class AuthenticatedUserService extends Service {
@service("fetch") declare fetchSvc: FetchService;
@service declare session: SessionService;
@service declare store: Store;
@service declare session: any;

@tracked subscriptions: Subscription[] | null = null;
@tracked private _info: AuthenticatedUser | null = null;
Expand Down
28 changes: 28 additions & 0 deletions web/app/services/session.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { inject as service } from "@ember/service";
import RouterService from "@ember/routing/router-service";
import EmberSimpleAuthSessionService from "ember-simple-auth/services/session";
import window from "ember-window-mock";

export default class SessionService extends EmberSimpleAuthSessionService {
@service declare router: RouterService;

readonly SESSION_STORAGE_KEY: string = "hermes.redirectTarget";

// ember-simple-auth only uses a cookie to track redirect target if you're using fastboot, otherwise it keeps track of the redirect target as a parameter on the session service. See the source here: https://github.com/mainmatter/ember-simple-auth/blob/a7e583cf4d04d6ebc96b198a8fa6dde7445abf0e/packages/ember-simple-auth/addon/-internals/routing.js#L33-L50
//
// Because we redirect as part of the authentication flow, the parameter storing the transition gets reset. Instead, we keep track of the redirectTarget in browser sessionStorage and override the handleAuthentication method as recommended by ember-simple-auth.

handleAuthentication(routeAfterAuthentication: string) {
let redirectTarget = window.sessionStorage.getItem(this.SESSION_STORAGE_KEY);
let transition;

if (redirectTarget) {
transition = this.router.transitionTo(redirectTarget);
} else {
transition = this.router.transitionTo(routeAfterAuthentication);
}
transition.followRedirects().then(() => {
window.sessionStorage.removeItem(this.SESSION_STORAGE_KEY);
});
}
}
25 changes: 25 additions & 0 deletions web/types/ember-simple-auth/services/session.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Reference: https://github.com/mainmatter/ember-simple-auth/blob/master/packages/ember-simple-auth/addon/services/session.js

import Service from "@ember/service";
import Evented from "@ember/object/evented";
import Transition from "@ember/routing/transition";

export interface Data {
authenticated: {
access_token: string;
};
}

declare module "ember-simple-auth/services/session" {
export default class EmberSimpleAuthSessionService extends Service.extend(Evented) {
data: Data;
setup: () => void;
authenticate(...args: any[]): RSVP.Promise;
invalidate(...args: any): RSVP.Promise;
requireAuthentication(
transition: Transition,
routeOrCallback: string | function
): RSVP.Promise;
prohibitAuthentication(routeOrCallback: string | function): RSVP.Promise;
}
}