Password Validation
Dokumentasi utility functions untuk validasi dan manajemen password.
Overview
Package utils menyediakan functions untuk validasi password dan pengecekan expiration password.
Functions
IsPasswordValid
Memvalidasi apakah password memenuhi kriteria keamanan.
func IsPasswordValid(KataSandi string) bool
Validation Rules
| Rule | Deskripsi | Regex |
|---|---|---|
| Minimum Length | Minimal 8 karakter | len >= 8 |
| Lowercase | Minimal 1 huruf kecil | [a-z] |
| Uppercase | Minimal 1 huruf besar | [A-Z] |
| Digit | Minimal 1 angka | [0-9] |
| Special Character | Minimal 1 karakter spesial | [\W_] |
Example
// ✅ Valid passwords
utils.IsPasswordValid("Password1!") // true
utils.IsPasswordValid("MyP@ssw0rd") // true
utils.IsPasswordValid("Str0ng#Pass") // true
// ❌ Invalid passwords
utils.IsPasswordValid("password") // false - no uppercase, no digit, no special
utils.IsPasswordValid("PASSWORD1") // false - no lowercase, no special
utils.IsPasswordValid("Pass1!") // false - less than 8 characters
utils.IsPasswordValid("Password1") // false - no special character
Implementation
func IsPasswordValid(KataSandi string) bool {
if len(KataSandi) < 8 {
return false
}
hasLower := regexp.MustCompile(`[a-z]`).MatchString(KataSandi)
hasUpper := regexp.MustCompile(`[A-Z]`).MatchString(KataSandi)
hasDigit := regexp.MustCompile(`[0-9]`).MatchString(KataSandi)
hasSpecial := regexp.MustCompile(`[\W_]`).MatchString(KataSandi)
return hasLower && hasUpper && hasDigit && hasSpecial
}
CheckUmurSandi
Mengecek apakah password sudah expired dan mengirim notifikasi warning.
func CheckUmurSandi(result *models.Auth, token string) bool
Parameters
| Parameter | Type | Deskripsi |
|---|---|---|
result | *models.Auth | Data auth pengguna |
token | string | Authorization token untuk notifikasi |
Return
true- Password sudah expiredfalse- Password masih valid
Password Lifecycle
┌─────────────────────────────────────────────────────────────────────────────┐
│ PASSWORD LIFECYCLE │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Created/Updated ◀────────────────── 6 Months ──────────────────▶ Expired │
│ │ │ │
│ │ ┌─────────────────┐ │ │
│ │ │ WARNING ZONE │ │ │
│ │ │ (10 days) │ │ │
│ │ │ │ │ │
│ │ │ ┌───────────┐ │ │ │
│ │ │ │Notification│ │ │ │
│ │ │ │ Sent │ │ │ │
│ │ │ └───────────┘ │ │ │
│ │ └─────────────────┘ │ │
│ ▼ ▲ ▼ │
│ ┌─────────┐ │ ┌─────────┐ │
│ │ VALID │───────────────────────┼──────────────────────────│ EXPIRED │ │
│ └─────────┘ │ └─────────┘ │
│ │ │
│ Day 170 (10 days before expiry) │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Logic Flow
- Password belum pernah di-update → Set
UpdateAtSandike waktu sekarang, returnfalse - Dalam warning zone (10 hari sebelum expired) → Kirim notifikasi, return
false - Password expired (> 6 bulan) → Return
true - Password masih valid → Return
false
Example Usage
func Login(c *gin.Context) {
// ... authenticate user
// Check password expiration
isExpired := utils.CheckUmurSandi(&authResult, c.GetHeader("Authorization"))
if isExpired {
c.JSON(http.StatusUnauthorized, gin.H{
"code": 401,
"status": false,
"message": "Password expired. Please reset your password.",
"data": gin.H{
"requirePasswordReset": true,
},
})
return
}
// Continue with login...
}
Password Policy Summary
| Policy | Value |
|---|---|
| Minimum Length | 8 characters |
| Requires Lowercase | Yes |
| Requires Uppercase | Yes |
| Requires Digit | Yes |
| Requires Special Character | Yes |
| Expiration Period | 6 months |
| Warning Period | 10 days before expiry |
Special Characters Reference
Karakter spesial yang diterima (regex [\W_]):
! @ # $ % ^ & * ( ) - _ = + [ ] { } | \ ; : ' " , . < > / ? ` ~
Integration Example
func ChangePassword(c *gin.Context) {
var req dto.ChangePasswordRequest
if err := c.ShouldBindJSON(&req); err != nil {
helpers.SendError(c, helpers.NewBadRequest("Invalid request"))
return
}
// Validate new password
if !utils.IsPasswordValid(req.NewPassword) {
helpers.SendError(c, helpers.NewBadRequest(
"Password must be at least 8 characters with uppercase, lowercase, digit, and special character"))
return
}
// Validate password confirmation
if req.NewPassword != req.ConfirmPassword {
helpers.SendError(c, helpers.NewBadRequest("Password confirmation does not match"))
return
}
// Update password...
user.KataSandi = hashPassword(req.NewPassword)
user.UpdateAtSandi = time.Now()
repository.Update(&user)
c.JSON(http.StatusOK, gin.H{
"code": 200,
"status": true,
"message": "Password changed successfully",
})
}