judu/ex-egopublic Fork
⑂ b6b617b
Commits
⬇ Clone ▾
git clone https://git.rickub.com/judu/ex-ego.git
git clone ssh://git@rickub.com/judu/ex-ego.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Download ZIP

feat(cli): exego user set-password — remplace le mot de passe d'un compteUnverified

Filet de récupération pour un mdp oublié (le mdp reste le seul moyen de
gérer les passkeys). Même règles que l'inscription (8 caractères min,
saisie confirmée au terminal ou --password), et comme le changement
depuis la page Sécurité, les sessions ouvertes ne sont pas révoquées.
La saisie de mot de passe de user add est factorisée (ask_password).
Julien Durillon committed 2026-09-01T23:39:16+02:00 Browse files
b6b617b parent: 8a09936
modified src/cli.rs +30 -8
@@ -103,14 +103,9 @@ fn choose(matches: Vec<TeamMatch>, input: &str) -> Result<TeamMatch> {
103103 }
104104 }
105105
106-/// `exego user add <username> --team <nom>` — création de compte côté
107-/// serveur, toujours rattaché à une équipe (invariant : jamais sans équipe).
108-pub async fn user_add(username: &str, password_arg: Option<String>, team: &str) -> Result<()> {
109- let username = username.trim();
110- if username.is_empty() {
111- bail!("le nom d'utilisateur ne peut pas être vide");
112- }
113-
106+/// Prend `--password` ou demande au terminal (avec confirmation) — mêmes
107+/// règles de longueur que l'inscription.
108+fn ask_password(password_arg: Option<String>) -> Result<String> {
114109 let password = match password_arg {
115110 Some(p) => p,
116111 None => {
@@ -125,6 +120,17 @@ pub async fn user_add(username: &str, password_arg: Option<String>, team: &str)
125120 if password.len() < 8 {
126121 bail!("le mot de passe doit faire au moins 8 caractères");
127122 }
123+ Ok(password)
124+}
125+
126+/// `exego user add <username> --team <nom>` — création de compte côté
127+/// serveur, toujours rattaché à une équipe (invariant : jamais sans équipe).
128+pub async fn user_add(username: &str, password_arg: Option<String>, team: &str) -> Result<()> {
129+ let username = username.trim();
130+ if username.is_empty() {
131+ bail!("le nom d'utilisateur ne peut pas être vide");
132+ }
133+ let password = ask_password(password_arg)?;
128134
129135 let pool = connect().await?;
130136 let team = pick_team(&pool, team.trim()).await?;
@@ -159,6 +165,22 @@ pub async fn user_add(username: &str, password_arg: Option<String>, team: &str)
159165 Ok(())
160166 }
161167
168+/// `exego user set-password <username>` — remplace le mot de passe d'un
169+/// compte. Filet de récupération (mdp oublié) : comme le changement depuis
170+/// la page Sécurité, il ne révoque pas les sessions ouvertes.
171+pub async fn user_set_password(username: &str, password_arg: Option<String>) -> Result<()> {
172+ let username = username.trim();
173+ let password = ask_password(password_arg)?;
174+ let pool = connect().await?;
175+ let user = users::find_by_username(&pool, username)
176+ .await?
177+ .with_context(|| format!("l'utilisateur « {username} » n'existe pas"))?;
178+ let hash = password::hash(&password)?;
179+ users::update_password(&pool, user.id, &hash).await?;
180+ println!("Mot de passe de « {username} » mis à jour.");
181+ Ok(())
182+}
183+
162184 /// `exego user join <username> --team <nom>` — rattache un compte
163185 /// existant à une équipe (équivalent CLI d'une invitation acceptée).
164186 pub async fn user_join(username: &str, team: &str) -> Result<()> {
@@ -103,14 +103,9 @@ fn choose(matches: Vec<TeamMatch>, input: &str) -> Result<TeamMatch> {
103 }103 }
104 }104 }
105 105
106-/// `exego user add <username> --team <nom>` — création de compte côté106+/// Prend `--password` ou demande au terminal (avec confirmation) — mêmes
107-/// serveur, toujours rattaché à une équipe (invariant : jamais sans équipe).107+/// règles de longueur que l'inscription.
108-pub async fn user_add(username: &str, password_arg: Option<String>, team: &str) -> Result<()> {108+fn ask_password(password_arg: Option<String>) -> Result<String> {
109- let username = username.trim();
110- if username.is_empty() {
111- bail!("le nom d'utilisateur ne peut pas être vide");
112- }
113-
114 let password = match password_arg {109 let password = match password_arg {
115 Some(p) => p,110 Some(p) => p,
116 None => {111 None => {
@@ -125,6 +120,17 @@ pub async fn user_add(username: &str, password_arg: Option<String>, team: &str)
125 if password.len() < 8 {120 if password.len() < 8 {
126 bail!("le mot de passe doit faire au moins 8 caractères");121 bail!("le mot de passe doit faire au moins 8 caractères");
127 }122 }
123+ Ok(password)
124+}
125+
126+/// `exego user add <username> --team <nom>` — création de compte côté
127+/// serveur, toujours rattaché à une équipe (invariant : jamais sans équipe).
128+pub async fn user_add(username: &str, password_arg: Option<String>, team: &str) -> Result<()> {
129+ let username = username.trim();
130+ if username.is_empty() {
131+ bail!("le nom d'utilisateur ne peut pas être vide");
132+ }
133+ let password = ask_password(password_arg)?;
128 134
129 let pool = connect().await?;135 let pool = connect().await?;
130 let team = pick_team(&pool, team.trim()).await?;136 let team = pick_team(&pool, team.trim()).await?;
@@ -159,6 +165,22 @@ pub async fn user_add(username: &str, password_arg: Option<String>, team: &str)
159 Ok(())165 Ok(())
160 }166 }
161 167
168+/// `exego user set-password <username>` — remplace le mot de passe d'un
169+/// compte. Filet de récupération (mdp oublié) : comme le changement depuis
170+/// la page Sécurité, il ne révoque pas les sessions ouvertes.
171+pub async fn user_set_password(username: &str, password_arg: Option<String>) -> Result<()> {
172+ let username = username.trim();
173+ let password = ask_password(password_arg)?;
174+ let pool = connect().await?;
175+ let user = users::find_by_username(&pool, username)
176+ .await?
177+ .with_context(|| format!("l'utilisateur « {username} » n'existe pas"))?;
178+ let hash = password::hash(&password)?;
179+ users::update_password(&pool, user.id, &hash).await?;
180+ println!("Mot de passe de « {username} » mis à jour.");
181+ Ok(())
182+}
183+
162 /// `exego user join <username> --team <nom>` — rattache un compte184 /// `exego user join <username> --team <nom>` — rattache un compte
163 /// existant à une équipe (équivalent CLI d'une invitation acceptée).185 /// existant à une équipe (équivalent CLI d'une invitation acceptée).
164 pub async fn user_join(username: &str, team: &str) -> Result<()> {186 pub async fn user_join(username: &str, team: &str) -> Result<()> {
modified src/main.rs +9 -0
@@ -55,6 +55,12 @@ enum UserCommand {
5555 #[arg(long)]
5656 team: String,
5757 },
58+ /// Remplace le mot de passe d'un utilisateur
59+ SetPassword {
60+ username: String,
61+ #[arg(long)]
62+ password: Option<String>,
63+ },
5864 /// Ajoute un utilisateur existant à une équipe
5965 Join {
6066 username: String,
@@ -86,6 +92,9 @@ async fn main() -> Result<()> {
8692 team,
8793 },
8894 }) => cli::user_add(&username, password, &team).await,
95+ Some(Command::User {
96+ command: UserCommand::SetPassword { username, password },
97+ }) => cli::user_set_password(&username, password).await,
8998 Some(Command::User {
9099 command: UserCommand::Join { username, team },
91100 }) => cli::user_join(&username, &team).await,
@@ -55,6 +55,12 @@ enum UserCommand {
55 #[arg(long)]55 #[arg(long)]
56 team: String,56 team: String,
57 },57 },
58+ /// Remplace le mot de passe d'un utilisateur
59+ SetPassword {
60+ username: String,
61+ #[arg(long)]
62+ password: Option<String>,
63+ },
58 /// Ajoute un utilisateur existant à une équipe64 /// Ajoute un utilisateur existant à une équipe
59 Join {65 Join {
60 username: String,66 username: String,
@@ -86,6 +92,9 @@ async fn main() -> Result<()> {
86 team,92 team,
87 },93 },
88 }) => cli::user_add(&username, password, &team).await,94 }) => cli::user_add(&username, password, &team).await,
95+ Some(Command::User {
96+ command: UserCommand::SetPassword { username, password },
97+ }) => cli::user_set_password(&username, password).await,
89 Some(Command::User {98 Some(Command::User {
90 command: UserCommand::Join { username, team },99 command: UserCommand::Join { username, team },
91 }) => cli::user_join(&username, &team).await,100 }) => cli::user_join(&username, &team).await,