Change getPublicUrlForMxc function for authmedia
This commit is contained in:
parent
96fd046530
commit
decc32f7e6
6 changed files with 39 additions and 14 deletions
|
@ -11,6 +11,8 @@ const {discord, sync, db, select} = require("../passthrough")
|
||||||
const api = sync.require("../matrix/api")
|
const api = sync.require("../matrix/api")
|
||||||
/** @type {import("../matrix/file")} */
|
/** @type {import("../matrix/file")} */
|
||||||
const file = sync.require("../matrix/file")
|
const file = sync.require("../matrix/file")
|
||||||
|
/** @type {import("../m2d/converters/utils")} */
|
||||||
|
const mxUtils = sync.require("../matrix/utils")
|
||||||
/** @type {import("../d2m/actions/create-space")} */
|
/** @type {import("../d2m/actions/create-space")} */
|
||||||
const createSpace = sync.require("../d2m/actions/create-space")
|
const createSpace = sync.require("../d2m/actions/create-space")
|
||||||
/** @type {import("./utils")} */
|
/** @type {import("./utils")} */
|
||||||
|
@ -91,9 +93,8 @@ const commands = [{
|
||||||
|
|
||||||
// Current avatar
|
// Current avatar
|
||||||
const avatarEvent = await api.getStateEvent(roomID, "m.room.avatar", "")
|
const avatarEvent = await api.getStateEvent(roomID, "m.room.avatar", "")
|
||||||
const avatarURLParts = avatarEvent?.url.match(/^mxc:\/\/([^/]+)\/(\w+)$/)
|
|
||||||
let currentAvatarMessage =
|
let currentAvatarMessage =
|
||||||
( avatarURLParts ? `Current room-specific avatar: ${reg.ooye.server_origin}/_matrix/media/r0/download/${avatarURLParts[1]}/${avatarURLParts[2]}`
|
( avatarEvent.url ? `Current room-specific avatar: ${mxUtils.getPublicUrlForMxc(avatarEvent.url)}`
|
||||||
: "No avatar. Now's your time to strike. Use `//icon` again with a link or upload to set the room-specific avatar.")
|
: "No avatar. Now's your time to strike. Use `//icon` again with a link or upload to set the room-specific avatar.")
|
||||||
|
|
||||||
// Next potential avatar
|
// Next potential avatar
|
||||||
|
|
|
@ -15,6 +15,8 @@ const {sync, db, discord, select, from} = passthrough
|
||||||
const mxUtils = sync.require("../converters/utils")
|
const mxUtils = sync.require("../converters/utils")
|
||||||
/** @type {import("../../discord/utils")} */
|
/** @type {import("../../discord/utils")} */
|
||||||
const dUtils = sync.require("../../discord/utils")
|
const dUtils = sync.require("../../discord/utils")
|
||||||
|
/** @type {import("../../matrix/file")} */
|
||||||
|
const file = sync.require("../../matrix/file")
|
||||||
/** @type {import("./emoji-sheet")} */
|
/** @type {import("./emoji-sheet")} */
|
||||||
const emojiSheet = sync.require("./emoji-sheet")
|
const emojiSheet = sync.require("./emoji-sheet")
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
// @ts-check
|
// @ts-check
|
||||||
|
|
||||||
|
const assert = require("assert").strict
|
||||||
|
|
||||||
|
const passthrough = require("../../passthrough")
|
||||||
|
const {db} = passthrough
|
||||||
|
|
||||||
const {reg} = require("../../matrix/read-registration")
|
const {reg} = require("../../matrix/read-registration")
|
||||||
const userRegex = reg.namespaces.users.map(u => new RegExp(u.regex))
|
const userRegex = reg.namespaces.users.map(u => new RegExp(u.regex))
|
||||||
const assert = require("assert").strict
|
|
||||||
/** @type {import("xxhash-wasm").XXHashAPI} */ // @ts-ignore
|
/** @type {import("xxhash-wasm").XXHashAPI} */ // @ts-ignore
|
||||||
let hasher = null
|
let hasher = null
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
@ -35,16 +40,6 @@ function eventSenderIsFromDiscord(sender) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} mxc
|
|
||||||
* @returns {string?}
|
|
||||||
*/
|
|
||||||
function getPublicUrlForMxc(mxc) {
|
|
||||||
const avatarURLParts = mxc?.match(/^mxc:\/\/([^/]+)\/(\w+)$/)
|
|
||||||
if (avatarURLParts) return `${reg.ooye.server_origin}/_matrix/media/r0/download/${avatarURLParts[1]}/${avatarURLParts[2]}`
|
|
||||||
else return null
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Event IDs are really big and have more entropy than we need.
|
* Event IDs are really big and have more entropy than we need.
|
||||||
* If we want to store the event ID in the database, we can store a more compact version by hashing it with this.
|
* If we want to store the event ID in the database, we can store a more compact version by hashing it with this.
|
||||||
|
@ -213,6 +208,32 @@ async function getViaServersQuery(roomID, api) {
|
||||||
return qs
|
return qs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Since the introduction of authenticated media, this can no longer just be the /_matrix/media/r0/download URL
|
||||||
|
* because Discord and Discord users cannot use those URLs. Media now has to be proxied through the bridge.
|
||||||
|
* To avoid the bridge acting as a proxy for *any* media, there is a list of permitted media stored in the database.
|
||||||
|
* (The other approach would be signing the URLs with a MAC (or similar) and adding the signature, but I'm not a
|
||||||
|
* cryptographer, so I don't want to.) To reduce database disk space usage, instead of storing each permitted URL,
|
||||||
|
* we just store its xxhash as a signed (as in +/-, not signature) 64-bit integer, which fits in an SQLite integer field.
|
||||||
|
* @see https://matrix.org/blog/2024/06/26/sunsetting-unauthenticated-media/ background
|
||||||
|
* @see https://matrix.org/blog/2024/06/20/matrix-v1.11-release/ implementation details
|
||||||
|
* @see https://www.sqlite.org/fileformat2.html#record_format SQLite integer field size
|
||||||
|
* @param {string} mxc
|
||||||
|
* @returns {string?}
|
||||||
|
*/
|
||||||
|
function getPublicUrlForMxc(mxc) {
|
||||||
|
assert(hasher, "xxhash is not ready yet")
|
||||||
|
const avatarURLParts = mxc?.match(/^mxc:\/\/([^/]+)\/(\w+)$/)
|
||||||
|
if (!avatarURLParts) return null
|
||||||
|
|
||||||
|
const serverAndMediaID = `${avatarURLParts[1]}/${avatarURLParts[2]}`
|
||||||
|
const unsignedHash = hasher.h64(serverAndMediaID)
|
||||||
|
const signedHash = unsignedHash - 0x8000000000000000n // shifting down to signed 64-bit range
|
||||||
|
db.prepare("INSERT OR IGNORE INTO media_proxy (permitted_hash) VALUES (?)").run(signedHash)
|
||||||
|
|
||||||
|
return `${reg.ooye.bridge_origin}/download/matrix/${serverAndMediaID}`
|
||||||
|
}
|
||||||
|
|
||||||
module.exports.BLOCK_ELEMENTS = BLOCK_ELEMENTS
|
module.exports.BLOCK_ELEMENTS = BLOCK_ELEMENTS
|
||||||
module.exports.eventSenderIsFromDiscord = eventSenderIsFromDiscord
|
module.exports.eventSenderIsFromDiscord = eventSenderIsFromDiscord
|
||||||
module.exports.getPublicUrlForMxc = getPublicUrlForMxc
|
module.exports.getPublicUrlForMxc = getPublicUrlForMxc
|
||||||
|
|
1
stdin.js
1
stdin.js
|
@ -32,7 +32,6 @@ if (process.stdin.isTTY) {
|
||||||
} else {
|
} else {
|
||||||
Object.assign(passthrough.repl.context, extraContext)
|
Object.assign(passthrough.repl.context, extraContext)
|
||||||
}
|
}
|
||||||
// @ts-expect-error Says exit isn't assignable to a string
|
|
||||||
sync.addTemporaryListener(passthrough.repl, "exit", () => process.exit())
|
sync.addTemporaryListener(passthrough.repl, "exit", () => process.exit())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ reg.ooye.server_name = "cadence.moe"
|
||||||
reg.id = "baby" // don't actually take authenticated actions on the server
|
reg.id = "baby" // don't actually take authenticated actions on the server
|
||||||
reg.as_token = "baby"
|
reg.as_token = "baby"
|
||||||
reg.hs_token = "baby"
|
reg.hs_token = "baby"
|
||||||
|
reg.ooye.bridge_origin = "https://bridge.example.org"
|
||||||
reg.ooye.invite = []
|
reg.ooye.invite = []
|
||||||
|
|
||||||
const sync = new HeatSync({watchFS: false})
|
const sync = new HeatSync({watchFS: false})
|
||||||
|
|
1
types.d.ts
vendored
1
types.d.ts
vendored
|
@ -21,6 +21,7 @@ export type AppServiceRegistrationConfig = {
|
||||||
max_file_size: number
|
max_file_size: number
|
||||||
server_name: string
|
server_name: string
|
||||||
server_origin: string
|
server_origin: string
|
||||||
|
bridge_origin: string
|
||||||
content_length_workaround: boolean
|
content_length_workaround: boolean
|
||||||
include_user_id_in_mxid: boolean
|
include_user_id_in_mxid: boolean
|
||||||
invite: string[]
|
invite: string[]
|
||||||
|
|
Loading…
Reference in a new issue