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 }}
+
+
+
{{ .strings.linkMatrix }}
+
{{ .strings.matrixEnterUser }}
+
+
+
+
+
+
+
+ {{ .matrixUser }}
+
+
{{ .strings.submit }}
+
+
+ {{ 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