Optional password protection for the web server

This commit is contained in:
Cadence Ember
2025-02-25 14:36:49 +13:00
parent 3bc37857bb
commit 3b034dd6e5
9 changed files with 103 additions and 32 deletions

View File

@@ -71,7 +71,7 @@ server {
client_max_body_size 5M;
location / {
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
proxy_pass http://127.0.0.1:6693;
}
}

View File

@@ -141,6 +141,7 @@ function defineEchoHandler() {
console.log("OOYE has its own web server. It needs to be accessible on the public internet.")
console.log("You need to enter a public URL where you will be able to host this web server.")
console.log("OOYE listens on localhost:6693, so you will probably have to set up a reverse proxy.")
console.log("Examples: https://gitdab.com/cadence/out-of-your-element/src/branch/main/docs/get-started.md#appendix")
console.log("Now listening on port 6693. Feel free to send some test requests.")
/** @type {{bridge_origin: string}} */
const bridgeOriginResponse = await prompt({
@@ -207,6 +208,15 @@ function defineEchoHandler() {
})
}
console.log("Would you like to require a password to add your bot to servers? This will discourage others from using your bridge.")
console.log("Important: To make it truly private, you MUST ALSO disable Public Bot in the Discord bot configuration page.")
/** @type {{web_password: string}} */
const passwordResponse = await prompt({
type: "text",
name: "web_password",
message: "Choose a simple password (optional)"
})
console.log("What is your Discord client secret?")
console.log(`You can find it in the application's OAuth2 section: https://discord.com/developers/applications/${client.id}/oauth2`)
/** @type {{discord_client_secret: string}} */
@@ -244,7 +254,8 @@ function defineEchoHandler() {
...bridgeOriginResponse,
server_origin: serverOrigin,
...discordTokenResponse,
...clientSecretResponse
...clientSecretResponse,
...passwordResponse
}
}
registration.reg = reg

3
src/types.d.ts vendored
View File

@@ -29,7 +29,8 @@ export type AppServiceRegistrationConfig = {
include_user_id_in_mxid: boolean
invite: string[]
discord_origin?: string
discord_cdn_origin?: string
discord_cdn_origin?: string,
web_password: string
}
old_bridge?: {
as_token: string

View File

@@ -23,7 +23,7 @@ async function getManagedGuilds(event) {
/**
* @param {h3.H3Event} event
* @returns {ReturnType<typeof h3.useSession<{userID?: string, mxid?: string, managedGuilds?: string[], state?: string, selfService?: boolean}>>}
* @returns {ReturnType<typeof h3.useSession<{userID?: string, mxid?: string, managedGuilds?: string[], state?: string, selfService?: boolean, password?: string}>>}
*/
function useSession(event) {
return h3.useSession(event, {password: reg.as_token})

View File

@@ -1,24 +1,56 @@
extends includes/template.pug
block body
.s-page-title.mb24
h1.s-page-title--header Bridge a Discord server
- let locked = reg.ooye.web_password && reg.ooye.web_password !== session.data.password
.d-grid.g24.grid__2(class="sm:grid__1")
.s-card.bs-md.d-flex.fd-column
h2 Easy mode
p Add the bot to your Discord server.
p It will automatically create new Matrix rooms for you.
.fl-grow1
a.s-btn.s-btn__filled.s-btn__icon(href=rel("/oauth?action=add"))
!= icons.Icons.IconPlus
= ` Add to server`
.s-card.bs-md.d-flex.fd-column
h2 Self-service
p OOYE will link an existing Discord server and Matrix space together.
p Choose this option if you already have a community set up on Matrix.
p Or, choose this if you're migrating from a different bridge.
.fl-grow1
a.s-btn.s-btn__outlined.s-btn__icon(href=rel("/oauth?action=add-self-service"))
!= icons.Icons.IconUnorderedList
= ` Set up self-service`
if locked
aside.s-notice.s-notice__warning.p8
.d-flex.flex__center.jc-space-between.s-banner--container.g8(class="md:fw-wrap")
.d-flex.ai-center.g8
.flex--item!= icons.Icons.IconLock
p.m0 <strong>Private instance.</strong> You need the password to use this instance of Out Of Your Element.
form(method="post" action="/api/password")
input.s-input(placeholder="Enter password" name="password")
.h32
.s-page-title.mb24
h1.s-page-title--header Out Of Your Element
else
.s-page-title.mb24
h1.s-page-title--header Bridge a Discord server
.d-grid.g24.grid__2.mb24(class="sm:grid__1")
.s-card.bs-md.d-flex.fd-column
h2 Easy mode
p Add the bot to your Discord server.
p It will automatically create new Matrix rooms for you.
.fl-grow1
a.s-btn.s-btn__filled.s-btn__icon(href=rel("/oauth?action=add"))
!= icons.Icons.IconPlus
= ` Add to server`
.s-card.bs-md.d-flex.fd-column
h2 Self-service
p OOYE will link an existing Discord server and Matrix space together.
p Choose this option if you already have a community set up on Matrix.
p Or, choose this if you're migrating from a different bridge.
.fl-grow1
a.s-btn.s-btn__outlined.s-btn__icon(href=rel("/oauth?action=add-self-service"))
!= icons.Icons.IconUnorderedList
= ` Set up self-service`
.s-prose
h2 What is this?
p #[a(href="https://gitdab.com/cadence/out-of-your-element") Out Of Your Element] is a bridge between the Discord and Matrix chat apps. It lets people on both platforms chat with each other without needing to get everyone on the same app.
p Just chat like usual, and the bridge will forward messages back and forth between the two platforms, so everyone sees the whole conversation.
p All kinds of content are supported, including pictures, threads, emojis, and @mentions.
p It's really easy to set up, even if you only have Discord. Just add the bot to your server, and it'll make everything available on Matrix automatically.
if locked
h2 This is a private instance
p Anybody can run their own instance of the Out Of Your Element software. The person running this instance has made it private, so you can't add it to your server just yet. If you know the people in charge of #{reg.ooye.server_name}, ask them for the password.
h2 Run your own instance
p You can still use Out Of Your Element by running your own copy of the software, but this requires some technical skill.
p To get started, #[a(href="https://gitdab.com/cadence/out-of-your-element/src/branch/main/docs/get-started.md") check the installation instructions.]

View File

@@ -61,6 +61,9 @@ html(lang="en")
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 80%22><text y=%22.83em%22 font-size=%2283%22>💬</text></svg>">
meta(name="htmx-config" content='{"requestClass":"is-loading"}')
style.
.s-prose a {
text-decoration: underline;
}
.themed {
--theme-base-primary-color-h: 266;
--theme-base-primary-color-s: 53%;

View File

@@ -37,13 +37,15 @@ as.router.get("/oauth", defineEventHandler(async event => {
const session = await auth.useSession(event)
let scope = "guilds"
const parsedFirstQuery = await getValidatedQuery(event, schema.first.safeParse)
if (parsedFirstQuery.data?.action === "add") {
scope = "bot+guilds"
await session.update({selfService: false})
} else if (parsedFirstQuery.data?.action === "add-self-service") {
scope = "bot+guilds"
await session.update({selfService: true})
if (!reg.ooye.web_password || reg.ooye.web_password === session.data.password) {
const parsedFirstQuery = await getValidatedQuery(event, schema.first.safeParse)
if (parsedFirstQuery.data?.action === "add") {
scope = "bot+guilds"
await session.update({selfService: false})
} else if (parsedFirstQuery.data?.action === "add-self-service") {
scope = "bot+guilds"
await session.update({selfService: true})
}
}
async function tryAgain() {

View File

@@ -0,0 +1,21 @@
// @ts-check
const {z} = require("zod")
const {defineEventHandler, readValidatedBody, sendRedirect} = require("h3")
const {as, sync} = require("../../passthrough")
/** @type {import("../auth")} */
const auth = sync.require("../auth")
const schema = {
password: z.object({
password: z.string()
})
}
as.router.post("/api/password", defineEventHandler(async event => {
const {password} = await readValidatedBody(event, schema.password.parse)
const session = await auth.useSession(event)
await session.update({password})
return sendRedirect(event, "../")
}))

View File

@@ -30,8 +30,9 @@ sync.require("./routes/download-discord")
sync.require("./routes/guild-settings")
sync.require("./routes/guild")
sync.require("./routes/link")
sync.require("./routes/oauth")
sync.require("./routes/log-in-with-matrix")
sync.require("./routes/oauth")
sync.require("./routes/password")
// Files