chore: fix vulenrability

This commit is contained in:
2026-03-12 21:59:18 +01:00
parent f5902665ec
commit 9cb50bb625
12 changed files with 146 additions and 153 deletions
+47 -14
View File
@@ -270,35 +270,68 @@ func (d *Database) DecrementProductStockByID(productID int, quantity float64) er
return nil
}
// DeleteProductFromBasket supprime un produit spécifique du panier
// DeleteProductFromBasket supprime un produit spécifique du panier et restitue le stock.
func (d *Database) DeleteProductFromBasket(basketID int) error {
query := `DELETE FROM baskets WHERE id = $1`
result, err := d.Exec(query, basketID)
tx, err := d.Begin()
if err != nil {
return fmt.Errorf("erreur lors de la suppression du produit: %w", err)
return fmt.Errorf("erreur transaction: %w", err)
}
defer tx.Rollback()
rowsAffected, err := result.RowsAffected()
var productID int
var quantity float64
err = tx.QueryRow(
`SELECT product_id, quantity FROM baskets WHERE id = $1`,
basketID,
).Scan(&productID, &quantity)
if err != nil {
return fmt.Errorf("erreur lors de la vérification des lignes affectées: %w", err)
}
if rowsAffected == 0 {
return fmt.Errorf("produit non trouvé dans le panier")
}
return nil
_, err = tx.Exec(
`UPDATE products SET stock = stock + $1 WHERE id = $2`,
quantity, productID,
)
if err != nil {
return fmt.Errorf("erreur restitution stock: %w", err)
}
result, err := tx.Exec(`DELETE FROM baskets WHERE id = $1`, basketID)
if err != nil {
return fmt.Errorf("erreur lors de la suppression du produit: %w", err)
}
rows, _ := result.RowsAffected()
if rows == 0 {
return fmt.Errorf("produit non trouvé dans le panier")
}
return tx.Commit()
}
// ClearBasket vide complètement le panier d'un utilisateur
// ClearBasket vide complètement le panier d'un utilisateur et restitue les stocks.
func (d *Database) ClearBasket(username string) error {
query := `DELETE FROM baskets WHERE username = $1`
_, err := d.Exec(query, username)
tx, err := d.Begin()
if err != nil {
return fmt.Errorf("erreur transaction: %w", err)
}
defer tx.Rollback()
_, err = tx.Exec(`
UPDATE products p
SET stock = stock + b.quantity
FROM baskets b
WHERE b.username = $1 AND b.product_id = p.id
`, username)
if err != nil {
return fmt.Errorf("erreur restitution stock: %w", err)
}
_, err = tx.Exec(`DELETE FROM baskets WHERE username = $1`, username)
if err != nil {
return fmt.Errorf("erreur lors du vidage du panier: %w", err)
}
return nil
return tx.Commit()
}
// GetBasketTotal calcule le montant total du panier d'un utilisateur
-1
View File
@@ -89,7 +89,6 @@ func ValidateStatuses(statuses string) ([]string, error) {
"arrived": true,
"livre": true,
"approved": true,
"failed": true,
"cancelled": true,
}
+1 -1
View File
@@ -75,7 +75,7 @@ func (d *Database) ProcessNextCommandForDeliveryman(deliveryman string) error {
log.Printf("📊 [NEXT_COMMAND] Commande %d: statut = '%s'", commandID, currentStatus)
// ✅ Si la commande n'est plus assignable, la retirer et passer à la suivante
nonAssignableStatuses := []string{"livre", "approved", "cancelled", "disabled", "failed"}
nonAssignableStatuses := []string{"livre", "approved", "cancelled", "disabled"}
isNonAssignable := false
for _, s := range nonAssignableStatuses {
if currentStatus == s {
+38
View File
@@ -37,6 +37,44 @@ func (d *Database) CreditClientReferral(username string, amount float64) error {
return nil
}
// DebitReferralBalance déduit atomiquement le solde parrainage avant la création de commande.
// Gère sa propre transaction avec FOR UPDATE pour éviter le double-spend concurrent.
// Retourne une erreur si le solde est insuffisant.
func (d *Database) DebitReferralBalance(username string, amount float64) error {
if amount <= 0 {
return nil
}
tx, err := d.Begin()
if err != nil {
return fmt.Errorf("erreur transaction: %w", err)
}
var balance float64
if err := tx.QueryRow(
`SELECT referral_balance FROM clients WHERE username = $1 FOR UPDATE`,
username,
).Scan(&balance); err != nil {
tx.Rollback()
return fmt.Errorf("client non trouvé")
}
if balance < amount {
tx.Rollback()
return fmt.Errorf("solde parrainage insuffisant (disponible: %.2f€)", balance)
}
if _, err := tx.Exec(
`UPDATE clients SET referral_balance = referral_balance - $1 WHERE username = $2`,
amount, username,
); err != nil {
tx.Rollback()
return err
}
return tx.Commit()
}
// RestoreReferralBalance restaure le solde parrainage si la commande échoue après le débit.
func (d *Database) RestoreReferralBalance(username string, amount float64) error {
return d.CreditClientReferral(username, amount)
}
// UseClientReferralBalance déduit un montant du solde parrainage dans une transaction.
// Retourne une erreur si le solde est insuffisant.
func (d *Database) UseClientReferralBalance(tx *sql.Tx, username string, amount float64) error {