diff --git a/api-userpage.go b/api-userpage.go index b63199d..4a84949 100644 --- a/api-userpage.go +++ b/api-userpage.go @@ -10,7 +10,7 @@ import ( "github.com/golang-jwt/jwt" ) -// @Summary Returns the logged-in user's Jellyfin ID & Username. +// @Summary Returns the logged-in user's Jellyfin ID & Username, and other details. // @Produce json // @Success 200 {object} MyDetailsDTO // @Router /my/details [get] @@ -379,3 +379,73 @@ func (app *appContext) MyTelegramVerifiedInvite(gc *gin.Context) { app.storage.SetTelegramKey(gc.GetString("jfId"), tgUser) respondBool(200, true, gc) } + +// @Summary Generate and send a new PIN to your given matrix user. +// @Produce json +// @Success 200 {object} boolResponse +// @Failure 400 {object} stringResponse +// @Failure 401 {object} boolResponse +// @Failure 500 {object} boolResponse +// @Param MatrixSendPINDTO body MatrixSendPINDTO true "User's Matrix ID." +// @Router /my/matrix/user [post] +// @tags User Page +func (app *appContext) MatrixSendMyPIN(gc *gin.Context) { + var req MatrixSendPINDTO + gc.BindJSON(&req) + if req.UserID == "" { + respond(400, "errorNoUserID", gc) + return + } + if app.config.Section("matrix").Key("require_unique").MustBool(false) { + for _, u := range app.storage.GetMatrix() { + if req.UserID == u.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 your matrix PIN is valid, and link the account to yours if so. +// @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 /my/matrix/verified/{userID}/{pin} [get] +// @tags User Page +func (app *appContext) MatrixCheckMyPIN(gc *gin.Context) { + 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 + } + + mxUser := *user.User + mxUser.Contact = true + existingUser, ok := app.storage.GetMatrixKey(gc.GetString("jfId")) + if ok { + mxUser.Lang = existingUser.Lang + mxUser.Contact = existingUser.Contact + } + + app.storage.SetMatrixKey(gc.GetString("jfId"), mxUser) + delete(app.matrix.tokens, pin) + respondBool(200, true, gc) +} diff --git a/router.go b/router.go index b1b5b95..18e3814 100644 --- a/router.go +++ b/router.go @@ -235,6 +235,8 @@ func (app *appContext) loadRoutes(router *gin.Engine) { user.GET(p+"/pin/:service", app.GetMyPIN) user.GET(p+"/discord/verified/:pin", app.MyDiscordVerifiedInvite) user.GET(p+"/telegram/verified/:pin", app.MyTelegramVerifiedInvite) + user.POST(p+"/matrix/user", app.MatrixSendMyPIN) + user.POST(p+"/matrix/verified/:userID/:pin", app.MatrixCheckMyPIN) } } } diff --git a/storage.go b/storage.go index 605516e..d24b960 100644 --- a/storage.go +++ b/storage.go @@ -63,6 +63,7 @@ func (st *Storage) SetEmailsKey(k string, v EmailAddress) { func (st *Storage) DeleteEmailsKey(k string) { st.emailsLock.Lock() delete(st.emails, k) + st.storeEmails() st.emailsLock.Unlock() } @@ -89,6 +90,7 @@ func (st *Storage) SetDiscordKey(k string, v DiscordUser) { func (st *Storage) DeleteDiscordKey(k string) { st.discordLock.Lock() delete(st.discord, k) + st.storeDiscordUsers() st.discordLock.Unlock() } @@ -115,6 +117,7 @@ func (st *Storage) SetTelegramKey(k string, v TelegramUser) { func (st *Storage) DeleteTelegramKey(k string) { st.telegramLock.Lock() delete(st.telegram, k) + st.storeTelegramUsers() st.telegramLock.Unlock() } @@ -141,6 +144,7 @@ func (st *Storage) SetMatrixKey(k string, v MatrixUser) { func (st *Storage) DeleteMatrixKey(k string) { st.matrixLock.Lock() delete(st.matrix, k) + st.storeMatrixUsers() st.matrixLock.Unlock() } diff --git a/ts/form.ts b/ts/form.ts index 3722c23..961de8a 100644 --- a/ts/form.ts +++ b/ts/form.ts @@ -121,6 +121,7 @@ if (window.matrixEnabled) { verifiedURL: "/invite/" + window.code + "/matrix/verified/", invalidCodeError: window.messages["errorInvalidPIN"], accountLinkedError: window.messages["errorAccountLinked"], + unknownError: window.messages["errorUnknown"], successError: window.messages["verified"], successFunc: () => { matrixVerified = true; diff --git a/ts/modules/account-linking.ts b/ts/modules/account-linking.ts index d14fcbb..ea3994f 100644 --- a/ts/modules/account-linking.ts +++ b/ts/modules/account-linking.ts @@ -188,7 +188,7 @@ export class Matrix { private _conf: MatrixConfiguration; private _verified = false; private _name: string = "matrix"; - private _userID: string; + private _userID: string = ""; private _pin: string = ""; private _input: HTMLInputElement; private _submit: HTMLSpanElement; @@ -212,7 +212,10 @@ export class Matrix { } }; - show = () => { this._conf.modal.show(); } + show = () => { + this._input.value = ""; + this._conf.modal.show(); + } private _sendMessage = () => _post(this._conf.sendMessageURL, { "user_id": this._input.value }, (req: XMLHttpRequest) => { if (req.readyState != 4) return; @@ -258,6 +261,6 @@ export class Matrix { this._submit.classList.remove("~critical"); }, 800); } - }); + }, true); } diff --git a/ts/user.ts b/ts/user.ts index 7c334d8..1983d66 100644 --- a/ts/user.ts +++ b/ts/user.ts @@ -3,7 +3,7 @@ import { lang, LangFile, loadLangSelector } from "./modules/lang.js"; import { Modal } from "./modules/modal.js"; import { _get, _post, notificationBox, whichAnimationEvent, toDateString, toggleLoader } from "./modules/common.js"; import { Login } from "./modules/login.js"; -import { Discord, Telegram, ServiceConfiguration } from "./modules/account-linking.js"; +import { Discord, Telegram, Matrix, ServiceConfiguration, MatrixConfiguration } from "./modules/account-linking.js"; interface userWindow extends Window { jellyfinID: string; @@ -316,6 +316,22 @@ const telegramConf: ServiceConfiguration = { let telegram = new Telegram(telegramConf); +const matrixConf: MatrixConfiguration = { + modal: window.modals.matrix as Modal, + sendMessageURL: "/my/matrix/user", + verifiedURL: "/my/matrix/verified/", + invalidCodeError: window.lang.notif("errorInvalidPIN"), + accountLinkedError: window.lang.notif("errorAccountLinked"), + unknownError: window.lang.notif("errorUnknown"), + successError: window.lang.notif("verified"), + successFunc: () => { + setTimeout(() => window.location.reload(), 1200); + } +}; + +let matrix = new Matrix(matrixConf); + + document.addEventListener("details-reload", () => { _get("/my/details", null, (req: XMLHttpRequest) => { if (req.readyState == 4) { @@ -347,7 +363,7 @@ document.addEventListener("details-reload", () => { {name: "email", icon: ``, f: addEditEmail}, {name: "discord", icon: ``, f: (add: boolean) => { discord.onclick(); }}, {name: "telegram", icon: ``, f: (add: boolean) => { telegram.onclick() }}, - {name: "matrix", icon: `[m]`, f: null} + {name: "matrix", icon: `[m]`, f: (add: boolean) => { matrix.show(); }} ]; for (let method of contactMethods) {