Skip to content
This repository was archived by the owner on Sep 10, 2024. It is now read-only.

Commit f8d745d

Browse files
committed
Add a GraphQL mutation to allow cross-signing reset
1 parent 5957112 commit f8d745d

File tree

4 files changed

+147
-0
lines changed

4 files changed

+147
-0
lines changed

crates/graphql/src/mutations/user.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
use anyhow::Context as _;
1516
use async_graphql::{Context, Description, Enum, InputObject, Object, ID};
1617
use mas_storage::{
1718
job::{DeactivateUserJob, JobRepositoryExt, ProvisionUserJob},
@@ -22,6 +23,7 @@ use tracing::info;
2223
use crate::{
2324
model::{NodeType, User},
2425
state::ContextExt,
26+
UserId,
2527
};
2628

2729
#[derive(Default)]
@@ -157,6 +159,34 @@ impl SetCanRequestAdminPayload {
157159
}
158160
}
159161

162+
/// The input for the `allowUserCrossSigningReset` mutation.
163+
#[derive(InputObject)]
164+
struct AllowUserCrossSigningResetInput {
165+
/// The ID of the user to update.
166+
user_id: ID,
167+
}
168+
169+
/// The payload for the `allowUserCrossSigningReset` mutation.
170+
#[derive(Description)]
171+
enum AllowUserCrossSigningResetPayload {
172+
/// The user was updated.
173+
Allowed(mas_data_model::User),
174+
175+
/// The user was not found.
176+
NotFound,
177+
}
178+
179+
#[Object(use_type_description)]
180+
impl AllowUserCrossSigningResetPayload {
181+
/// The user that was updated.
182+
async fn user(&self) -> Option<User> {
183+
match self {
184+
Self::Allowed(user) => Some(User(user.clone())),
185+
Self::NotFound => None,
186+
}
187+
}
188+
}
189+
160190
fn valid_username_character(c: char) -> bool {
161191
c.is_ascii_lowercase()
162192
|| c.is_ascii_digit()
@@ -296,4 +326,36 @@ impl UserMutations {
296326

297327
Ok(SetCanRequestAdminPayload::Updated(user))
298328
}
329+
330+
/// Temporarily allow user to reset their cross-signing keys.
331+
async fn allow_user_cross_signing_reset(
332+
&self,
333+
ctx: &Context<'_>,
334+
input: AllowUserCrossSigningResetInput,
335+
) -> Result<AllowUserCrossSigningResetPayload, async_graphql::Error> {
336+
let state = ctx.state();
337+
let user_id = NodeType::User.extract_ulid(&input.user_id)?;
338+
let requester = ctx.requester();
339+
340+
if !requester.is_owner_or_admin(&UserId(user_id)) {
341+
return Err(async_graphql::Error::new("Unauthorized"));
342+
}
343+
344+
let mut repo = state.repository().await?;
345+
let user = repo.user().lookup(user_id).await?;
346+
repo.cancel().await?;
347+
348+
let Some(user) = user else {
349+
return Ok(AllowUserCrossSigningResetPayload::NotFound);
350+
};
351+
352+
let conn = state.homeserver_connection();
353+
let mxid = conn.mxid(&user.username);
354+
355+
conn.allow_cross_signing_reset(&mxid)
356+
.await
357+
.context("Failed to allow cross-signing reset")?;
358+
359+
Ok(AllowUserCrossSigningResetPayload::Allowed(user))
360+
}
299361
}

frontend/schema.graphql

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,26 @@ enum AddUserStatus {
106106
INVALID
107107
}
108108

109+
"""
110+
The input for the `allowUserCrossSigningReset` mutation.
111+
"""
112+
input AllowUserCrossSigningResetInput {
113+
"""
114+
The ID of the user to update.
115+
"""
116+
userId: ID!
117+
}
118+
119+
"""
120+
The payload for the `allowUserCrossSigningReset` mutation.
121+
"""
122+
type AllowUserCrossSigningResetPayload {
123+
"""
124+
The user that was updated.
125+
"""
126+
user: User
127+
}
128+
109129
type Anonymous implements Node {
110130
id: ID!
111131
}
@@ -650,6 +670,12 @@ type Mutation {
650670
input: SetCanRequestAdminInput!
651671
): SetCanRequestAdminPayload!
652672
"""
673+
Temporarily allow user to reset their cross-signing keys.
674+
"""
675+
allowUserCrossSigningReset(
676+
input: AllowUserCrossSigningResetInput!
677+
): AllowUserCrossSigningResetPayload!
678+
"""
653679
Create a new arbitrary OAuth 2.0 Session.
654680
655681
Only available for administrators.

frontend/src/gql/graphql.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,19 @@ export enum AddUserStatus {
9999
Invalid = "INVALID",
100100
}
101101

102+
/** The input for the `allowUserCrossSigningReset` mutation. */
103+
export type AllowUserCrossSigningResetInput = {
104+
/** The ID of the user to update. */
105+
userId: Scalars["ID"]["input"];
106+
};
107+
108+
/** The payload for the `allowUserCrossSigningReset` mutation. */
109+
export type AllowUserCrossSigningResetPayload = {
110+
__typename?: "AllowUserCrossSigningResetPayload";
111+
/** The user that was updated. */
112+
user?: Maybe<User>;
113+
};
114+
102115
export type Anonymous = Node & {
103116
__typename?: "Anonymous";
104117
id: Scalars["ID"]["output"];
@@ -421,6 +434,8 @@ export type Mutation = {
421434
addEmail: AddEmailPayload;
422435
/** Add a user. This is only available to administrators. */
423436
addUser: AddUserPayload;
437+
/** Temporarily allow user to reset their cross-signing keys. */
438+
allowUserCrossSigningReset: AllowUserCrossSigningResetPayload;
424439
/**
425440
* Create a new arbitrary OAuth 2.0 Session.
426441
*
@@ -459,6 +474,11 @@ export type MutationAddUserArgs = {
459474
input: AddUserInput;
460475
};
461476

477+
/** The mutations root of the GraphQL interface. */
478+
export type MutationAllowUserCrossSigningResetArgs = {
479+
input: AllowUserCrossSigningResetInput;
480+
};
481+
462482
/** The mutations root of the GraphQL interface. */
463483
export type MutationCreateOauth2SessionArgs = {
464484
input: CreateOAuth2SessionInput;

frontend/src/gql/schema.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,22 @@ export default {
8686
],
8787
interfaces: [],
8888
},
89+
{
90+
kind: "OBJECT",
91+
name: "AllowUserCrossSigningResetPayload",
92+
fields: [
93+
{
94+
name: "user",
95+
type: {
96+
kind: "OBJECT",
97+
name: "User",
98+
ofType: null,
99+
},
100+
args: [],
101+
},
102+
],
103+
interfaces: [],
104+
},
89105
{
90106
kind: "OBJECT",
91107
name: "Anonymous",
@@ -1100,6 +1116,29 @@ export default {
11001116
},
11011117
],
11021118
},
1119+
{
1120+
name: "allowUserCrossSigningReset",
1121+
type: {
1122+
kind: "NON_NULL",
1123+
ofType: {
1124+
kind: "OBJECT",
1125+
name: "AllowUserCrossSigningResetPayload",
1126+
ofType: null,
1127+
},
1128+
},
1129+
args: [
1130+
{
1131+
name: "input",
1132+
type: {
1133+
kind: "NON_NULL",
1134+
ofType: {
1135+
kind: "SCALAR",
1136+
name: "Any",
1137+
},
1138+
},
1139+
},
1140+
],
1141+
},
11031142
{
11041143
name: "createOauth2Session",
11051144
type: {

0 commit comments

Comments
 (0)