mirror of
https://github.com/webstudio-is/webstudio.git
synced 2026-11-05 11:38:36 +09:00
## Description closes #3400 `+` on dev login its now possible to add any email like `{code}:hello@world.xx` to login as other user ## Steps for reproduction Login on main with `{code}:ice@yandex.ru` - See no plan <img width="213" alt="image" src="https://github.com/webstudio-is/webstudio/assets/5077042/65f79295-63b3-4d4f-b5d2-ed854f8462e3"> --- Login on main as usual - See user has plan <img width="265" alt="image" src="https://github.com/webstudio-is/webstudio/assets/5077042/db9e1c3e-a8d7-4cde-bbd5-1f39ce7442b8"> --- Login locally See user has plan <img width="231" alt="image" src="https://github.com/webstudio-is/webstudio/assets/5077042/c1187bce-2c7e-49f3-a3ac-bfa15560ccce"> ## Code Review - [ ] hi @kof, I need you to do - conceptual review (architecture, feature-correctness) - detailed review (read every line) - test it on preview ## Before requesting a review - [ ] made a self-review - [ ] added inline comments where things may be not obvious (the "why", not "what") ## Before merging - [ ] tested locally and on preview environment (preview dev login: 5de6) - [ ] updated [test cases](https://github.com/webstudio-is/webstudio/blob/main/apps/builder/docs/test-cases.md) document - [ ] added tests - [ ] if any new env variables are added, added them to `.env.example` and the `builder/env-check.js` if mandatory
115 lines
3.0 KiB
TypeScript
115 lines
3.0 KiB
TypeScript
import { Authenticator } from "remix-auth";
|
|
import { FormStrategy } from "remix-auth-form";
|
|
import { GitHubStrategy, type GitHubProfile } from "remix-auth-github";
|
|
import { GoogleStrategy, type GoogleProfile } from "remix-auth-google";
|
|
import * as db from "~/shared/db";
|
|
import { sessionStorage } from "~/services/session.server";
|
|
import { AUTH_PROVIDERS } from "~/shared/session";
|
|
import { authCallbackPath } from "~/shared/router-utils";
|
|
import { getUserById, type User } from "~/shared/db/user.server";
|
|
import env from "~/env/env.server";
|
|
|
|
const url =
|
|
env.DEPLOYMENT_ENVIRONMENT === "production"
|
|
? env.DEPLOYMENT_URL
|
|
: `http://localhost:${env.PORT || 3000}`;
|
|
|
|
const strategyCallback = async ({
|
|
profile,
|
|
}: {
|
|
profile: GitHubProfile | GoogleProfile;
|
|
}) => {
|
|
try {
|
|
const user = await db.user.createOrLoginWithOAuth(profile);
|
|
return user;
|
|
} catch (error) {
|
|
if (error instanceof Error) {
|
|
console.error({
|
|
error,
|
|
extras: {
|
|
loginMethod: AUTH_PROVIDERS.LOGIN_DEV,
|
|
},
|
|
});
|
|
}
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
// Create an instance of the authenticator, pass a generic with what
|
|
// strategies will return and will store in the session
|
|
export const authenticator = new Authenticator<User>(sessionStorage, {
|
|
throwOnError: true,
|
|
});
|
|
|
|
if (env.GH_CLIENT_ID && env.GH_CLIENT_SECRET) {
|
|
const github = new GitHubStrategy(
|
|
{
|
|
clientID: env.GH_CLIENT_ID,
|
|
clientSecret: env.GH_CLIENT_SECRET,
|
|
callbackURL: `${url}${authCallbackPath({ provider: "github" })}`,
|
|
},
|
|
strategyCallback
|
|
);
|
|
authenticator.use(github, "github");
|
|
}
|
|
|
|
if (env.GOOGLE_CLIENT_ID && env.GOOGLE_CLIENT_SECRET) {
|
|
const google = new GoogleStrategy(
|
|
{
|
|
clientID: env.GOOGLE_CLIENT_ID,
|
|
clientSecret: env.GOOGLE_CLIENT_SECRET,
|
|
callbackURL: `${url}${authCallbackPath({ provider: "google" })}`,
|
|
},
|
|
strategyCallback
|
|
);
|
|
authenticator.use(google, "google");
|
|
}
|
|
|
|
if (env.DEV_LOGIN === "true") {
|
|
authenticator.use(
|
|
new FormStrategy(async ({ form }) => {
|
|
const secretValue = form.get("secret");
|
|
|
|
if (secretValue == null) {
|
|
throw new Error("Secret is required");
|
|
}
|
|
|
|
const [secret, email = "hello@webstudio.is"] = secretValue
|
|
.toString()
|
|
.split(":");
|
|
|
|
if (secret === env.AUTH_SECRET?.slice(0, 4)) {
|
|
try {
|
|
const user = await db.user.createOrLoginWithDev(email);
|
|
return user;
|
|
} catch (error) {
|
|
if (error instanceof Error) {
|
|
console.error({
|
|
error,
|
|
extras: {
|
|
loginMethod: AUTH_PROVIDERS.LOGIN_DEV,
|
|
},
|
|
});
|
|
}
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
throw new Error("Secret is incorrect");
|
|
}),
|
|
"dev"
|
|
);
|
|
}
|
|
|
|
export const findAuthenticatedUser = async (request: Request) => {
|
|
const user = await authenticator.isAuthenticated(request);
|
|
if (user == null) {
|
|
return null;
|
|
}
|
|
try {
|
|
return await getUserById(user.id);
|
|
} catch (error) {
|
|
return null;
|
|
}
|
|
};
|