From e97b90d4d74752d40f89d5cd648169b170d9e389 Mon Sep 17 00:00:00 2001 From: Harvey Tindall Date: Sat, 29 May 2021 17:43:11 +0100 Subject: [PATCH] Matrix: Setup bot, add PIN verification PIN is verified but not used currently. Works a little different than the others, you input your matrix user ID and then the PIN is sent to you. The bot doesn't support E2EE, so the bot being the first one to message ensures the chat is unencrypted. --- api.go | 62 ++++++++++++++++++ config.go | 7 ++- config/config-base.json | 73 +++++++++++++++++++++ go.mod | 1 + go.sum | 2 + html/form-base.html | 3 + html/form.html | 28 ++++++++- lang/common/en-us.json | 2 + lang/form/en-us.json | 4 +- lang/telegram/en-us.json | 1 + main.go | 11 ++++ matrix.go | 133 +++++++++++++++++++++++++++++++++++++++ models.go | 7 +++ router.go | 4 ++ storage.go | 39 +++++++----- telegram.go | 2 +- ts/form.ts | 77 ++++++++++++++++++++++- ts/modules/common.ts | 6 +- ts/typings/d.ts | 1 + views.go | 5 ++ 20 files changed, 446 insertions(+), 22 deletions(-) create mode 100644 matrix.go diff --git a/api.go b/api.go index 4c1ccb2..66b6f0f 100644 --- a/api.go +++ b/api.go @@ -2233,6 +2233,68 @@ func (app *appContext) DiscordServerInvite(gc *gin.Context) { gc.JSON(200, DiscordInviteDTO{invURL, iconURL}) } +// @Summary Generate and send a new PIN to a specified Matrix user. +// @Produce json +// @Success 200 {object} boolResponse +// @Failure 400 {object} boolResponse +// @Failure 401 {object} boolResponse +// @Failure 500 {object} boolResponse +// @Param invCode path string true "invite Code" +// @Param MatrixSendPINDTO body MatrixSendPINDTO true "User's Matrix ID." +// @Router /invite/{invCode}/matrix/user [post] +// @tags Other +func (app *appContext) MatrixSendPIN(gc *gin.Context) { + code := gc.Param("invCode") + if _, ok := app.storage.invites[code]; !ok { + respondBool(401, false, gc) + return + } + var req MatrixSendPINDTO + gc.BindJSON(&req) + if req.UserID == "" { + respondBool(400, false, gc) + return + } + ok := app.matrix.SendStart(req.UserID) + if !ok { + respondBool(500, false, gc) + return + } + respondBool(200, true, gc) +} + +// @Summary Check whether a matrix PIN is valid. Requires invite code. +// @Produce json +// @Success 200 {object} boolResponse +// @Failure 401 {object} boolResponse +// @Param pin path string true "PIN code to check" +// @Param invCode path string true "invite Code" +// @Param userID path string true "Matrix User ID" +// @Router /invite/{invCode}/matrix/verified/{userID}/{pin} [get] +// @tags Other +func (app *appContext) MatrixCheckPIN(gc *gin.Context) { + code := gc.Param("invCode") + if _, ok := app.storage.invites[code]; !ok { + app.debug.Println("Matrix: Invite code was invalid") + respondBool(401, false, gc) + return + } + userID := gc.Param("userID") + pin := gc.Param("pin") + user, ok := app.matrix.tokens[pin] + if !ok { + app.debug.Println("Matrix: PIN not found") + respondBool(200, false, gc) + return + } + if user.User.UserID != userID { + app.debug.Println("Matrix: User ID of PIN didn't match") + respondBool(200, false, gc) + return + } + respondBool(200, true, gc) +} + // @Summary Returns a list of matching users from a Discord guild, given a username (discriminator optional). // @Produce json // @Success 200 {object} DiscordUsersDTO diff --git a/config.go b/config.go index d605ef5..70e1330 100644 --- a/config.go +++ b/config.go @@ -15,6 +15,7 @@ var emailEnabled = false var messagesEnabled = false var telegramEnabled = false var discordEnabled = false +var matrixEnabled = false func (app *appContext) GetPath(sect, key string) (fs.FS, string) { val := app.config.Section(sect).Key(key).MustString("") @@ -43,7 +44,7 @@ func (app *appContext) loadConfig() error { key.SetValue(key.MustString(filepath.Join(app.dataPath, (key.Name() + ".json")))) } } - for _, key := range []string{"user_configuration", "user_displayprefs", "user_profiles", "ombi_template", "invites", "emails", "user_template", "custom_emails", "users", "telegram_users", "discord_users"} { + for _, key := range []string{"user_configuration", "user_displayprefs", "user_profiles", "ombi_template", "invites", "emails", "user_template", "custom_emails", "users", "telegram_users", "discord_users", "matrix_users"} { app.config.Section("files").Key(key).SetValue(app.config.Section("files").Key(key).MustString(filepath.Join(app.dataPath, (key + ".json")))) } app.URLBase = strings.TrimSuffix(app.config.Section("ui").Key("url_base").MustString(""), "/") @@ -89,16 +90,18 @@ func (app *appContext) loadConfig() error { messagesEnabled = app.config.Section("messages").Key("enabled").MustBool(false) telegramEnabled = app.config.Section("telegram").Key("enabled").MustBool(false) discordEnabled = app.config.Section("discord").Key("enabled").MustBool(false) + matrixEnabled = app.config.Section("matrix").Key("enabled").MustBool(false) if !messagesEnabled { emailEnabled = false telegramEnabled = false discordEnabled = false + matrixEnabled = false } else if app.config.Section("email").Key("method").MustString("") == "" { emailEnabled = false } else { emailEnabled = true } - if !emailEnabled && !telegramEnabled && !discordEnabled { + if !emailEnabled && !telegramEnabled && !discordEnabled && !matrixEnabled { messagesEnabled = false } diff --git a/config/config-base.json b/config/config-base.json index 36bad28..46d2b18 100644 --- a/config/config-base.json +++ b/config/config-base.json @@ -676,6 +676,71 @@ } } }, + "matrix": { + "order": [], + "meta": { + "name": "Matrix", + "description": "Settings for Matrix invites/signup/notifications" + }, + "settings": { + "enabled": { + "name": "Enabled", + "required": false, + "requires_restart": true, + "type": "bool", + "value": false, + "description": "Enable signup verification through Matrix and the sending of notifications through it.\nSee the jfa-go wiki for setting up a bot." + }, + "required": { + "name": "Require on sign-up", + "required": false, + "required_restart": true, + "depends_true": "enabled", + "type": "bool", + "value": false, + "description": "Require Matrix connection on sign-up." + }, + "homeserver": { + "name": "Home Server URL", + "required": false, + "requires_restart": true, + "depends_true": "enabled", + "type": "text", + "value": "", + "description": "Matrix Home server URL." + }, + "token": { + "name": "Access Token", + "required": false, + "requires_restart": true, + "depends_true": "enabled", + "type": "text", + "value": "", + "description": "Matrix Bot API Token." + }, + "user_id": { + "name": "Bot User ID", + "required": false, + "requires_restart": true, + "depends_true": "enabled", + "type": "text", + "value": "", + "description": "User ID of bot account (Example: @jfa-bot:riot.im)" + }, + "language": { + "name": "Language", + "required": false, + "requires_restart": false, + "depends_true": "enabled", + "type": "select", + "options": [ + ["en-us", "English (US)"] + ], + "value": "en-us", + "description": "Default Matrix message language. Visit weblate if you'd like to translate." + } + } + }, "password_resets": { "order": [], "meta": { @@ -1225,6 +1290,14 @@ "value": "", "description": "Stores telegram user IDs and language preferences." }, + "matrix_users": { + "name": "Matrix users", + "required": false, + "requires_restart": false, + "type": "text", + "value": "", + "description": "Stores matrix user IDs and language preferences." + }, "discord_users": { "name": "Discord users", "required": false, diff --git a/go.mod b/go.mod index 33d4591..7e15dfa 100644 --- a/go.mod +++ b/go.mod @@ -38,6 +38,7 @@ require ( github.com/lithammer/shortuuid/v3 v3.0.4 github.com/mailgun/mailgun-go/v4 v4.5.1 github.com/mailru/easyjson v0.7.7 // indirect + github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect github.com/smartystreets/goconvey v1.6.4 // indirect diff --git a/go.sum b/go.sum index 42b3910..c20797a 100644 --- a/go.sum +++ b/go.sum @@ -189,6 +189,8 @@ github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16 h1:ZtO5uywdd5dLDCud4r0r55eP4j9FuUNpl60Gmntcop4= +github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16/go.mod h1:/gBX06Kw0exX1HrwmoBibFA98yBk/jxKpGVeyQbff+s= github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= diff --git a/html/form-base.html b/html/form-base.html index 855253b..be95c3e 100644 --- a/html/form-base.html +++ b/html/form-base.html @@ -22,6 +22,9 @@ window.discordPIN = "{{ .discordPIN }}"; window.discordInviteLink = {{ .discordInviteLink }}; window.discordServerName = "{{ .discordServerName }}"; + window.matrixEnabled = {{ .matrixEnabled }}; + window.matrixRequired = {{ .matrixRequired }}; + window.matrixUserID = "{{ .matrixUser }}"; {{ end }} diff --git a/html/form.html b/html/form.html index 6b785d0..fecaccd 100644 --- a/html/form.html +++ b/html/form.html @@ -48,6 +48,24 @@ {{ end }} + {{ if .matrixEnabled }} + + {{ end }} @@ -84,7 +102,10 @@ {{ if .discordEnabled }} {{ .strings.linkDiscord }} {{ end }} - {{ if or (.telegramEnabled) (.discordEnabled) }} + {{ if .matrixEnabled }} + {{ .strings.linkMatrix }} + {{ end }} + {{ if or (.telegramEnabled) (or .discordEnabled .matrixEnabled) }}
{{ end }} + {{ if .matrixEnabled }} + + {{ end }}
{{ end }} diff --git a/lang/common/en-us.json b/lang/common/en-us.json index 3e9ef53..5f8ec44 100644 --- a/lang/common/en-us.json +++ b/lang/common/en-us.json @@ -8,6 +8,7 @@ "emailAddress": "Email Address", "name": "Name", "submit": "Submit", + "send": "Send", "success": "Success", "error": "Error", "copy": "Copy", @@ -18,6 +19,7 @@ "contactEmail": "Contact through Email", "contactTelegram": "Contact through Telegram", "linkDiscord": "Link Discord", + "linkMatrix": "Link Matrix", "contactDiscord": "Contact through Discord", "theme": "Theme" } diff --git a/lang/form/en-us.json b/lang/form/en-us.json index 6726c0b..995da7f 100644 --- a/lang/form/en-us.json +++ b/lang/form/en-us.json @@ -19,7 +19,8 @@ "confirmationRequiredMessage": "Please check your email inbox to verify your address.", "yourAccountIsValidUntil": "Your account will be valid until {date}.", "sendPIN": "Send the PIN below to the bot, then come back here to link your account.", - "sendPINDiscord": "Type {command} in {server_channel} on Discord, then send the PIN below via DM to the bot." + "sendPINDiscord": "Type {command} in {server_channel} on Discord, then send the PIN below via DM to the bot.", + "matrixEnterUser": "Enter your User ID, press submit, and a PIN will be sent to you. Enter it here to continue." }, "notifications": { "errorUserExists": "User already exists.", @@ -27,6 +28,7 @@ "errorTelegramVerification": "Telegram verification required.", "errorDiscordVerification": "Discord verification required.", "errorInvalidPIN": "PIN is invalid.", + "errorUnknown": "Unknown error.", "verified": "Account verified." }, "validationStrings": { diff --git a/lang/telegram/en-us.json b/lang/telegram/en-us.json index 642399f..e93aed7 100644 --- a/lang/telegram/en-us.json +++ b/lang/telegram/en-us.json @@ -4,6 +4,7 @@ }, "strings": { "startMessage": "Hi!\nEnter your Jellyfin PIN code here to verify your account.", + "matrixStartMessage": "Hi\nEnter the below PIN in the Jellyfin sign-up page to verify your account.", "invalidPIN": "That PIN was invalid, try again.", "pinSuccess": "Success! You can now return to the sign-up page.", "languageMessage": "Note: See available languages with {command}, and set language with {command} ." diff --git a/main.go b/main.go index fa4749d..b9a1483 100644 --- a/main.go +++ b/main.go @@ -100,6 +100,7 @@ type appContext struct { email *Emailer telegram *TelegramDaemon discord *DiscordDaemon + matrix *MatrixDaemon info, debug, err logger.Logger host string port int @@ -590,6 +591,16 @@ func start(asDaemon, firstCall bool) { defer app.discord.Shutdown() } } + if matrixEnabled { + app.matrix, err = newMatrixDaemon(app) + if err != nil { + app.err.Printf("Failed to initialize Matrix daemon: %v", err) + matrixEnabled = false + } else { + go app.matrix.run() + defer app.matrix.Shutdown() + } + } } else { debugMode = false address = "0.0.0.0:8056" diff --git a/matrix.go b/matrix.go new file mode 100644 index 0000000..1d004b5 --- /dev/null +++ b/matrix.go @@ -0,0 +1,133 @@ +package main + +import ( + "encoding/json" + + "github.com/matrix-org/gomatrix" +) + +type MatrixDaemon struct { + Stopped bool + ShutdownChannel chan string + bot *gomatrix.Client + userID string + tokens map[string]UnverifiedUser // Map of tokens to users + languages map[string]string // Map of roomIDs to language codes + app *appContext +} + +type UnverifiedUser struct { + Verified bool + User *MatrixUser +} + +type MatrixUser struct { + RoomID string + UserID string + Lang string + Contact bool +} + +var matrixFilter = gomatrix.Filter{ + Room: gomatrix.RoomFilter{ + Timeline: gomatrix.FilterPart{ + Types: []string{ + "m.room.message", + "m.room.member", + }, + }, + }, + EventFields: []string{ + "type", + "event_id", + "room_id", + "state_key", + "sender", + "content.body", + "content.membership", + }, +} + +func newMatrixDaemon(app *appContext) (d *MatrixDaemon, err error) { + matrix := app.config.Section("matrix") + homeserver := matrix.Key("homeserver").String() + token := matrix.Key("token").String() + d = &MatrixDaemon{ + ShutdownChannel: make(chan string), + userID: matrix.Key("user_id").String(), + tokens: map[string]UnverifiedUser{}, + languages: map[string]string{}, + app: app, + } + d.bot, err = gomatrix.NewClient(homeserver, d.userID, token) + if err != nil { + return + } + filter, err := json.Marshal(matrixFilter) + if err != nil { + return + } + resp, err := d.bot.CreateFilter(filter) + d.bot.Store.SaveFilterID(d.userID, resp.FilterID) + for _, user := range app.storage.matrix { + if user.Lang != "" { + d.languages[user.RoomID] = user.Lang + } + } + return +} + +func (d *MatrixDaemon) run() { + d.app.info.Println("Starting Matrix bot daemon") + syncer := d.bot.Syncer.(*gomatrix.DefaultSyncer) + syncer.OnEventType("m.room.message", d.handleMessage) + // syncer.OnEventType("m.room.member", d.handleMembership) + if err := d.bot.Sync(); err != nil { + d.app.err.Printf("Matrix sync failed: %v", err) + } +} + +func (d *MatrixDaemon) Shutdown() { + d.bot.StopSync() + d.Stopped = true + close(d.ShutdownChannel) +} + +func (d *MatrixDaemon) handleMessage(event *gomatrix.Event) { return } + +func (d *MatrixDaemon) SendStart(userID string) (ok bool) { + room, err := d.bot.CreateRoom(&gomatrix.ReqCreateRoom{ + Visibility: "private", + Invite: []string{userID}, + Topic: "jfa-go", + }) + if err != nil { + d.app.err.Printf("Failed to create room for user \"%s\": %v", userID, err) + return + } + lang := "en-us" + pin := genAuthToken() + d.tokens[pin] = UnverifiedUser{ + false, + &MatrixUser{ + RoomID: room.RoomID, + UserID: userID, + Lang: lang, + }, + } + _, err = d.bot.SendText( + room.RoomID, + d.app.storage.lang.Telegram[lang].Strings.get("matrixStartMessage")+"\n\n"+pin+"\n\n"+ + d.app.storage.lang.Telegram[lang].Strings.template("languageMessage", tmpl{"command": "!lang"}), + ) + if err != nil { + d.app.err.Printf("Matrix: Failed to send welcome message to \"%s\": %v", userID, err) + return + } + ok = true + return +} + +// User enters ID on sign-up, a PIN is sent to them. They enter it on sign-up. + +// Message the user first, to avoid E2EE by default diff --git a/models.go b/models.go index e14030d..a5b2ae6 100644 --- a/models.go +++ b/models.go @@ -281,3 +281,10 @@ type DiscordInviteDTO struct { InviteURL string `json:"invite"` IconURL string `json:"icon"` } + +type MatrixSendPINDTO struct { + UserID string `json:"user_id"` +} +type MatrixCheckPINDTO struct { + PIN string `json:"pin"` +} diff --git a/router.go b/router.go index a717d49..9b14672 100644 --- a/router.go +++ b/router.go @@ -127,6 +127,10 @@ func (app *appContext) loadRoutes(router *gin.Engine) { router.GET(p+"/invite/:invCode/discord/invite", app.DiscordServerInvite) } } + if matrixEnabled { + router.GET(p+"/invite/:invCode/matrix/verified/:userID/:pin", app.MatrixCheckPIN) + router.POST(p+"/invite/:invCode/matrix/user", app.MatrixSendPIN) + } } if *SWAGGER { app.info.Print(warning("\n\nWARNING: Swagger should not be used on a public instance.\n\n")) diff --git a/storage.go b/storage.go index c32fb75..ae2022a 100644 --- a/storage.go +++ b/storage.go @@ -15,21 +15,22 @@ import ( ) type Storage struct { - timePattern string - invite_path, emails_path, policy_path, configuration_path, displayprefs_path, ombi_path, profiles_path, customEmails_path, users_path, telegram_path, discord_path string - users map[string]time.Time - invites Invites - profiles map[string]Profile - defaultProfile string - displayprefs, ombi_template map[string]interface{} - emails map[string]EmailAddress - telegram map[string]TelegramUser // Map of Jellyfin User IDs to telegram users. - discord map[string]DiscordUser // Map of Jellyfin user IDs to discord users. - customEmails customEmails - policy mediabrowser.Policy - configuration mediabrowser.Configuration - lang Lang - invitesLock, usersLock sync.Mutex + timePattern string + invite_path, emails_path, policy_path, configuration_path, displayprefs_path, ombi_path, profiles_path, customEmails_path, users_path, telegram_path, discord_path, matrix_path string + users map[string]time.Time + invites Invites + profiles map[string]Profile + defaultProfile string + displayprefs, ombi_template map[string]interface{} + emails map[string]EmailAddress + telegram map[string]TelegramUser // Map of Jellyfin User IDs to telegram users. + discord map[string]DiscordUser // Map of Jellyfin user IDs to discord users. + matrix map[string]MatrixUser // Map of Jellyfin user IDs to Matrix users. + customEmails customEmails + policy mediabrowser.Policy + configuration mediabrowser.Configuration + lang Lang + invitesLock, usersLock sync.Mutex } type TelegramUser struct { @@ -790,6 +791,14 @@ func (st *Storage) storeDiscordUsers() error { return storeJSON(st.discord_path, st.discord) } +func (st *Storage) loadMatrixUsers() error { + return loadJSON(st.matrix_path, &st.matrix) +} + +func (st *Storage) storeMatrixUsers() error { + return storeJSON(st.matrix_path, st.matrix) +} + func (st *Storage) loadCustomEmails() error { return loadJSON(st.customEmails_path, &st.customEmails) } diff --git a/telegram.go b/telegram.go index 4cca16f..654d05b 100644 --- a/telegram.go +++ b/telegram.go @@ -58,7 +58,7 @@ func genAuthToken() string { rand.Seed(time.Now().UnixNano()) pin := make([]rune, 8) for i := range pin { - if i == 2 || i == 5 { + if (i+1)%3 == 0 { pin[i] = '-' } else { pin[i] = runes[rand.Intn(len(runes))] diff --git a/ts/form.ts b/ts/form.ts index 94d3874..b3b0815 100644 --- a/ts/form.ts +++ b/ts/form.ts @@ -1,6 +1,6 @@ import { Modal } from "./modules/modal.js"; import { notificationBox, whichAnimationEvent } from "./modules/common.js"; -import { _get, _post, toggleLoader, toDateString } from "./modules/common.js"; +import { _get, _post, toggleLoader, addLoader, removeLoader, toDateString } from "./modules/common.js"; import { loadLangSelector } from "./modules/lang.js"; interface formWindow extends Window { @@ -9,6 +9,7 @@ interface formWindow extends Window { successModal: Modal; telegramModal: Modal; discordModal: Modal; + matrixModal: Modal; confirmationModal: Modal code: string; messages: { [key: string]: string }; @@ -20,6 +21,8 @@ interface formWindow extends Window { discordStartCommand: string; discordInviteLink: boolean; discordServerName: string; + matrixRequired: boolean; + matrixUserID: string; userExpiryEnabled: boolean; userExpiryMonths: number; userExpiryDays: number; @@ -150,6 +153,69 @@ if (window.discordEnabled) { }; } +var matrixVerified = false; +var matrixPIN = ""; +if (window.matrixEnabled) { + window.matrixModal = new Modal(document.getElementById("modal-matrix"), window.matrixRequired); + const matrixButton = document.getElementById("link-matrix") as HTMLSpanElement; + matrixButton.onclick = window.matrixModal.show; + const submitButton = document.getElementById("matrix-send") as HTMLSpanElement; + const input = document.getElementById("matrix-userid") as HTMLInputElement; + let userID = ""; + submitButton.onclick = () => { + addLoader(submitButton); + if (userID == "") { + const send = { + user_id: input.value + }; + _post("/invite/" + window.code + "/matrix/user", send, (req: XMLHttpRequest) => { + if (req.readyState == 4) { + removeLoader(submitButton); + userID = input.value; + if (req.status != 200) { + window.notifications.customError("errorUnknown", window.messages["errorUnknown"]); + window.matrixModal.close(); + return; + } + submitButton.classList.add("~positive"); + submitButton.classList.remove("~info"); + setTimeout(() => { + submitButton.classList.add("~info"); + submitButton.classList.remove("~positive"); + }, 2000); + input.placeholder = "PIN"; + input.value = ""; + } + }); + } else { + _get("/invite/" + window.code + "/matrix/verified/" + userID + "/" + input.value, null, (req: XMLHttpRequest) => { + if (req.readyState == 4) { + removeLoader(submitButton) + const valid = req.response["success"] as boolean; + if (valid) { + window.matrixModal.close(); + window.notifications.customPositive("successVerified", "", window.messages["verified"]); + matrixVerified = true; + matrixPIN = input.value; + matrixButton.classList.add("unfocused"); + document.getElementById("contact-via").classList.remove("unfocused"); + const radio = document.getElementById("contact-via-discord") as HTMLInputElement; + radio.checked = true; + } else { + window.notifications.customError("errorInvalidPIN", window.messages["errorInvalidPIN"]); + submitButton.classList.add("~critical"); + submitButton.classList.remove("~info"); + setTimeout(() => { + submitButton.classList.add("~info"); + submitButton.classList.remove("~critical"); + }, 800); + } + } + },); + } + }; +} + if (window.confirmation) { window.confirmationModal = new Modal(document.getElementById("modal-confirmation"), true); } @@ -229,6 +295,8 @@ interface sendDTO { telegram_contact?: boolean; discord_pin?: string; discord_contact?: boolean; + matrix_pin?: string; + matrix_contact?: boolean; } const create = (event: SubmitEvent) => { @@ -254,6 +322,13 @@ const create = (event: SubmitEvent) => { send.discord_contact = true; } } + if (matrixVerified) { + send.matrix_pin = matrixPIN; + const radio = document.getElementById("contact-via-matrix") as HTMLInputElement; + if (radio.checked) { + send.matrix_contact = true; + } + } _post("/newUser", send, (req: XMLHttpRequest) => { if (req.readyState == 4) { let vals = req.response as respDTO; diff --git a/ts/modules/common.ts b/ts/modules/common.ts index f761a4c..05b6bcb 100644 --- a/ts/modules/common.ts +++ b/ts/modules/common.ts @@ -105,7 +105,11 @@ export class notificationBox implements NotificationBox { private _error = (message: string): HTMLElement => { const noti = document.createElement('aside'); noti.classList.add("aside", "~critical", "!normal", "mt-half", "notification-error"); - noti.innerHTML = `${window.lang.strings("error")}: ${message}`; + let error = ""; + if (window.lang) { + error = window.lang.strings("error") + ":" + } + noti.innerHTML = `${error} ${message}`; const closeButton = document.createElement('span') as HTMLSpanElement; closeButton.classList.add("button", "~critical", "!low", "ml-1"); closeButton.innerHTML = ``; diff --git a/ts/typings/d.ts b/ts/typings/d.ts index eb5be55..785db4d 100644 --- a/ts/typings/d.ts +++ b/ts/typings/d.ts @@ -22,6 +22,7 @@ declare interface Window { emailEnabled: boolean; telegramEnabled: boolean; discordEnabled: boolean; + matrixEnabled: boolean; ombiEnabled: boolean; usernameEnabled: boolean; token: string; diff --git a/views.go b/views.go index 6d8e306..f463fd9 100644 --- a/views.go +++ b/views.go @@ -287,6 +287,7 @@ func (app *appContext) InviteProxy(gc *gin.Context) { "langName": lang, "telegramEnabled": telegramEnabled, "discordEnabled": discordEnabled, + "matrixEnabled": matrixEnabled, } if telegramEnabled { data["telegramPIN"] = app.telegram.NewAuthToken() @@ -294,6 +295,10 @@ func (app *appContext) InviteProxy(gc *gin.Context) { data["telegramURL"] = app.telegram.link data["telegramRequired"] = app.config.Section("telegram").Key("required").MustBool(false) } + if matrixEnabled { + data["matrixRequired"] = app.config.Section("matrix").Key("required").MustBool(false) + data["matrixUser"] = app.matrix.userID + } if discordEnabled { data["discordPIN"] = app.discord.NewAuthToken() data["discordUsername"] = app.discord.username