KI-AGENT: Matrix-Login-Rate-Limits vermeiden
This commit is contained in:
@@ -35,8 +35,18 @@ type MatrixUserSession = {
|
||||
validUntilMs: number
|
||||
}
|
||||
|
||||
type MatrixCachedValue<T = any> = {
|
||||
exists: true
|
||||
cachedUntil: number
|
||||
value: T
|
||||
}
|
||||
|
||||
const matrixUserSessionCache = new Map<string, MatrixUserSession>()
|
||||
const matrixJoinedRoomCache = new Map<string, number>()
|
||||
const matrixProvisionedUserCache = new Map<string, number>()
|
||||
const matrixTenantSpaceCache = new Map<string, MatrixCachedValue>()
|
||||
const matrixTenantRoomCache = new Map<string, MatrixCachedValue>()
|
||||
let matrixServiceSessionCache: MatrixUserSession | null = null
|
||||
|
||||
const trimTrailingSlash = (value: string) => value.replace(/\/+$/, "")
|
||||
const readLocalDevRegistrationSharedSecret = () => {
|
||||
@@ -229,6 +239,10 @@ export function matrixService(server: FastifyInstance) {
|
||||
)
|
||||
}
|
||||
|
||||
if (matrixServiceSessionCache && matrixServiceSessionCache.validUntilMs > Date.now() + 60_000) {
|
||||
return matrixServiceSessionCache
|
||||
}
|
||||
|
||||
const username = serviceUserLocalpart()
|
||||
const password = serviceUserPassword()
|
||||
|
||||
@@ -240,7 +254,14 @@ export function matrixService(server: FastifyInstance) {
|
||||
}
|
||||
}
|
||||
|
||||
return loginMatrixUser(username, password)
|
||||
const login = await loginMatrixUser(username, password)
|
||||
matrixServiceSessionCache = {
|
||||
accessToken: login.access_token,
|
||||
matrixUserId: login.user_id,
|
||||
validUntilMs: Date.now() + 30 * 60 * 1000,
|
||||
}
|
||||
|
||||
return matrixServiceSessionCache
|
||||
}
|
||||
|
||||
const getCurrentUserDisplayName = async (userId: string, tenantId: number | null) => {
|
||||
@@ -320,7 +341,7 @@ export function matrixService(server: FastifyInstance) {
|
||||
|
||||
const login = await requestMatrixJson<{ access_token: string }>(
|
||||
`/_synapse/admin/v1/users/${encodeURIComponent(matrixUserId)}/login`,
|
||||
serviceLogin.access_token,
|
||||
serviceLogin.accessToken,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
@@ -386,11 +407,25 @@ export function matrixService(server: FastifyInstance) {
|
||||
|
||||
const username = await matrixLocalpartForUser(userId, tenantId)
|
||||
const matrixUserId = await matrixUserIdForUser(userId, tenantId)
|
||||
const password = randomBytes(32).toString("base64url")
|
||||
const displayName = await getCurrentUserDisplayName(userId, tenantId)
|
||||
const cacheKey = `${tenantId || "global"}:${userId}`
|
||||
const cachedUntil = matrixProvisionedUserCache.get(cacheKey)
|
||||
|
||||
if (cachedUntil && cachedUntil > Date.now()) {
|
||||
return {
|
||||
matrixUserId,
|
||||
localpart: username,
|
||||
displayName,
|
||||
created: false,
|
||||
alreadyExisted: true,
|
||||
}
|
||||
}
|
||||
|
||||
const password = randomBytes(32).toString("base64url")
|
||||
|
||||
try {
|
||||
await registerWithSharedSecret(username, password, false)
|
||||
matrixProvisionedUserCache.set(cacheKey, Date.now() + 30 * 60 * 1000)
|
||||
|
||||
return {
|
||||
matrixUserId,
|
||||
@@ -401,6 +436,8 @@ export function matrixService(server: FastifyInstance) {
|
||||
}
|
||||
} catch (err: any) {
|
||||
if (err.errcode === "M_USER_IN_USE") {
|
||||
matrixProvisionedUserCache.set(cacheKey, Date.now() + 30 * 60 * 1000)
|
||||
|
||||
return {
|
||||
matrixUserId,
|
||||
localpart: username,
|
||||
@@ -478,23 +515,37 @@ export function matrixService(server: FastifyInstance) {
|
||||
|
||||
const provisionCurrentTenantSpace = async (userId: string, tenantId: number | null) => {
|
||||
const tenant = await getCurrentTenant(tenantId)
|
||||
const cacheKey = String(tenant.id)
|
||||
const cachedSpace = matrixTenantSpaceCache.get(cacheKey)
|
||||
|
||||
if (cachedSpace?.exists && cachedSpace.cachedUntil > Date.now()) {
|
||||
return cachedSpace.value
|
||||
}
|
||||
|
||||
const existing = await getTenantSpaceStatus(tenant.id)
|
||||
const userAccount = await provisionCurrentUser(userId, tenant.id)
|
||||
|
||||
if (existing.exists) {
|
||||
return {
|
||||
const value = {
|
||||
...existing,
|
||||
created: false,
|
||||
alreadyExisted: true,
|
||||
invitedUserId: userAccount.matrixUserId,
|
||||
}
|
||||
|
||||
matrixTenantSpaceCache.set(cacheKey, {
|
||||
exists: true,
|
||||
cachedUntil: Date.now() + 30 * 60 * 1000,
|
||||
value,
|
||||
})
|
||||
return value
|
||||
}
|
||||
|
||||
const serviceLogin = await ensureServiceAccessToken()
|
||||
const aliasLocalpart = tenantSpaceAliasLocalpart(tenant)
|
||||
const createdRoom = await requestMatrixJson<{ room_id: string }>(
|
||||
"/_matrix/client/v3/createRoom",
|
||||
serviceLogin.access_token,
|
||||
serviceLogin.accessToken,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
@@ -521,7 +572,7 @@ export function matrixService(server: FastifyInstance) {
|
||||
}
|
||||
)
|
||||
|
||||
return {
|
||||
const value = {
|
||||
tenantId: tenant.id,
|
||||
tenantName: tenant.name,
|
||||
alias: tenantSpaceAlias(tenant),
|
||||
@@ -530,8 +581,15 @@ export function matrixService(server: FastifyInstance) {
|
||||
alreadyExisted: false,
|
||||
roomId: createdRoom.room_id,
|
||||
invitedUserId: userAccount.matrixUserId,
|
||||
serviceUserId: serviceLogin.user_id,
|
||||
serviceUserId: serviceLogin.matrixUserId,
|
||||
}
|
||||
|
||||
matrixTenantSpaceCache.set(cacheKey, {
|
||||
exists: true,
|
||||
cachedUntil: Date.now() + 30 * 60 * 1000,
|
||||
value,
|
||||
})
|
||||
return value
|
||||
}
|
||||
|
||||
const getTenantRoomStatus = async (
|
||||
@@ -589,24 +647,38 @@ export function matrixService(server: FastifyInstance) {
|
||||
const key = normalizeMatrixAliasSeed(options.key || options.name || "allgemein")
|
||||
const name = (options.name || "Allgemeiner Chat").trim() || "Allgemeiner Chat"
|
||||
const topic = (options.topic || `Allgemeiner Kommunikationsraum für ${tenant.name}`).trim()
|
||||
const cacheKey = `${tenant.id}:${key}`
|
||||
const cachedRoom = matrixTenantRoomCache.get(cacheKey)
|
||||
|
||||
if (cachedRoom?.exists && cachedRoom.cachedUntil > Date.now()) {
|
||||
return cachedRoom.value
|
||||
}
|
||||
|
||||
const existing = await getTenantRoomStatus(tenant.id, key, name)
|
||||
const userAccount = await provisionCurrentUser(userId, tenant.id)
|
||||
const tenantSpace = await provisionCurrentTenantSpace(userId, tenant.id)
|
||||
|
||||
if (existing.exists) {
|
||||
return {
|
||||
const value = {
|
||||
...existing,
|
||||
created: false,
|
||||
alreadyExisted: true,
|
||||
parentSpaceRoomId: tenantSpace.roomId,
|
||||
invitedUserId: userAccount.matrixUserId,
|
||||
}
|
||||
|
||||
matrixTenantRoomCache.set(cacheKey, {
|
||||
exists: true,
|
||||
cachedUntil: Date.now() + 30 * 60 * 1000,
|
||||
value,
|
||||
})
|
||||
return value
|
||||
}
|
||||
|
||||
const serviceLogin = await ensureServiceAccessToken()
|
||||
const createdRoom = await requestMatrixJson<{ room_id: string }>(
|
||||
"/_matrix/client/v3/createRoom",
|
||||
serviceLogin.access_token,
|
||||
serviceLogin.accessToken,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
@@ -640,7 +712,7 @@ export function matrixService(server: FastifyInstance) {
|
||||
|
||||
await requestMatrixJson(
|
||||
`/_matrix/client/v3/rooms/${encodeURIComponent(tenantSpace.roomId)}/state/m.space.child/${encodeURIComponent(createdRoom.room_id)}`,
|
||||
serviceLogin.access_token,
|
||||
serviceLogin.accessToken,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
@@ -652,7 +724,7 @@ export function matrixService(server: FastifyInstance) {
|
||||
}
|
||||
)
|
||||
|
||||
return {
|
||||
const value = {
|
||||
tenantId: tenant.id,
|
||||
tenantName: tenant.name,
|
||||
key,
|
||||
@@ -664,8 +736,15 @@ export function matrixService(server: FastifyInstance) {
|
||||
roomId: createdRoom.room_id,
|
||||
parentSpaceRoomId: tenantSpace.roomId,
|
||||
invitedUserId: userAccount.matrixUserId,
|
||||
serviceUserId: serviceLogin.user_id,
|
||||
serviceUserId: serviceLogin.matrixUserId,
|
||||
}
|
||||
|
||||
matrixTenantRoomCache.set(cacheKey, {
|
||||
exists: true,
|
||||
cachedUntil: Date.now() + 30 * 60 * 1000,
|
||||
value,
|
||||
})
|
||||
return value
|
||||
}
|
||||
|
||||
const ensureCurrentUserJoinedRoom = async (
|
||||
|
||||
Reference in New Issue
Block a user