mirror of
https://github.com/hrfee/jfa-go.git
synced 2024-12-22 09:00:10 +00:00
Matrix: Add token generation wizard
Pressing the "+" next to matrix in settings allows you to enter a homeserver, username and password to enable matrix and generate an access token.
This commit is contained in:
parent
75fdf6ec3d
commit
375022ba95
43
api.go
43
api.go
@ -1550,6 +1550,7 @@ func (app *appContext) GetConfig(gc *gin.Context) {
|
|||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param appConfig body configDTO true "Config split into sections as in config.ini, all values as strings."
|
// @Param appConfig body configDTO true "Config split into sections as in config.ini, all values as strings."
|
||||||
// @Success 200 {object} boolResponse
|
// @Success 200 {object} boolResponse
|
||||||
|
// @Failure 500 {object} boolResponse
|
||||||
// @Router /config [post]
|
// @Router /config [post]
|
||||||
// @Security Bearer
|
// @Security Bearer
|
||||||
// @tags Configuration
|
// @tags Configuration
|
||||||
@ -1575,7 +1576,11 @@ func (app *appContext) ModifyConfig(gc *gin.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tempConfig.SaveTo(app.configPath)
|
if err := tempConfig.SaveTo(app.configPath); err != nil {
|
||||||
|
app.err.Printf("Failed to save config to \"%s\": %v", app.configPath, err)
|
||||||
|
respondBool(500, false, gc)
|
||||||
|
return
|
||||||
|
}
|
||||||
app.debug.Println("Config saved")
|
app.debug.Println("Config saved")
|
||||||
gc.JSON(200, map[string]bool{"success": true})
|
gc.JSON(200, map[string]bool{"success": true})
|
||||||
if req["restart-program"] != nil && req["restart-program"].(bool) {
|
if req["restart-program"] != nil && req["restart-program"].(bool) {
|
||||||
@ -2367,6 +2372,42 @@ func (app *appContext) MatrixCheckPIN(gc *gin.Context) {
|
|||||||
respondBool(200, true, gc)
|
respondBool(200, true, gc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Summary Generates a Matrix access token from a username and password.
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} boolResponse
|
||||||
|
// @Failure 400 {object} stringResponse
|
||||||
|
// @Failure 401 {object} boolResponse
|
||||||
|
// @Failure 500 {object} boolResponse
|
||||||
|
// @Param MatrixLoginDTO body MatrixLoginDTO true "Username & password."
|
||||||
|
// @Router /matrix/login [post]
|
||||||
|
// @tags Other
|
||||||
|
func (app *appContext) MatrixLogin(gc *gin.Context) {
|
||||||
|
var req MatrixLoginDTO
|
||||||
|
gc.BindJSON(&req)
|
||||||
|
if req.Username == "" || req.Password == "" {
|
||||||
|
respond(400, "errorLoginBlank", gc)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
token, err := app.matrix.generateAccessToken(req.Homeserver, req.Username, req.Password)
|
||||||
|
if err != nil {
|
||||||
|
app.err.Printf("Matrix: Failed to generate token: %v", err)
|
||||||
|
respond(401, "Unauthorized", gc)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tempConfig, _ := ini.Load(app.configPath)
|
||||||
|
matrix := tempConfig.Section("matrix")
|
||||||
|
matrix.Key("enabled").SetValue("true")
|
||||||
|
matrix.Key("homeserver").SetValue(req.Homeserver)
|
||||||
|
matrix.Key("token").SetValue(token)
|
||||||
|
matrix.Key("user_id").SetValue(req.Username)
|
||||||
|
if err := tempConfig.SaveTo(app.configPath); err != nil {
|
||||||
|
app.err.Printf("Failed to save config to \"%s\": %v", app.configPath, err)
|
||||||
|
respondBool(500, false, gc)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
respondBool(200, true, gc)
|
||||||
|
}
|
||||||
|
|
||||||
// @Summary Links a Matrix user to a Jellyfin account via user IDs. Notifications are turned on by default.
|
// @Summary Links a Matrix user to a Jellyfin account via user IDs. Notifications are turned on by default.
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} boolResponse
|
// @Success 200 {object} boolResponse
|
||||||
|
@ -341,6 +341,19 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
<div id="modal-matrix" class="modal">
|
||||||
|
<form class="modal-content card" id="form-matrix" href="">
|
||||||
|
<span class="heading">{{ .strings.linkMatrix }}</span>
|
||||||
|
<p class="content">{{ .strings.linkMatrixDescription }}</p>
|
||||||
|
<input type="text" class="field input ~neutral !high mt-half mb-1" placeholder="{{ .strings.matrixHomeServer }}" id="matrix-homeserver">
|
||||||
|
<input type="text" class="field input ~neutral !high mt-half mb-1" placeholder="{{ .strings.username }}" id="matrix-user">
|
||||||
|
<input type="password" class="field input ~neutral !high mt-half mb-1" placeholder="{{ .strings.password }}" id="matrix-password">
|
||||||
|
<label>
|
||||||
|
<input type="submit" class="unfocused">
|
||||||
|
<span class="button ~urge !normal full-width center supra submit">{{ .strings.submit }}</span>
|
||||||
|
</label>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
<div id="notification-box"></div>
|
<div id="notification-box"></div>
|
||||||
<span class="dropdown" tabindex="0" id="lang-dropdown">
|
<span class="dropdown" tabindex="0" id="lang-dropdown">
|
||||||
<span class="button ~urge dropdown-button">
|
<span class="button ~urge dropdown-button">
|
||||||
|
@ -98,7 +98,9 @@
|
|||||||
"notifyUserCreation": "On user creation",
|
"notifyUserCreation": "On user creation",
|
||||||
"sendPIN": "Ask the user to send the PIN below to the bot.",
|
"sendPIN": "Ask the user to send the PIN below to the bot.",
|
||||||
"searchDiscordUser": "Start typing the Discord username to find the user.",
|
"searchDiscordUser": "Start typing the Discord username to find the user.",
|
||||||
"findDiscordUser": "Find Discord user"
|
"findDiscordUser": "Find Discord user",
|
||||||
|
"linkMatrixDescription": "Enter the username and password of the user to use as a bot. Once submitted, the app will restart.",
|
||||||
|
"matrixHomeServer": "Home server address"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"changedEmailAddress": "Changed email address of {n}.",
|
"changedEmailAddress": "Changed email address of {n}.",
|
||||||
|
28
matrix.go
28
matrix.go
@ -31,6 +31,13 @@ type MatrixUser struct {
|
|||||||
Contact bool
|
Contact bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MatrixIdentifier struct {
|
||||||
|
User string `json:"user"`
|
||||||
|
IdentType string `json:"type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m MatrixIdentifier) Type() string { return m.IdentType }
|
||||||
|
|
||||||
var matrixFilter = gomatrix.Filter{
|
var matrixFilter = gomatrix.Filter{
|
||||||
Room: gomatrix.RoomFilter{
|
Room: gomatrix.RoomFilter{
|
||||||
Timeline: gomatrix.FilterPart{
|
Timeline: gomatrix.FilterPart{
|
||||||
@ -80,6 +87,27 @@ func newMatrixDaemon(app *appContext) (d *MatrixDaemon, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *MatrixDaemon) generateAccessToken(homeserver, username, password string) (string, error) {
|
||||||
|
req := &gomatrix.ReqLogin{
|
||||||
|
Type: "m.login.password",
|
||||||
|
Identifier: MatrixIdentifier{
|
||||||
|
User: username,
|
||||||
|
IdentType: "m.id.user",
|
||||||
|
},
|
||||||
|
Password: password,
|
||||||
|
DeviceID: "jfa-go-" + commit,
|
||||||
|
}
|
||||||
|
bot, err := gomatrix.NewClient(homeserver, username, "")
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
resp, err := bot.Login(req)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return resp.AccessToken, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (d *MatrixDaemon) run() {
|
func (d *MatrixDaemon) run() {
|
||||||
d.app.info.Println("Starting Matrix bot daemon")
|
d.app.info.Println("Starting Matrix bot daemon")
|
||||||
syncer := d.bot.Syncer.(*gomatrix.DefaultSyncer)
|
syncer := d.bot.Syncer.(*gomatrix.DefaultSyncer)
|
||||||
|
@ -299,3 +299,9 @@ type MatrixConnectUserDTO struct {
|
|||||||
JellyfinID string `json:"jf_id"`
|
JellyfinID string `json:"jf_id"`
|
||||||
UserID string `json:"user_id"`
|
UserID string `json:"user_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MatrixLoginDTO struct {
|
||||||
|
Homeserver string `json:"homeserver"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
}
|
||||||
|
@ -169,7 +169,7 @@ func (app *appContext) loadRoutes(router *gin.Engine) {
|
|||||||
api.GET(p+"/config", app.GetConfig)
|
api.GET(p+"/config", app.GetConfig)
|
||||||
api.POST(p+"/config", app.ModifyConfig)
|
api.POST(p+"/config", app.ModifyConfig)
|
||||||
api.POST(p+"/restart", app.restart)
|
api.POST(p+"/restart", app.restart)
|
||||||
if telegramEnabled || discordEnabled {
|
if telegramEnabled || discordEnabled || matrixEnabled {
|
||||||
api.GET(p+"/telegram/pin", app.TelegramGetPin)
|
api.GET(p+"/telegram/pin", app.TelegramGetPin)
|
||||||
api.GET(p+"/telegram/verified/:pin", app.TelegramVerified)
|
api.GET(p+"/telegram/verified/:pin", app.TelegramVerified)
|
||||||
api.POST(p+"/users/telegram", app.TelegramAddUser)
|
api.POST(p+"/users/telegram", app.TelegramAddUser)
|
||||||
@ -183,6 +183,8 @@ func (app *appContext) loadRoutes(router *gin.Engine) {
|
|||||||
api.GET(p+"/ombi/users", app.OmbiUsers)
|
api.GET(p+"/ombi/users", app.OmbiUsers)
|
||||||
api.POST(p+"/ombi/defaults", app.SetOmbiDefaults)
|
api.POST(p+"/ombi/defaults", app.SetOmbiDefaults)
|
||||||
}
|
}
|
||||||
|
api.POST(p+"/matrix/login", app.MatrixLogin)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,6 +63,8 @@ window.availableProfiles = window.availableProfiles || [];
|
|||||||
|
|
||||||
window.modals.updateInfo = new Modal(document.getElementById("modal-update"));
|
window.modals.updateInfo = new Modal(document.getElementById("modal-update"));
|
||||||
|
|
||||||
|
window.modals.matrix = new Modal(document.getElementById("modal-matrix"));
|
||||||
|
|
||||||
if (window.telegramEnabled) {
|
if (window.telegramEnabled) {
|
||||||
window.modals.telegram = new Modal(document.getElementById("modal-telegram"));
|
window.modals.telegram = new Modal(document.getElementById("modal-telegram"));
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { _get, _post, toggleLoader } from "../modules/common.js";
|
import { _get, _post, toggleLoader, addLoader, removeLoader } from "../modules/common.js";
|
||||||
import { Marked } from "@ts-stack/markdown";
|
import { Marked } from "@ts-stack/markdown";
|
||||||
import { stripMarkdown } from "../modules/stripmd.js";
|
import { stripMarkdown } from "../modules/stripmd.js";
|
||||||
|
|
||||||
@ -666,6 +666,40 @@ export class settingsList {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _addMatrix = () => {
|
||||||
|
// Modify the login modal, why not
|
||||||
|
const modal = document.getElementById("form-matrix") as HTMLFormElement;
|
||||||
|
modal.onsubmit = (event: Event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
const button = modal.querySelector("span.submit") as HTMLSpanElement;
|
||||||
|
addLoader(button);
|
||||||
|
let send = {
|
||||||
|
homeserver: (document.getElementById("matrix-homeserver") as HTMLInputElement).value,
|
||||||
|
username: (document.getElementById("matrix-user") as HTMLInputElement).value,
|
||||||
|
password: (document.getElementById("matrix-password") as HTMLInputElement).value
|
||||||
|
}
|
||||||
|
_post("/matrix/login", send, (req: XMLHttpRequest) => {
|
||||||
|
if (req.readyState == 4) {
|
||||||
|
removeLoader(button);
|
||||||
|
if (req.status == 400) {
|
||||||
|
window.notifications.customError("errorUnknown", window.lang.notif(req.response["error"] as string));
|
||||||
|
return;
|
||||||
|
} else if (req.status == 401) {
|
||||||
|
window.notifications.customError("errorUnauthorized", req.response["error"] as string);
|
||||||
|
return;
|
||||||
|
} else if (req.status == 500) {
|
||||||
|
window.notifications.customError("errorAddMatrix", window.lang.notif("errorFailureCheckLogs"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
window.modals.matrix.close();
|
||||||
|
_post("/restart", null, () => {});
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
}, true);
|
||||||
|
};
|
||||||
|
window.modals.matrix.show();
|
||||||
|
}
|
||||||
|
|
||||||
reload = () => _get("/config", null, (req: XMLHttpRequest) => {
|
reload = () => _get("/config", null, (req: XMLHttpRequest) => {
|
||||||
if (req.readyState == 4) {
|
if (req.readyState == 4) {
|
||||||
if (req.status != 200) {
|
if (req.status != 200) {
|
||||||
@ -698,6 +732,17 @@ export class settingsList {
|
|||||||
icon.onclick = () => window.updater.checkForUpdates(window.modals.updateInfo.show);
|
icon.onclick = () => window.updater.checkForUpdates(window.modals.updateInfo.show);
|
||||||
}
|
}
|
||||||
this.addSection(name, settings.sections[name], icon);
|
this.addSection(name, settings.sections[name], icon);
|
||||||
|
} else if (name == "matrix" && !window.matrixEnabled) {
|
||||||
|
const addButton = document.createElement("div");
|
||||||
|
addButton.classList.add("tooltip", "left");
|
||||||
|
addButton.innerHTML = `
|
||||||
|
<span class="button ~neutral !normal">+</span>
|
||||||
|
<span class="content sm">
|
||||||
|
${window.lang.strings("linkMatrix")}
|
||||||
|
</span>
|
||||||
|
`;
|
||||||
|
(addButton.querySelector("span.button") as HTMLSpanElement).onclick = this._addMatrix;
|
||||||
|
this.addSection(name, settings.sections[name], addButton);
|
||||||
} else {
|
} else {
|
||||||
this.addSection(name, settings.sections[name]);
|
this.addSection(name, settings.sections[name]);
|
||||||
}
|
}
|
||||||
|
@ -104,6 +104,7 @@ declare interface Modals {
|
|||||||
updateInfo: Modal;
|
updateInfo: Modal;
|
||||||
telegram: Modal;
|
telegram: Modal;
|
||||||
discord: Modal;
|
discord: Modal;
|
||||||
|
matrix: Modal;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Invite {
|
interface Invite {
|
||||||
|
Loading…
Reference in New Issue
Block a user