From aee4d17ebe948d6ae5fb50b1a7c1e25e28d83b44 Mon Sep 17 00:00:00 2001 From: "H. Shay" Date: Tue, 25 Feb 2025 15:47:28 -0800 Subject: [PATCH 1/6] add client for mas compatibility --- src/MASclient.ts | 140 +++++++++++++++++++++++++++++++++++++++++++++++ src/Mjolnir.ts | 36 +++++++++--- src/config.ts | 12 ++++ 3 files changed, 180 insertions(+), 8 deletions(-) create mode 100644 src/MASclient.ts diff --git a/src/MASclient.ts b/src/MASclient.ts new file mode 100644 index 00000000..7f113e93 --- /dev/null +++ b/src/MASclient.ts @@ -0,0 +1,140 @@ +/* +Copyright 2025 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + + +import { ClientCredentials, AccessToken } from "simple-oauth2"; +import { IConfig } from "./config"; +import axios from "axios"; +import { LogService } from "@vector-im/matrix-bot-sdk"; + +export class MASclient { + public readonly config: IConfig; + private client: ClientCredentials; + private accessToken: AccessToken; + + constructor(config: IConfig) { + LogService.info("MAS client", "Setting up mas client"); + this.config = config; + const clientConfig = { + client: { + id: config.mas.clientId, + secret: config.mas.clientSecret, + }, + auth: { + tokenPath: config.mas.url + "/oauth2/token", + tokenHost: config.mas.url, + }, + }; + this.client = new ClientCredentials(clientConfig); + } + + public async getAccessToken() { + if (!this.accessToken || this.accessToken.expired()) { + // fetch a new one + const tokenParams = { scope: "urn:mas:admin" }; + try { + this.accessToken = await this.client.getToken(tokenParams); + } catch (error) { + LogService.error("MAS client", "Error fetching auth token for MAS:", error.message); + throw error; + } + } + return this.accessToken; + } + + public async getMASUserId(userId: string): Promise { + const index = userId.indexOf(":"); + const localpart = userId.substring(1, index); + const accessToken = await this.getAccessToken(); + try { + const resp = await axios({ + method: "get", + url: this.config.mas.url + `/api/admin/v1/users/by-username/${localpart}`, + headers: { + "User-Agent": "Mjolnir", + "Content-Type": "application/json; charset=UTF-8", + "Authorization": `Bearer ${accessToken.token.access_token}`, + }, + }); + return resp.data.data.id; + } catch (error) { + LogService.error("MAS client", `Error fetching MAS id for user ${userId}:`, error.message); + throw error; + } + } + + public async deactivateMasUser(userId: string): Promise { + const masId = await this.getMASUserId(userId); + const accessToken = await this.getAccessToken(); + const url = this.config.mas.url + `/api/admin/v1/users/${masId}/deactivate`; + try { + await axios({ + method: "post", + url: url, + headers: { + "User-Agent": "Mjolnir", + "Content-Type": "application/json; charset=UTF-8", + "Authorization": `Bearer ${accessToken.token.access_token}`, + }, + }); + } catch (error) { + LogService.error("MAS client", `Error deactivating user ${userId} via MAS`, error.message); + throw error; + } + } + + public async lockMasUser(userId: string): Promise { + const masId = await this.getMASUserId(userId); + const accessToken = await this.getAccessToken(); + try { + await axios({ + method: "post", + url: this.config.mas.url + `/api/admin/v1/users/${masId}/lock`, + headers: { + "User-Agent": "Mjolnir", + "Content-Type": "application/json; charset=UTF-8", + "Authorization": `Bearer ${accessToken.token.access_token}`, + }, + }); + } catch (error) { + LogService.error("Mas client", `Error locking user ${userId} via MAS:`, error.message); + throw error; + } + } + + public async masUserIsAdmin(userId: string): Promise { + const index = userId.indexOf(":"); + const localpart = userId.substring(1, index); + const accessToken = await this.getAccessToken(); + + var resp; + try { + resp = await axios({ + method: "get", + url: this.config.mas.url + `/api/admin/v1/users/by-username/${localpart}`, + headers: { + "User-Agent": "Janitor", + "Content-Type": "application/json; charset=UTF-8", + "Authorization": `Bearer ${accessToken.token.access_token}`, + }, + }); + } catch (error) { + LogService.error("MAS client", `Error determining if MAS user ${userId} is admin: `, error.message); + throw error; + } + return resp.data.data.attributes.admin; + } +} diff --git a/src/Mjolnir.ts b/src/Mjolnir.ts index 1a19de7a..662e9b7f 100644 --- a/src/Mjolnir.ts +++ b/src/Mjolnir.ts @@ -43,6 +43,7 @@ import { MatrixEmitter, MatrixSendClient } from "./MatrixEmitter"; import { OpenMetrics } from "./webapis/OpenMetrics"; import { LRUCache } from "lru-cache"; import { ModCache } from "./ModCache"; +import { MASclient } from "./MASclient"; export const STATE_NOT_STARTED = "not_started"; export const STATE_CHECKING_PERMISSIONS = "checking_permissions"; @@ -100,6 +101,16 @@ export class Mjolnir { */ public moderators: ModCache; + /** + * Whether the Synapse Mjolnir is protecting uses the Matrix Authentication Service + */ + public readonly usingMas: boolean; + + /** + * Client for making calls to MAS (if using) + */ + public masClient: MASclient; + /** * Adds a listener to the client that will automatically accept invitations. * @param {MatrixSendClient} client @@ -214,6 +225,11 @@ export class Mjolnir { this.protectedRoomsConfig = new ProtectedRoomsConfig(client); this.policyListManager = new PolicyListManager(this); + if (config.mas.use) { + this.usingMas = true; + this.masClient = new MASclient(config); + } + // Setup bot. matrixEmitter.on("room.event", this.handleEvent.bind(this)); @@ -562,14 +578,18 @@ export class Mjolnir { } public async isSynapseAdmin(): Promise { - try { - const endpoint = `/_synapse/admin/v1/users/${await this.client.getUserId()}/admin`; - const response = await this.client.doRequest("GET", endpoint); - return response["admin"]; - } catch (e) { - LogService.error("Mjolnir", "Error determining if Mjolnir is a server admin:"); - LogService.error("Mjolnir", extractRequestError(e)); - return false; // assume not + try { + if (this.usingMas) { + return await this.masClient.masUserIsAdmin(this.clientUserId); + } else { + const endpoint = `/_synapse/admin/v1/users/${await this.client.getUserId()}/admin`; + const response = await this.client.doRequest("GET", endpoint); + return response["admin"]; + } + } catch (e) { + LogService.error("Mjolnir", "Error determining if Mjolnir is a server admin:"); + LogService.error("Mjolnir", extractRequestError(e)); + return false; // assume not } } diff --git a/src/config.ts b/src/config.ts index 8b965ecf..1c9e3868 100644 --- a/src/config.ts +++ b/src/config.ts @@ -75,6 +75,12 @@ export interface IConfig { username: string; password: string; }; + mas: { + use: boolean; + url: string; + clientId: string; + clientSecret: string; + }; pantalaimon: { use: boolean; username: string; @@ -200,6 +206,12 @@ const defaultConfig: IConfig = { username: "name", password: "pass", }, + mas: { + use: false, + url: "", + clientId: "", + clientSecret: "", + }, pantalaimon: { use: false, username: "", From 94869669233fa31487456d505514dfe37552eee3 Mon Sep 17 00:00:00 2001 From: "H. Shay" Date: Tue, 25 Feb 2025 16:50:52 -0800 Subject: [PATCH 2/6] update deactivate command to use mas --- src/commands/DeactivateCommand.ts | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/commands/DeactivateCommand.ts b/src/commands/DeactivateCommand.ts index 6b97a980..8eafc503 100644 --- a/src/commands/DeactivateCommand.ts +++ b/src/commands/DeactivateCommand.ts @@ -15,7 +15,7 @@ limitations under the License. */ import { Mjolnir } from "../Mjolnir"; -import { RichReply } from "@vector-im/matrix-bot-sdk"; +import { LogLevel, RichReply } from "@vector-im/matrix-bot-sdk"; // !mjolnir deactivate export async function execDeactivateCommand(roomId: string, event: any, mjolnir: Mjolnir, parts: string[]) { @@ -30,6 +30,20 @@ export async function execDeactivateCommand(roomId: string, event: any, mjolnir: return; } - await mjolnir.deactivateSynapseUser(target); + if (mjolnir.usingMas) { + try { + await mjolnir.masClient.deactivateMasUser(target); + } catch (err) { + mjolnir.managementRoomOutput.logMessage( + LogLevel.ERROR, + "Deactivate Command", + `There was an error deactivating ${target}, please check the logs for more information.`, + ); + await mjolnir.client.unstableApis.addReactionToEvent(roomId, event["event_id"], "❌"); + return; + } + } else { + await mjolnir.deactivateSynapseUser(target); + } await mjolnir.client.unstableApis.addReactionToEvent(roomId, event["event_id"], "✅"); } From 51f4ce1eab7a539c6dbd9b5b89afe9e69a4e7447 Mon Sep 17 00:00:00 2001 From: "H. Shay" Date: Tue, 25 Feb 2025 17:30:54 -0800 Subject: [PATCH 3/6] add mas-compatible lock/unlock command --- src/MASclient.ts | 19 +++++++++++++ src/Mjolnir.ts | 12 ++++++++ src/commands/CommandHandler.ts | 8 ++++++ src/commands/LockCommand.ts | 50 ++++++++++++++++++++++++++++++++++ src/commands/UnlockCommand.ts | 50 ++++++++++++++++++++++++++++++++++ 5 files changed, 139 insertions(+) create mode 100644 src/commands/LockCommand.ts create mode 100644 src/commands/UnlockCommand.ts diff --git a/src/MASclient.ts b/src/MASclient.ts index 7f113e93..31533b1e 100644 --- a/src/MASclient.ts +++ b/src/MASclient.ts @@ -115,6 +115,25 @@ export class MASclient { } } + public async unlockMasUser(userId: string): Promise { + const masId = await this.getMASUserId(userId); + const accessToken = await this.getAccessToken(); + try { + await axios({ + method: "post", + url: this.config.mas.url + `/api/admin/v1/users/${masId}/unlock`, + headers: { + "User-Agent": "Mjolnir", + "Content-Type": "application/json; charset=UTF-8", + "Authorization": `Bearer ${accessToken.token.access_token}`, + }, + }); + } catch (error) { + LogService.error("Mas client", `Error unlocking user ${userId} via MAS:`, error.message); + throw error; + } + } + public async masUserIsAdmin(userId: string): Promise { const index = userId.indexOf(":"); const localpart = userId.substring(1, index); diff --git a/src/Mjolnir.ts b/src/Mjolnir.ts index 662e9b7f..baf19987 100644 --- a/src/Mjolnir.ts +++ b/src/Mjolnir.ts @@ -610,6 +610,18 @@ export class Mjolnir { return await this.client.doRequest("PUT", endpoint, null, body); } + public async lockSynapseUser(userId: string): Promise { + const endpoint = `/_synapse/admin/v2/users/${userId}`; + const body = { locked: true }; + return await this.client.doRequest("PUT", endpoint, null, body); + } + + public async unlockSynapseUser(userId: string): Promise { + const endpoint = `/_synapse/admin/v2/users/${userId}`; + const body = { locked: false }; + return await this.client.doRequest("PUT", endpoint, null, body); + } + public async shutdownSynapseRoom(roomId: string, message?: string): Promise { const endpoint = `/_synapse/admin/v1/rooms/${roomId}`; return await this.client.doRequest("DELETE", endpoint, null, { diff --git a/src/commands/CommandHandler.ts b/src/commands/CommandHandler.ts index 3271df66..5d95b062 100644 --- a/src/commands/CommandHandler.ts +++ b/src/commands/CommandHandler.ts @@ -51,6 +51,8 @@ import { execSetupProtectedRoom } from "./SetupDecentralizedReportingCommand"; import { execSuspendCommand } from "./SuspendCommand"; import { execUnsuspendCommand } from "./UnsuspendCommand"; import { execIgnoreCommand, execListIgnoredCommand } from "./IgnoreCommand"; +import {execLockCommand} from "./LockCommand"; +import {execUnlockCommand} from "./UnlockCommand"; export const COMMAND_PREFIX = "!mjolnir"; @@ -146,6 +148,10 @@ export async function handleCommand(roomId: string, event: { content: { body: st return await execIgnoreCommand(roomId, event, mjolnir, parts); } else if (parts[1] === "ignored") { return await execListIgnoredCommand(roomId, event, mjolnir, parts); + } else if (parts[1] === "lock") { + return await execLockCommand(roomId, event, mjolnir, parts); + } else if (parts[1] === "unlock") { + return await execUnlockCommand(roomId, event, mjolnir, parts); } else if (parts[1] === "help") { // Help menu const protectionMenu = @@ -172,6 +178,8 @@ export async function handleCommand(roomId: string, event: { content: { body: st "!mjolnir make admin [user alias/ID] - Make the specified user or the bot itself admin of the room\n" + "!mjolnir suspend - Suspend the specified user\n" + "!mjolnir unsuspend - Unsuspend the specified user\n" + + "!mjolnir lock - Lock the account of the specified user\n" + + "!mjolnir unlock - Unlock the account of the specified user\n" + "!mjolnir ignore - Add user to list of users/servers that cannot be banned/ACL'd. Note that this does not survive restart.\n" + "!mjolnir ignored - List currently ignored entities.\n" + "!mjolnir shutdown room [message] - Uses the bot's account to shut down a room, preventing access to the room on this server\n"; diff --git a/src/commands/LockCommand.ts b/src/commands/LockCommand.ts new file mode 100644 index 00000000..5f2e5d20 --- /dev/null +++ b/src/commands/LockCommand.ts @@ -0,0 +1,50 @@ +/* +Copyright 2025 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + + +import { Mjolnir } from "../Mjolnir"; +import { LogLevel, RichReply } from "@vector-im/matrix-bot-sdk"; + +// !mjolnir lock +export async function execLockCommand(roomId: string, event: any, mjolnir: Mjolnir, parts: string[]) { + const target = parts[2]; + + const isAdmin = await mjolnir.isSynapseAdmin(); + if (!isAdmin) { + const message = "I am not a Synapse administrator, or the endpoint is blocked"; + const reply = RichReply.createFor(roomId, event, message, message); + reply["msgtype"] = "m.notice"; + mjolnir.client.sendMessage(roomId, reply); + return; + } + + if (mjolnir.usingMas) { + try { + await mjolnir.masClient.lockMasUser(target); + } catch (err) { + mjolnir.managementRoomOutput.logMessage( + LogLevel.ERROR, + "Lock Command", + `There was an error locking ${target}, please check the logs for more information.`, + ); + await mjolnir.client.unstableApis.addReactionToEvent(roomId, event["event_id"], "❌"); + return; + } + } else { + await mjolnir.lockSynapseUser(target); + } + await mjolnir.client.unstableApis.addReactionToEvent(roomId, event["event_id"], "✅"); +} \ No newline at end of file diff --git a/src/commands/UnlockCommand.ts b/src/commands/UnlockCommand.ts new file mode 100644 index 00000000..a49ab875 --- /dev/null +++ b/src/commands/UnlockCommand.ts @@ -0,0 +1,50 @@ +/* +Copyright 2025 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + + +import { Mjolnir } from "../Mjolnir"; +import { LogLevel, RichReply } from "@vector-im/matrix-bot-sdk"; + +// !mjolnir unlock +export async function execUnlockCommand(roomId: string, event: any, mjolnir: Mjolnir, parts: string[]) { + const target = parts[2]; + + const isAdmin = await mjolnir.isSynapseAdmin(); + if (!isAdmin) { + const message = "I am not a Synapse administrator, or the endpoint is blocked"; + const reply = RichReply.createFor(roomId, event, message, message); + reply["msgtype"] = "m.notice"; + mjolnir.client.sendMessage(roomId, reply); + return; + } + + if (mjolnir.usingMas) { + try { + await mjolnir.masClient.unlockMasUser(target); + } catch (err) { + mjolnir.managementRoomOutput.logMessage( + LogLevel.ERROR, + "Unlock Command", + `There was an error unlocking ${target}, please check the logs for more information.`, + ); + await mjolnir.client.unstableApis.addReactionToEvent(roomId, event["event_id"], "❌"); + return; + } + } else { + await mjolnir.unlockSynapseUser(target); + } + await mjolnir.client.unstableApis.addReactionToEvent(roomId, event["event_id"], "✅"); +} \ No newline at end of file From 21284882b1e7dc8bdf5e903df6280ab57eb79c15 Mon Sep 17 00:00:00 2001 From: "H. Shay" Date: Tue, 25 Feb 2025 17:45:43 -0800 Subject: [PATCH 4/6] lint --- src/MASclient.ts | 1 - src/Mjolnir.ts | 24 ++++++++++++------------ src/commands/CommandHandler.ts | 4 ++-- src/commands/LockCommand.ts | 3 +-- src/commands/UnlockCommand.ts | 3 +-- 5 files changed, 16 insertions(+), 19 deletions(-) diff --git a/src/MASclient.ts b/src/MASclient.ts index 31533b1e..6ca2c243 100644 --- a/src/MASclient.ts +++ b/src/MASclient.ts @@ -14,7 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ - import { ClientCredentials, AccessToken } from "simple-oauth2"; import { IConfig } from "./config"; import axios from "axios"; diff --git a/src/Mjolnir.ts b/src/Mjolnir.ts index baf19987..17975b9c 100644 --- a/src/Mjolnir.ts +++ b/src/Mjolnir.ts @@ -578,18 +578,18 @@ export class Mjolnir { } public async isSynapseAdmin(): Promise { - try { - if (this.usingMas) { - return await this.masClient.masUserIsAdmin(this.clientUserId); - } else { - const endpoint = `/_synapse/admin/v1/users/${await this.client.getUserId()}/admin`; - const response = await this.client.doRequest("GET", endpoint); - return response["admin"]; - } - } catch (e) { - LogService.error("Mjolnir", "Error determining if Mjolnir is a server admin:"); - LogService.error("Mjolnir", extractRequestError(e)); - return false; // assume not + try { + if (this.usingMas) { + return await this.masClient.masUserIsAdmin(this.clientUserId); + } else { + const endpoint = `/_synapse/admin/v1/users/${await this.client.getUserId()}/admin`; + const response = await this.client.doRequest("GET", endpoint); + return response["admin"]; + } + } catch (e) { + LogService.error("Mjolnir", "Error determining if Mjolnir is a server admin:"); + LogService.error("Mjolnir", extractRequestError(e)); + return false; // assume not } } diff --git a/src/commands/CommandHandler.ts b/src/commands/CommandHandler.ts index 5d95b062..c306480b 100644 --- a/src/commands/CommandHandler.ts +++ b/src/commands/CommandHandler.ts @@ -51,8 +51,8 @@ import { execSetupProtectedRoom } from "./SetupDecentralizedReportingCommand"; import { execSuspendCommand } from "./SuspendCommand"; import { execUnsuspendCommand } from "./UnsuspendCommand"; import { execIgnoreCommand, execListIgnoredCommand } from "./IgnoreCommand"; -import {execLockCommand} from "./LockCommand"; -import {execUnlockCommand} from "./UnlockCommand"; +import { execLockCommand } from "./LockCommand"; +import { execUnlockCommand } from "./UnlockCommand"; export const COMMAND_PREFIX = "!mjolnir"; diff --git a/src/commands/LockCommand.ts b/src/commands/LockCommand.ts index 5f2e5d20..a5948042 100644 --- a/src/commands/LockCommand.ts +++ b/src/commands/LockCommand.ts @@ -14,7 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ - import { Mjolnir } from "../Mjolnir"; import { LogLevel, RichReply } from "@vector-im/matrix-bot-sdk"; @@ -47,4 +46,4 @@ export async function execLockCommand(roomId: string, event: any, mjolnir: Mjoln await mjolnir.lockSynapseUser(target); } await mjolnir.client.unstableApis.addReactionToEvent(roomId, event["event_id"], "✅"); -} \ No newline at end of file +} diff --git a/src/commands/UnlockCommand.ts b/src/commands/UnlockCommand.ts index a49ab875..db213595 100644 --- a/src/commands/UnlockCommand.ts +++ b/src/commands/UnlockCommand.ts @@ -14,7 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ - import { Mjolnir } from "../Mjolnir"; import { LogLevel, RichReply } from "@vector-im/matrix-bot-sdk"; @@ -47,4 +46,4 @@ export async function execUnlockCommand(roomId: string, event: any, mjolnir: Mjo await mjolnir.unlockSynapseUser(target); } await mjolnir.client.unstableApis.addReactionToEvent(roomId, event["event_id"], "✅"); -} \ No newline at end of file +} From 421a9a85003e62d81906705187c8f81b104239ad Mon Sep 17 00:00:00 2001 From: "H. Shay" Date: Wed, 26 Feb 2025 12:09:33 -0800 Subject: [PATCH 5/6] add deps --- package.json | 2 ++ yarn.lock | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 91 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 99cf6b69..fee08710 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "@types/pg": "^8.6.5", "@types/request": "^2.48.8", "@types/shell-quote": "1.7.1", + "@types/simple-oauth2": "^5.0.7", "crypto-js": "^4.2.0", "eslint": "^7.32", "expect": "^27.0.6", @@ -64,6 +65,7 @@ "pg": "^8.8.0", "prom-client": "^14.1.0", "shell-quote": "^1.7.3", + "simple-oauth2": "^5.1.0", "ulidx": "^0.3.0", "yaml": "^2.2.2" }, diff --git a/yarn.lock b/yarn.lock index 6e433a61..c591c900 100644 --- a/yarn.lock +++ b/yarn.lock @@ -69,6 +69,44 @@ minimatch "^3.0.4" strip-json-comments "^3.1.1" +"@hapi/boom@^10.0.1": + version "10.0.1" + resolved "https://registry.yarnpkg.com/@hapi/boom/-/boom-10.0.1.tgz#ebb14688275ae150aa6af788dbe482e6a6062685" + integrity sha512-ERcCZaEjdH3OgSJlyjVk8pHIFeus91CjKP3v+MpgBNp5IvGzP2l/bRiD78nqYcKPaZdbKkK5vDBVPd2ohHBlsA== + dependencies: + "@hapi/hoek" "^11.0.2" + +"@hapi/bourne@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@hapi/bourne/-/bourne-3.0.0.tgz#f11fdf7dda62fe8e336fa7c6642d9041f30356d7" + integrity sha512-Waj1cwPXJDucOib4a3bAISsKJVb15MKi9IvmTI/7ssVEm6sywXGjVJDhl6/umt1pK1ZS7PacXU3A1PmFKHEZ2w== + +"@hapi/hoek@^11.0.2", "@hapi/hoek@^11.0.4": + version "11.0.7" + resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-11.0.7.tgz#56a920793e0a42d10e530da9a64cc0d3919c4002" + integrity sha512-HV5undWkKzcB4RZUusqOpcgxOaq6VOAH7zhhIr2g3G8NF/MlFO75SjOr2NfuSx0Mh40+1FqCkagKLJRykUWoFQ== + +"@hapi/hoek@^9.0.0", "@hapi/hoek@^9.3.0": + version "9.3.0" + resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.3.0.tgz#8368869dcb735be2e7f5cb7647de78e167a251fb" + integrity sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ== + +"@hapi/topo@^5.1.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-5.1.0.tgz#dc448e332c6c6e37a4dc02fd84ba8d44b9afb012" + integrity sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg== + dependencies: + "@hapi/hoek" "^9.0.0" + +"@hapi/wreck@^18.0.0": + version "18.1.0" + resolved "https://registry.yarnpkg.com/@hapi/wreck/-/wreck-18.1.0.tgz#68e631fc7568ebefc6252d5b86cb804466c8dbe6" + integrity sha512-0z6ZRCmFEfV/MQqkQomJ7sl/hyxvcZM7LtuVqN3vdAO4vM9eBbowl0kaqQj9EJJQab+3Uuh1GxbGIBFy4NfJ4w== + dependencies: + "@hapi/boom" "^10.0.1" + "@hapi/bourne" "^3.0.0" + "@hapi/hoek" "^11.0.2" + "@humanwhocodes/config-array@^0.5.0": version "0.5.0" resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz" @@ -183,6 +221,23 @@ "@sentry/types" "7.22.0" tslib "^1.9.3" +"@sideway/address@^4.1.5": + version "4.1.5" + resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.5.tgz#4bc149a0076623ced99ca8208ba780d65a99b9d5" + integrity sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q== + dependencies: + "@hapi/hoek" "^9.0.0" + +"@sideway/formula@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@sideway/formula/-/formula-3.0.1.tgz#80fcbcbaf7ce031e0ef2dd29b1bfc7c3f583611f" + integrity sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg== + +"@sideway/pinpoint@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df" + integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ== + "@tensorflow/tfjs-backend-cpu@4.21.0": version "4.21.0" resolved "https://registry.yarnpkg.com/@tensorflow/tfjs-backend-cpu/-/tfjs-backend-cpu-4.21.0.tgz#27a489f838b88aa98220da0aaf29f58d16fc9d05" @@ -505,6 +560,11 @@ resolved "https://registry.npmjs.org/@types/shell-quote/-/shell-quote-1.7.1.tgz" integrity sha512-SWZ2Nom1pkyXCDohRSrkSKvDh8QOG9RfAsrt5/NsPQC4UQJ55eG0qClA40I+Gkez4KTQ0uDUT8ELRXThf3J5jw== +"@types/simple-oauth2@^5.0.7": + version "5.0.7" + resolved "https://registry.yarnpkg.com/@types/simple-oauth2/-/simple-oauth2-5.0.7.tgz#92df8c2fba8ec58c9fea6dd3206d4395de19e721" + integrity sha512-8JbWVJbiTSBQP/7eiyGKyXWAqp3dKQZpaA+pdW16FCi32ujkzRMG8JfjoAzdWt6W8U591ZNdHcPtP2D7ILTKuA== + "@types/stack-utils@^2.0.0": version "2.0.1" resolved "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz" @@ -1153,6 +1213,13 @@ debug@^3.1.0: dependencies: ms "^2.1.1" +debug@^4.3.4: + version "4.4.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" + integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== + dependencies: + ms "^2.1.3" + decamelize@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz" @@ -2353,6 +2420,17 @@ jest-regex-util@^27.0.6: resolved "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.0.6.tgz" integrity sha512-SUhPzBsGa1IKm8hx2F4NfTGGp+r7BXJ4CulsZ1k2kI+mGLG+lxGrs76veN2LF/aUdGosJBzKgXmNCw+BzFqBDQ== +joi@^17.6.4: + version "17.13.3" + resolved "https://registry.yarnpkg.com/joi/-/joi-17.13.3.tgz#0f5cc1169c999b30d344366d384b12d92558bcec" + integrity sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA== + dependencies: + "@hapi/hoek" "^9.3.0" + "@hapi/topo" "^5.1.0" + "@sideway/address" "^4.1.5" + "@sideway/formula" "^3.0.1" + "@sideway/pinpoint" "^2.0.0" + js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" @@ -2806,7 +2884,7 @@ ms@2.1.2: resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3, ms@^2.1.1: +ms@2.1.3, ms@^2.1.1, ms@^2.1.3: version "2.1.3" resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -3663,6 +3741,16 @@ signal-exit@^3.0.0: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== +simple-oauth2@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/simple-oauth2/-/simple-oauth2-5.1.0.tgz#1398fe2b8f4b4066298d63c155501b31b42238f2" + integrity sha512-gWDa38Ccm4MwlG5U7AlcJxPv3lvr80dU7ARJWrGdgvOKyzSj1gr3GBPN1rABTedAYvC/LsGYoFuFxwDBPtGEbw== + dependencies: + "@hapi/hoek" "^11.0.4" + "@hapi/wreck" "^18.0.0" + debug "^4.3.4" + joi "^17.6.4" + simple-swizzle@^0.2.2: version "0.2.2" resolved "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz" From d1e4fbae635b18cf78c5fce95081d5a734d1c82c Mon Sep 17 00:00:00 2001 From: "H. Shay" Date: Wed, 26 Feb 2025 12:26:22 -0800 Subject: [PATCH 6/6] another lint --- src/MASclient.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MASclient.ts b/src/MASclient.ts index 6ca2c243..1e8ff3bd 100644 --- a/src/MASclient.ts +++ b/src/MASclient.ts @@ -138,7 +138,7 @@ export class MASclient { const localpart = userId.substring(1, index); const accessToken = await this.getAccessToken(); - var resp; + let resp; try { resp = await axios({ method: "get",