Skip to content

Commit

Permalink
Private Gifable features (#101)
Browse files Browse the repository at this point in the history
* Seed admin user on server start.

* Optionally disable public user registration.
  • Loading branch information
pietvanzoen authored Dec 10, 2023
1 parent ac6e9ad commit 73de7ef
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 16 deletions.
7 changes: 7 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,10 @@ S3_USE_SSL=true # optional
SESSION_SECRET=

DEBUG="app:*"

# Seed an admin user on server start.
# ADMIN_USERNAME=
# ADMIN_PASSWORD=

# Disable public user registration.
# DISABLE_SIGNUP=1
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,7 @@ docker run -d \
-e DATABASE_URL="file:/data/gifable.db" \
ghcr.io/pietvanzoen/gifable:latest
```

## Configuration

See `.env.example` for all available configuration options.
60 changes: 45 additions & 15 deletions app/routes/login.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { ActionArgs } from "@remix-run/node";
import { json, type ActionArgs } from "@remix-run/node";
import {
isRouteErrorResponse,
useActionData,
useLoaderData,
useRouteError,
useSearchParams,
} from "@remix-run/react";
Expand All @@ -21,6 +22,7 @@ import { UserSchema } from "~/utils/validators";
import { makeTitle } from "~/utils/meta";
import styles from "~/styles/login.css";
import { isRateLimited, rateLimitError } from "~/utils/rate-limiter.server";
import env from "~/utils/env.server";

const log = debug("app:login");

Expand Down Expand Up @@ -84,6 +86,14 @@ export async function action({ request }: ActionArgs) {
}

case "register": {
if (env.get("DISABLE_SIGNUP")) {
log("Signup is disabled");
return badRequest({
repopulateFields: result.submittedData,
message: `Signup is disabled`,
});
}

log("Registering user %s", username);
const resp = await isRateLimited(
getClientIPAddress(request) || username,
Expand Down Expand Up @@ -126,14 +136,23 @@ export async function action({ request }: ActionArgs) {
}
}

export function loader() {
return json({
allowSignup: !env.get("DISABLE_SIGNUP"),
});
}

export default function Login() {
const data = useLoaderData<typeof loader>();
const actionData = useActionData<typeof action>();
const [searchParams] = useSearchParams();
const defaultValues = actionData?.repopulateFields || {
redirectTo: searchParams.get("redirectTo") || "/",
loginType: "login",
};

const title = data.allowSignup ? "Login or Register" : "Login";

return (
<ValidatedForm
validator={validator}
Expand All @@ -143,22 +162,33 @@ export default function Login() {
>
<fieldset>
<legend>
<h1>Login or Register?</h1>
<h1>{title}</h1>
</legend>
<FormInput label="Redirect to" type="hidden" name="redirectTo" />
<FormInput
name="loginType"
label="Login"
type="radio"
value="login"
checked
/>
<FormInput
name="loginType"
label="Register"
type="radio"
value="register"
/>
{data.allowSignup ? (
<>
<FormInput
name="loginType"
label="Login"
type="radio"
value="login"
checked
/>
<FormInput
name="loginType"
label="Register"
type="radio"
value="register"
/>
</>
) : (
<FormInput
name="loginType"
label="Login"
type="hidden"
value="login"
/>
)}
<FormInput name="username" label="Username" required />
<FormInput name="password" label="Password" type="password" required />
<Alert>{actionData?.message}</Alert>
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"build": "remix build",
"dev": "DEBUG=app:* remix dev",
"predev": "prisma generate && npm run install:css",
"prestart": "prisma migrate deploy",
"prestart": "prisma migrate deploy && node ./seed-admin.mjs",
"start": "remix-serve build",
"typecheck": "tsc",
"test": "jest app",
Expand Down
44 changes: 44 additions & 0 deletions seed-admin.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//@ts-check
import { PrismaClient } from "@prisma/client";
import bycrypt from "bcryptjs";

const db = new PrismaClient();

const log = (/** @type {string} */ message) =>
console.log(`ADMIN SEED: ${message}`);

async function main() {
const { ADMIN_USERNAME, ADMIN_PASSWORD } = process.env;

if (!ADMIN_USERNAME || !ADMIN_PASSWORD) {
return;
}

const admin = await db.user.findUnique({
where: {
username: ADMIN_USERNAME,
},
});

if (admin) {
log(`Admin user '${ADMIN_USERNAME}' already exists`);
return;
}

log(`Seeding admin user '${ADMIN_USERNAME}'`);

await db.user.create({
data: {
username: ADMIN_USERNAME,
passwordHash: await bycrypt.hash(ADMIN_PASSWORD, 10),
isAdmin: true,
},
});

log(`Admin user '${ADMIN_USERNAME}' created`);
}

main().catch((e) => {
console.error(e);
process.exit(1);
});

0 comments on commit 73de7ef

Please sign in to comment.