Desktop support (#4484)
* Remove home link on desktop app * Spellcheck, installation toasts, background styling, … * Add email,slack, auth support * More desktop style tweaks * Move redirect to client * cleanup * Record desktop usage * docs * fix: Selection state in search input when double clicking header
This commit is contained in:
@@ -2,10 +2,12 @@ import querystring from "querystring";
|
||||
import { addMonths } from "date-fns";
|
||||
import { Context } from "koa";
|
||||
import { pick } from "lodash";
|
||||
import { Client } from "@shared/types";
|
||||
import { getCookieDomain } from "@shared/utils/domains";
|
||||
import env from "@server/env";
|
||||
import Logger from "@server/logging/Logger";
|
||||
import { User, Event, Team, Collection, View } from "@server/models";
|
||||
import { Event, Collection, View } from "@server/models";
|
||||
import { AuthenticationResult } from "@server/types";
|
||||
|
||||
/**
|
||||
* Parse and return the details from the "sessions" cookie in the request, if
|
||||
@@ -27,11 +29,8 @@ export function getSessionsInCookie(ctx: Context) {
|
||||
|
||||
export async function signIn(
|
||||
ctx: Context,
|
||||
user: User,
|
||||
team: Team,
|
||||
service: string,
|
||||
_isNewUser = false,
|
||||
isNewTeam = false
|
||||
{ user, team, client, isNewTeam }: AuthenticationResult
|
||||
) {
|
||||
if (user.isSuspended) {
|
||||
return ctx.redirect("/?notice=suspended");
|
||||
@@ -74,6 +73,7 @@ export async function signIn(
|
||||
});
|
||||
const domain = getCookieDomain(ctx.request.hostname);
|
||||
const expires = addMonths(new Date(), 3);
|
||||
|
||||
// set a cookie for which service we last signed in with. This is
|
||||
// only used to display a UI hint for the user for next time
|
||||
ctx.cookies.set("lastSignedIn", service, {
|
||||
@@ -103,7 +103,20 @@ export async function signIn(
|
||||
expires,
|
||||
domain,
|
||||
});
|
||||
ctx.redirect(`${team.url}/auth/redirect?token=${user.getTransferToken()}`);
|
||||
|
||||
// If the authentication request originally came from the desktop app then we send the user
|
||||
// back to a screen in the web app that will immediately redirect to the desktop. The reason
|
||||
// to do this from the client is that if you redirect from the server then the browser ends up
|
||||
// stuck on the SSO screen.
|
||||
if (client === Client.Desktop) {
|
||||
ctx.redirect(
|
||||
`${team.url}/desktop-redirect?token=${user.getTransferToken()}`
|
||||
);
|
||||
} else {
|
||||
ctx.redirect(
|
||||
`${team.url}/auth/redirect?token=${user.getTransferToken()}`
|
||||
);
|
||||
}
|
||||
} else {
|
||||
ctx.cookies.set("accessToken", user.getJwtToken(), {
|
||||
sameSite: true,
|
||||
@@ -136,6 +149,7 @@ export async function signIn(
|
||||
}),
|
||||
]);
|
||||
const hasViewedDocuments = !!view;
|
||||
|
||||
ctx.redirect(
|
||||
!hasViewedDocuments && collection
|
||||
? `${team.url}${collection.url}`
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
StateStoreStoreCallback,
|
||||
StateStoreVerifyCallback,
|
||||
} from "passport-oauth2";
|
||||
import { Client } from "@shared/types";
|
||||
import { getCookieDomain, parseDomain } from "@shared/utils/domains";
|
||||
import env from "@server/env";
|
||||
import { Team } from "@server/models";
|
||||
@@ -20,8 +21,10 @@ export class StateStore {
|
||||
|
||||
// We expect host to be a team subdomain, custom domain, or apex domain
|
||||
// that is passed via query param from the auth provider component.
|
||||
const clientInput = ctx.query.client?.toString();
|
||||
const client = clientInput === Client.Desktop ? Client.Desktop : Client.Web;
|
||||
const host = ctx.query.host?.toString() || parseDomain(ctx.hostname).host;
|
||||
const state = buildState(host, token);
|
||||
const state = buildState(host, token, client);
|
||||
|
||||
ctx.cookies.set(this.key, state, {
|
||||
httpOnly: false,
|
||||
@@ -76,13 +79,19 @@ export async function request(endpoint: string, accessToken: string) {
|
||||
return response.json();
|
||||
}
|
||||
|
||||
function buildState(host: string, token: string) {
|
||||
return [host, token].join("|");
|
||||
function buildState(host: string, token: string, client?: Client) {
|
||||
return [host, token, client].join("|");
|
||||
}
|
||||
|
||||
export function parseState(state: string) {
|
||||
const [host, token] = state.split("|");
|
||||
return { host, token };
|
||||
const [host, token, client] = state.split("|");
|
||||
return { host, token, client };
|
||||
}
|
||||
|
||||
export function getClientFromContext(ctx: Context): Client {
|
||||
const state = ctx.cookies.get("state");
|
||||
const client = state ? parseState(state).client : undefined;
|
||||
return client === Client.Desktop ? Client.Desktop : Client.Web;
|
||||
}
|
||||
|
||||
export async function getTeamFromContext(ctx: Context) {
|
||||
@@ -90,7 +99,6 @@ export async function getTeamFromContext(ctx: Context) {
|
||||
// we use it to infer the team they intend on signing into
|
||||
const state = ctx.cookies.get("state");
|
||||
const host = state ? parseState(state).host : ctx.hostname;
|
||||
|
||||
const domain = parseDomain(host);
|
||||
|
||||
let team;
|
||||
|
||||
Reference in New Issue
Block a user