Documentation
¶
Index ¶
- Constants
- Variables
- func CleanSearchPath(p string) string
- func ValidateLabel(key, value string) error
- type AdminHolder
- type AdminLogEntry
- type ArchiveBacklogReport
- type ArchivePending
- type ArchiveState
- type Credential
- type DirectoryAccount
- type FileQuery
- type FileTouch
- type GroupMapping
- type LocalCredentialHolder
- type PendingUser
- type ProvisionRequest
- type PublicKey
- type PurgeResult
- type PurgedAccount
- type SessionFile
- type SessionStart
- type SettingView
- type StaleAccount
- type Store
- func (s *Store) AccountID(ctx context.Context, username string) (string, error)
- func (s *Store) AccountState(ctx context.Context, username string) (state string, confirmed time.Time, err error)
- func (s *Store) AddGroupMapping(ctx context.Context, externalGroup, roleName, actor string) error
- func (s *Store) AddLocalCredential(ctx context.Context, username, verifier, by string) error
- func (s *Store) AddPublicKey(ctx context.Context, username string, keyBlob []byte, comment string) error
- func (s *Store) AddSessionFiles(ctx context.Context, sessionID string, files []SessionFile) error
- func (s *Store) AdminLog(ctx context.Context, limit int) ([]AdminLogEntry, error)
- func (s *Store) AdminVia(ctx context.Context, username string) (string, error)
- func (s *Store) Admins(ctx context.Context) ([]AdminHolder, error)
- func (s *Store) AllTargetFacts(ctx context.Context) (map[string]model.TargetFacts, error)
- func (s *Store) AllowIdentityBind(ctx context.Context, username string, at time.Time) error
- func (s *Store) ApplyAdminGroup(ctx context.Context, members []string) (granted, revoked []string, err error)
- func (s *Store) ApprovePending(ctx context.Context, id, osUser, by string) (PendingUser, error)
- func (s *Store) ArchiveBacklog(ctx context.Context) (b ArchiveBacklogReport, err error)
- func (s *Store) ArchiveStateOf(ctx context.Context, sessionID string) (ArchiveState, bool, error)
- func (s *Store) ArchivedIDs(ctx context.Context, ids []string) (map[string]bool, error)
- func (s *Store) AssignRole(ctx context.Context, username, roleName string, expiresAt time.Time) error
- func (s *Store) BeginTOTP(ctx context.Context, username, secret string) error
- func (s *Store) BindDirIdentity(ctx context.Context, username, subject string) error
- func (s *Store) BindIdPSubject(ctx context.Context, username, issuer, subject string) error
- func (s *Store) ClaimArchives(ctx context.Context, limit int, now time.Time, ...) ([]ArchivePending, error)
- func (s *Store) ClaimByVerifiedEmail(ctx context.Context, email, issuer, subject string, adminGroupMember bool) (model.User, error)
- func (s *Store) Close() error
- func (s *Store) CloseOrphanSessions(ctx context.Context, at time.Time) (closed, queued int64, err error)
- func (s *Store) ConfirmAccount(ctx context.Context, username string, at time.Time) error
- func (s *Store) ConfirmTOTP(ctx context.Context, username string, step int64) error
- func (s *Store) CreateFromDirectory(ctx context.Context, acc DirectoryAccount) (model.User, error)
- func (s *Store) CreateRole(ctx context.Context, name string) (string, error)
- func (s *Store) CreateTarget(ctx context.Context, t model.Target) (string, error)
- func (s *Store) CreateUser(ctx context.Context, username, email, osUser string) (string, error)
- func (s *Store) DeleteRole(ctx context.Context, name string) error
- func (s *Store) DeleteSetting(ctx context.Context, key string) error
- func (s *Store) DeleteTarget(ctx context.Context, name string) error
- func (s *Store) DeleteTargetLabel(ctx context.Context, targetName, key, actor, via string) error
- func (s *Store) DeleteUser(ctx context.Context, username string) error
- func (s *Store) DirSubjectOf(ctx context.Context, username string) (string, error)
- func (s *Store) DisableTOTP(ctx context.Context, username string) error
- func (s *Store) EndSession(ctx context.Context, id string, endedAt time.Time) error
- func (s *Store) FileHistory(ctx context.Context, q FileQuery) ([]FileTouch, error)
- func (s *Store) FinishSyncRun(ctx context.Context, run SyncRun) error
- func (s *Store) FirstKeyAdded(ctx context.Context, username string) (bool, error)
- func (s *Store) ForgetPending(ctx context.Context, id string) error
- func (s *Store) GrantTarget(ctx context.Context, roleName, targetName string) error
- func (s *Store) GroupMappings(ctx context.Context) ([]GroupMapping, error)
- func (s *Store) HasIdPIdentity(ctx context.Context, username string) (bool, error)
- func (s *Store) ListPending(ctx context.Context) ([]PendingUser, error)
- func (s *Store) LocalCredential(ctx context.Context, username string) (Credential, error)
- func (s *Store) LocalCredentialHolders(ctx context.Context) ([]LocalCredentialHolder, error)
- func (s *Store) LogAdmin(ctx context.Context, e AdminLogEntry) error
- func (s *Store) MarkArchiveFailed(ctx context.Context, sessionID, reason string, permanent bool, at time.Time) error
- func (s *Store) MarkArchived(ctx context.Context, sessionID, bucket, key, sha string, size int64, ...) error
- func (s *Store) MarkDirectoryMissing(ctx context.Context, username string, at time.Time) error
- func (s *Store) MarkDirectorySeen(ctx context.Context, username string, at time.Time) error
- func (s *Store) MarkFirstKeyAdded(ctx context.Context, username string, at time.Time) error
- func (s *Store) Migrate(ctx context.Context) error
- func (s *Store) OpenSessions(ctx context.Context) ([]model.Session, error)
- func (s *Store) PendingByID(ctx context.Context, id string) (PendingUser, error)
- func (s *Store) PendingMigrations(ctx context.Context) (int, error)
- func (s *Store) Ping(ctx context.Context) error
- func (s *Store) ProvisionUser(ctx context.Context, req ProvisionRequest) (model.User, error)
- func (s *Store) PublicKeyCounts(ctx context.Context) (map[string]int, error)
- func (s *Store) PublicKeys(ctx context.Context, username string) ([]PublicKey, error)
- func (s *Store) PurgeAccount(ctx context.Context, username string, at time.Time) (PurgeResult, error)
- func (s *Store) PurgedAccounts(ctx context.Context) ([]PurgedAccount, error)
- func (s *Store) QueueArchive(ctx context.Context, sessionID string) error
- func (s *Store) RecordPending(ctx context.Context, p PendingUser) (string, error)
- func (s *Store) RecordTargetError(ctx context.Context, targetName, reason string) error
- func (s *Store) RecordTargetProbe(ctx context.Context, targetName string, p model.TargetProbe) error
- func (s *Store) RecordTargetProbeAttempt(ctx context.Context, targetName string, at time.Time) error
- func (s *Store) RecordTargetSeen(ctx context.Context, targetName string, f model.TargetFacts) error
- func (s *Store) RecordUnmappedGroups(ctx context.Context, groups []string) error
- func (s *Store) RefuseIfDeleted(ctx context.Context, username string) error
- func (s *Store) RefuseIfDeletedByID(ctx context.Context, id string) error
- func (s *Store) RejectPending(ctx context.Context, id, reason, by string) error
- func (s *Store) RemoveGroupMapping(ctx context.Context, externalGroup, roleName string) error
- func (s *Store) RemoveLocalCredential(ctx context.Context, username string) error
- func (s *Store) RemovePublicKey(ctx context.Context, username string, keyBlob []byte) error
- func (s *Store) ReplaceLocalCredential(ctx context.Context, username, verifier, by string) (replaced bool, err error)
- func (s *Store) RevokeRole(ctx context.Context, username, roleName string) error
- func (s *Store) RevokeTarget(ctx context.Context, roleName, targetName string) error
- func (s *Store) RoleGrantSource(ctx context.Context, username, roleName string) (source string, found bool, err error)
- func (s *Store) Roles(ctx context.Context) ([]model.Role, error)
- func (s *Store) RolesForGroups(ctx context.Context, groups []string) (roles, unmapped []string, err error)
- func (s *Store) Rollback(ctx context.Context) error
- func (s *Store) SchemaVersion(ctx context.Context) (int, error)
- func (s *Store) SeenGroupNames(ctx context.Context) ([]string, error)
- func (s *Store) Session(ctx context.Context, id string) (model.Session, error)
- func (s *Store) SessionFiles(ctx context.Context, sessionID string) ([]SessionFile, error)
- func (s *Store) Sessions(ctx context.Context, username string, limit int) ([]model.Session, error)
- func (s *Store) SetAccountState(ctx context.Context, username, state string) error
- func (s *Store) SetChosenPassword(ctx context.Context, username, verifier string, at time.Time) error
- func (s *Store) SetGroupAdmin(ctx context.Context, username string, admin bool) error
- func (s *Store) SetRecordingPathForTest(ctx context.Context, sessionID, path string) error
- func (s *Store) SetSearchTimeoutForTest(d time.Duration)
- func (s *Store) SetSetting(ctx context.Context, key, value string, encrypt bool, actor string) error
- func (s *Store) SetTargetLabel(ctx context.Context, targetName, key, value, actor, via string) error
- func (s *Store) SetUserAdmin(ctx context.Context, username string, admin bool) error
- func (s *Store) SetUserEmail(ctx context.Context, username, email string) error
- func (s *Store) SetUserOSUser(ctx context.Context, username, osUser string) error
- func (s *Store) SetUserSSOOnly(ctx context.Context, username string, ssoOnly bool) error
- func (s *Store) Setting(ctx context.Context, key string) (string, error)
- func (s *Store) Settings(ctx context.Context) ([]SettingView, error)
- func (s *Store) SourceAccountCount(ctx context.Context) (int, error)
- func (s *Store) StaleAccounts(ctx context.Context, olderThan time.Time, state string) ([]StaleAccount, error)
- func (s *Store) StartSession(ctx context.Context, rec SessionStart) error
- func (s *Store) StartSyncRun(ctx context.Context, source, trigger string, dryRun bool) (int64, error)
- func (s *Store) SyncCandidates(ctx context.Context) ([]SyncCandidate, error)
- func (s *Store) SyncRoles(ctx context.Context, username string, roleNames []string) error
- func (s *Store) SyncRuns(ctx context.Context, limit int) ([]SyncRun, error)
- func (s *Store) TOTP(ctx context.Context, username string) (TOTPCredential, error)
- func (s *Store) Target(ctx context.Context, name string) (model.Target, error)
- func (s *Store) TargetFacts(ctx context.Context, targetName string) (model.TargetFacts, error)
- func (s *Store) TargetLabels(ctx context.Context, targetName string) (map[string]string, error)
- func (s *Store) Targets(ctx context.Context) ([]model.Target, error)
- func (s *Store) TouchLocalCredential(ctx context.Context, username string, at time.Time) error
- func (s *Store) TryLockSync(ctx context.Context) (release func(), acquired bool, err error)
- func (s *Store) UnbindDirIdentity(ctx context.Context, username string) error
- func (s *Store) UnmappedGroups(ctx context.Context) ([]UnmappedGroup, error)
- func (s *Store) UseSecretBox(box *secret.Box)
- func (s *Store) UseTOTPStep(ctx context.Context, username string, step int64) error
- func (s *Store) User(ctx context.Context, username string) (model.User, error)
- func (s *Store) UserByDirSubject(ctx context.Context, subject string) (model.User, error)
- func (s *Store) UserByEmail(ctx context.Context, email string) (model.User, error)
- func (s *Store) UserByIdPSubject(ctx context.Context, issuer, subject string) (model.User, error)
- func (s *Store) UserByNameFold(ctx context.Context, name string) (string, error)
- func (s *Store) UserByPublicKey(ctx context.Context, keyBlob []byte) (model.User, error)
- func (s *Store) UserProfile(ctx context.Context, username string) (UserProfile, error)
- func (s *Store) Users(ctx context.Context) ([]model.User, error)
- type SyncCandidate
- type SyncRun
- type TOTPCredential
- type UnmappedGroup
- type UserProfile
Constants ¶
const ( StateActive = "active" StateInactive = "inactive" StateDeleted = "deleted" )
Hesap durumları.
const ( PendingWaiting = "waiting" PendingRejected = "rejected" )
Pending durumları.
const ( FileHistoryDefaultLimit = 200 FileHistoryMaxLimit = 1000 )
FileHistoryDefaultLimit / FileHistoryMaxLimit, geçmiş sorgusunun sınırları.
⚠️ DIŞARI AÇIKLAR çünkü kesilmiş bir listeyi "hepsi bu" diye göstermemek çağıranın işi: HTTP ucu, kaç satır istediğini bilmeden sonucun kırpılıp kırpılmadığını söyleyemez. Sınırı burada tutup orada bir kez daha yazsaydık, ikisi sessizce ayrışabilirdi.
Variables ¶
var ( // ErrNotFound, aranan kaydın olmadığını söyler. ErrNotFound = errors.New("store: not found") // ErrConflict, benzersizlik kısıtının ihlal edildiğini söyler // (aynı adla ikinci bir kullanıcı, rol, hedef...). ErrConflict = errors.New("store: already exists") // ErrInvalid: değerin kendisi kabul edilebilir değil — çağıranın // yeniden denemesi değil, DÜZELTMESİ gerekiyor. ErrConflict'ten // ayrı, çünkü "zaten var" ile "böyle olamaz" farklı cevaplar // gerektiriyor (409'a karşı 400). ErrInvalid = errors.New("store: invalid value") // ErrAccessDenied: kimlik geçerli ama postern'de karşılığı yok — // JIT sağlamada hiçbir grup role eşleşmediğinde. ErrAccessDenied = errors.New("store: access denied") // ErrIdentityConflict: kullanıcı adı var olan bir hesapla eşleşiyor // ama o hesap BAŞKA bir IdP kimliğine bağlı. // // ErrAccessDenied'dan AYRI TUTULUYOR çünkü ikisi operatöre bambaşka // şeyler söyler. "Grup eşlenmemiş" bir yapılandırma eksiğidir; bu // ise kullanıcı adı geri dönüşümü ya da hesap devralma denemesidir // — incelenmesi gereken bir olay. Tek bir sentinel altında // toplandığında giriş reddi "no mapped groups" diye loglanıyordu ve // olayı araştıran yönetici, düzeltmeyecek bir eşlemeyi düzeltmeye // gönderiliyordu. // // İstemciye giden yanıt İKİSİNDE DE aynı: ayrım yalnızca logda. ErrIdentityConflict = errors.New("store: identity conflict") /* * ErrAdminBindRefused: adı eşleşen bir YÖNETİCİ hesabını, ilk kez * görülen bir kimliğe bağlama denemesi. * * ErrIdentityConflict'ten AYRI, çünkü operatörün yapacağı şey * farklı: orada bir devralma denemesi var ve incelenmeli; burada * meşru bir yönetici de olabilir ve yolu açık — yöneticiliği * geçici olarak kaldırıp bağlaması yeterli. Aynı sentinel altında * toplansaydı, ikisi de "incelenecek olay" diye loglanır ve * gerçekten incelenmesi gereken seyrek olay gürültüye karışırdı. */ ErrAdminBindRefused = errors.New("store: administrator account cannot be claimed by username") /* * ErrAccountNotProvisioned: kimlik doğrulandı, postern hesabı yok ve * hesapların kendiliğinden açılması KAPALI. * * ⚠️ ErrAccessDenied'dan AYRI, çünkü çağıranın yapacağı şey farklı: * orada kapı kapanıyor, burada kişi onay kuyruğuna yazılıyor ve * bunu ekranda görüyor. Tek sentinel altında toplansalardı kuyruk * hiç dolmazdı. */ ErrAccountNotProvisioned = errors.New("store: account does not exist and auto-create is off") /* * ErrAdminPasswordRefused: yönetici hesabına kullanıcı parolası * konmak istendi. * * ⚠️ KURALI VERİTABANI TUTUYOR (göç 026), bu sentinel yalnızca onun * reddini konuşulabilir bir hataya çeviriyor. Burada bir `if` * yazmıyoruz: kural bir kez, kaçınılmaz olduğu yerde duruyor. * * Neden kural: acil durum kapısı tahmin edilebilir bir değere * bağlanamaz. Yönetici hesabının kimlik bilgisi makine üretimi * kalmak zorunda — postern'in "her şey bozulduğunda içeri girilir" * iddiası tam olarak buna dayanıyor. */ ErrAdminPasswordRefused = errors.New("store: an administrator account cannot hold a password") )
var ErrCredentialExists = errors.New("store: account already has a local credential")
ErrCredentialExists, hesabın zaten bir yerel kimlik bilgisi olduğunu söyler.
var ErrTooSlow = errors.New("store: search took too long and was stopped")
ErrTooSlow, arama sunucu tarafı zaman sınırına takıldı.
ErrInvalid DEĞİL: istek biçimsel olarak geçerliydi. Çağıranın söylemesi gereken şey "isteğin hatalı" değil, "bu arama fazla geniş".
Functions ¶
func CleanSearchPath ¶
* CleanSearchPath, ağaç aramasında kullanılacak yolu normalleştirir. * * ⚠️ DIŞARI AÇIK ÇÜNKÜ UÇ, ARANANI YANKILIYOR. Panel sonuçta * "under /etc/" yazıp sorgunun "/etc" ile çalıştığını gizleseydi, * denetçi neyin arandığını yanlış bilirdi — ve "moved here" rozetini * çizen istemci karşılaştırması da normalleştirilmemiş yola bakıp * kayardı. * * Sondaki eğik çizgiler atılıyor; hepsi eğik çizgiyse kök dizin.
func ValidateLabel ¶
ValidateLabel, anahtar/değer çiftini denetler.
DIŞA AÇIK, çünkü hedef yaratma yolu etiketleri hedefi AÇMADAN ÖNCE doğrulamak zorunda: önce açıp sonra etiketi reddetmek, yarısı uygulanmış bir istek bırakırdı.
Types ¶
type AdminHolder ¶
type AdminHolder struct {
Username string `json:"username"`
// Via: "cli", "group" ya da boş. Boş olan, admin_via sütunu
// eklenmeden önce yönetici yapılmış eski bir kayıttır (017 göçü
// mevcutları 'cli' sayıyor, yani pratikte boş kalmaması gerekir).
Via string `json:"via"`
}
AdminHolder, yönetici bayrağını taşıyan kişi ve bayrağın KAYNAĞI.
Kaynağı da taşıması şart: panel "kim yönetici" sorusuna cevap verirken "bunu kim verdi" sorusunu da cevaplamak zorunda. Aksi hâlde grup üzerinden gelen yetki ile acil durum için elle açılmış hesap ekranda ayırt edilemez ve operatör, kaldıramayacağı bir yetkiyi kaldırabileceğini sanır.
type AdminLogEntry ¶
type AdminLogEntry struct {
At time.Time
Actor string // web: oturum sahibi; cli: işletim sistemi kullanıcısı
Via string // "web" | "cli"
Action string // makine-okur: "user.create", "role.grant" ...
Entity string // etkilenen varlık adı
Details string
}
AdminLogEntry, tek bir yönetici işleminin kaydı.
type ArchiveBacklogReport ¶
type ArchiveBacklogReport struct {
Pending int
Oldest time.Time
Failing int
/*
* Lost, dosyası KAYIP olduğu için hiç yüklenemeyecek kayıtların
* sayısı (session_archives.permanent).
*
* ⚠️ Pending'DEN AYRI. Bunları "bekliyor" saymak, hiç bitmeyecek
* bir kuyruk ve sönmeyen bir "disk dolacak" alarmı demekti — oysa
* bu satırlar için yapılacak bir şey yok, yalnızca GÖRÜLMELERİ
* gerekiyor. "Kayıp" ile "bekliyor" operatöre bambaşka şey söyler.
*/
Lost int
}
* ArchiveBacklogReport, yükleme kuyruğunun durumu. * * ⚠️ Failing AYRI SAYILIYOR. "Bekleyen 40" ile "bekleyen 40, 40'ı da * üst üste başarısız" farklı iki durum: birincisi yükleyicinin geride * kalması, ikincisi hiç ilerlemediği. Arşivleyici hatanın kalıcı mı * geçici mi olduğunu zaten hesaplıyordu ama sonucu yalnızca log * cümlesini seçmek için kullanıyordu — operatörün baktığı ekranda bu * ayrım hiç görünmüyordu. * * Eşik ÜÇ: bir geçici kesinti bir iki denemeyi düşürür; üç üst üste * başarısızlık artık "bir şeyi düzeltmen gerekiyor" demektir.
type ArchivePending ¶
type ArchivePending struct {
SessionID string
RecordingPath string
StartedAt time.Time
Attempts int
}
ArchivePending, yüklenmeyi bekleyen bir kayıt.
type ArchiveState ¶
type ArchiveState struct {
Archived bool
ArchivedAt time.Time
Bucket string
ObjectKey string
SHA256 string
SizeBytes int64
Attempts int
LastError string
}
ArchiveState, bir oturumun arşiv durumu.
type Credential ¶
type Credential struct {
Verifier string
// Chosen: değeri KULLANICI seçti (parola). Değilse makine üretimi
// sır (015'in dünyası, acil durum kapısı).
Chosen bool
// MustChange: bir sonraki girişte değiştirilmek zorunda.
MustChange bool
}
* Credential, hesabın yerel kimlik bilgisi. Yoksa ErrNotFound. * * ⚠️ ARTIK DÜZ BİR DİZE DEĞİL. Eskiden yalnızca doğrulayıcı dönüyordu * ve doğruydu: tek bir kimlik bilgisi türü vardı. İki tür olduğu an * çağıranın HANGİ türle karşılaştığını bilmesi şart — yanlış doğrulama * yolunu seçmek, ya kullanıcıyı dışarıda bırakır ya da biçim kontrolünü * atlar. Türü çağıranın tahmin etmesine bırakmak yerine tek sorguda * veriyoruz.
type DirectoryAccount ¶
DirectoryAccount, dizinden kendiliğinden açılacak hesabın girdisi.
type FileQuery ¶
type FileQuery struct {
// Path, aranan yol. Under false ise TAM eşleşme.
Path string
/*
* Under: Path bir DİZİN, altındaki her şey aransın.
*
* ⚠️ SORUŞTURMANIN EN SIK SORDUĞU BU. "/etc altında ne oldu"
* sorusunu tam eşleşmeyle sormak imkânsız; her dosyayı tek tek
* bilmek gerekirdi.
*/
Under bool
// User / Target, olayın oturumundan süzme.
//
// ⚠️ Path'siz de anlamlılar: "ayse ne aldı" ve "web01'de ne oldu"
// soruşturmanın ikinci ve üçüncü sorusu.
User string
Target string
Limit int
}
* FileQuery, dosya geçmişi aramasının ölçütleri. * * ⚠️ EN AZ BİRİ DOLU OLMALI. Üçü birden boşken "her şeyi göster" * demek, sorulmamış bir soruya dolu bir ekranla cevap vermek olurdu — * bu ekranın kaçındığı şeyin ta kendisi.
type FileTouch ¶
type FileTouch struct {
SessionFile
/*
* Birleştirme LEFT JOIN, dolayısıyla bu alanlar boş kalabilir.
*
* ⚠️ BUGÜN BOŞ KALAMIYORLAR: 027'deki yabancı anahtar
* (ON DELETE RESTRICT) oturum satırının silinmesini engelliyor,
* yani her dosya olayının oturumu yerinde. LEFT JOIN yine de
* seçildi çünkü bedeli sıfır ve kısıt bir gün gevşetilirse doğru
* davranışı zaten yapıyor: olayın kendisi kanıt, yanındaki
* üstveriyi okuyamamak onu gizlemenin gerekçesi değil. Panel de
* bu ihtimale göre çiziyor (boş kullanıcıyı satırı yutarak değil,
* işaretleyerek gösteriyor).
*/
User string `json:"user"`
Target string `json:"target"`
OSUser string `json:"os_user"`
SrcIP string `json:"src_ip"`
}
* FileTouch, bir dosya olayı ve onu YAPAN oturumun kimliği. * * ⚠️ OTURUM KİMLİĞİ TEK BAŞINA CEVAP DEĞİL. "/etc/shadow'u kim aldı" * sorusunun cevabı bir UUID değil, bir kişidir; olayları çıplak * session_id'lerle döndürmek, denetçiyi her satır için ayrı bir * sorguya mecbur bırakırdı.
type GroupMapping ¶
GroupMapping, bir dış grubun hangi role karşılık geldiği.
type LocalCredentialHolder ¶
type LocalCredentialHolder struct {
Username string
IsAdmin bool
CreatedAt time.Time
CreatedBy string
LastUsedAt time.Time
// Chosen: değeri kullanıcı seçti (parola), makine üretmedi.
Chosen bool
// MustChange: ilk girişte değiştirilmek zorunda, yani henüz
// kullanılmamış bir "veren de biliyor" değeri.
MustChange bool
/*
* ⚠️ State BURADA OLMAK ZORUNDA.
*
* Ölçülen tutarsızlık: iki ayrı kilitlenme koruması (panelde
* canSwitchTo, CLI'da settings set) "yerel kimlik bilgisi olan bir
* yönetici var" gördüğünde paneli kapatmaya izin veriyor. Ama
* locallogin.go silinmiş hesabı REDDEDİYOR. Yani silinmiş bir
* yönetici, iki korumayı da tatmin edip kimsenin giremediği bir
* panel bırakabiliyordu. Durumu taşımayan bir liste, o soruyu
* cevaplayamaz.
*/
State string
}
LocalCredentialHolder, yerel kimlik bilgisi olan bir hesabın özeti.
type PendingUser ¶
type PendingUser struct {
ID string `json:"id"`
Subject string `json:"subject"`
Source string `json:"source"`
// ⚠️ Username, Email ve SeenGroups YALNIZCA GÖSTERİM. Hiçbir karar
// bunlara bakmıyor: üçü de kaynakta değişebiliyor.
Username string `json:"username"`
Email string `json:"email"`
SeenGroups []string `json:"seen_groups"`
State string `json:"state"`
FirstSeen time.Time `json:"first_seen"`
LastSeen time.Time `json:"last_seen"`
DecidedBy string `json:"decided_by,omitempty"`
DecidedAt time.Time `json:"decided_at,omitzero"`
Reason string `json:"reason,omitempty"`
}
PendingUser, onay bekleyen (ya da reddedilmiş) bir kimlik.
type ProvisionRequest ¶
type ProvisionRequest struct {
// Username, IdP'nin verdiği kullanıcı adı — aynı zamanda hedeflerdeki
// hesap adı olacak (os_user). Kurumsal ortamda "isim.soyisim".
Username string
Email string
// Groups, IdP'nin bildirdiği ham grup adları.
Groups []string
/*
* GroupsResolved, grupların GERÇEKTEN öğrenilip öğrenilmediği.
*
* ⚠️ SIFIR DEĞERİ false VE BU KASITLI. false iken SSO rollerine
* HİÇ DOKUNULMAZ. Alanı doldurmayı unutan bir çağrı yolu, rolleri
* TAZELEMEMİŞ olur — rolleri SİLMİŞ değil. İki yanlıştan geri
* dönülebilir olanı bu.
*
* Neden gerekti: kaynak "kullanıcıyı bulamadım" dediğinde de boş
* bir grup listesi geliyordu ve buradaki kod onu "hiçbir gruba üye
* değil" diye okuyup bütün SSO rollerini siliyordu. Giriş yolunda
* ne bekleme süresi ne tavan var; senkronizasyon döngüsündeki
* korumaların hiçbiri burada çalışmıyor.
*/
GroupsResolved bool
// Issuer ve Subject, IdP kimliğinin KALICI anahtarı (OIDC "iss" ve
// "sub"). Username DEĞİL bunlar eşleştirme anahtarıdır: username
// birçok sağlayıcıda değiştirilebilir ve geri dönüştürülebilir.
// Boş bırakılırsa eşleştirme yapılamaz ve ProvisionUser reddeder.
Issuer string
Subject string
/*
* AdminGroupMember, GELEN KİMLİĞİN kendisinin yönetici grubunda
* olduğu.
*
* ⚠️ Adı bir yöneticiyle eşleşen hesabı devralmanın önündeki kapıyı
* bu açıyor — ve açması doğru: yönetici grubunda olan kişi zaten
* yöneticidir, başka bir yönetici hesabını almakla YENİ bir yetki
* kazanmaz. Kapatsaydık, dizin grubundan yönetici olan herkes
* yükseltmeden sonra kendi hesabına giremezdi.
*
* ⚠️ Çağıran bunu YALNIZCA grupları gerçekten çözülmüşken true
* yapmalı. Sıfır değeri false ve bu kasıtlı: alanı doldurmayı
* unutan bir yol, kapıyı AÇMIŞ değil KAPATMIŞ olur.
*/
AdminGroupMember bool
/*
* AutoCreate, hesabın KENDİLİĞİNDEN açılabileceği.
*
* ⚠️ Sıfır değeri false ve bu kasıtlı: alanı doldurmayı unutan bir
* çağrı yolu hesap AÇMAZ, açar değil. İki yanlıştan geri
* dönülebilir olanı bu.
*
* Kapalıyken kullanıcı ErrAccountNotProvisioned alıyor ve çağıran
* onu onay kuyruğuna yazıyor — kapıda bırakmıyor.
*/
AutoCreate bool
}
ProvisionRequest, JIT sağlama için kimlik sağlayıcıdan gelen bilgi.
type PurgeResult ¶
PurgeResult, purge'ün neyi serbest bıraktığı.
type PurgedAccount ¶
PurgedAccount, purge edilmiş bir kaydın izi.
type SessionFile ¶
type SessionFile struct {
ID string `json:"id"`
SessionID string `json:"session_id"`
At time.Time `json:"at"`
Op string `json:"op"`
Path string `json:"path"`
NewPath string `json:"new_path,omitempty"`
Flags string `json:"flags,omitempty"`
Read int64 `json:"read"`
Wrote int64 `json:"wrote"`
OK bool `json:"ok"`
Detail string `json:"detail,omitempty"`
}
SessionFile, bir oturumda gerçekleşen tek bir dosya olayı.
type SessionStart ¶
type SettingView ¶
type SettingView struct {
Key string
Value string // şifreliyse maskeli
Secret bool
UpdatedAt time.Time
UpdatedBy string
}
SettingView, listeleme için ayar görünümü.
type StaleAccount ¶
type StaleAccount struct {
Username string
State string
Confirmed time.Time
SSOOnly bool
DirBound bool
ManualRoles int
}
StaleAccount, süresi dolmuş bir hesabın özeti.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
func (*Store) AccountID ¶
* AccountID, adı verilen hesabın kimliğini (users.id) döner. * * ⚠️ Panel oturumu bu KİMLİĞE bağlanıyor, ada değil. Ad yeniden * kullanılabiliyor (purge onu serbest bırakıyor); kimlik kalıcı. Oturum * ada bağlı kalırsa, adı devralan yeni kişiye çözülüyor.
func (*Store) AccountState ¶
func (s *Store) AccountState(ctx context.Context, username string) (state string, confirmed time.Time, err error)
AccountState, hesabın durumu ve son doğrulanma anı.
func (*Store) AddGroupMapping ¶
AddGroupMapping, dış grubu role bağlar. Rol yoksa ErrNotFound; aynı eşleme ikinci kez eklenirse ErrConflict.
func (*Store) AddLocalCredential ¶
* AddLocalCredential, hesaba yerel kimlik bilgisi bağlar. * * ⚠️ ÜSTÜNE YAZMAZ. Var olan bir kimlik bilgisini sessizce * değiştirmek, komutu ikinci kez çalıştıran operatörün ELİNDEKİ sırrı * geçersiz kılardı — üstelik o an ekranda yeni bir sır gördüğü için * bunu fark etmeden. Daha kötüsü: kurulumun tek yöneticisinin kimlik * bilgisini, yazma yetkisi olan herkes böylece döndürebilirdi. * Değiştirmek istiyorsa açık bir komut kullanır.
func (*Store) AddPublicKey ¶
func (*Store) AddSessionFiles ¶
* AddSessionFiles, bir grup olayı TEK transaction'da yazar. * * ⚠️ Toplu yazım şart: rsync gibi bir istemci binlerce küçük dosyaya * dokunur ve olay başına ayrı gidiş-dönüş, denetimi transferin hız * sınırı hâline getirirdi. Denetimi yavaşlatmak, onu kapatma isteği * doğurur. * * Ya hepsi yazılır ya hiçbiri: yarım yazılmış bir grup, "dosya açıldı * ama hiç kapanmadı" gibi görünen uydurma bir denetim satırı bırakırdı.
func (*Store) AdminVia ¶
AdminVia, yönetici yetkisinin kaynağını döner: "cli", "group" ya da boş (yönetici değil).
func (*Store) Admins ¶
func (s *Store) Admins(ctx context.Context) ([]AdminHolder, error)
Admins, yönetici bayrağı taşıyan herkesi kaynağıyla döner.
func (*Store) AllTargetFacts ¶
AllTargetFacts, hedef adı → gözlemler.
TEK SORGU: hedef başına ayrı sorgu, ana ekranı çizerken kullanıcının erişebildiği her hedef için bir gidiş dönüş demekti (N+1). Etiketlerde aynı gerekçeyle allTargetLabels var.
func (*Store) AllowIdentityBind ¶
AllowIdentityBind, bir yönetici hesabının SIRADAKİ kimlik bağlamasına izin verir. Tek kullanımlık.
func (*Store) ApplyAdminGroup ¶
func (s *Store) ApplyAdminGroup(ctx context.Context, members []string) (granted, revoked []string, err error)
* ApplyAdminGroup, grup üzerinden yönetici kümesini TEK İŞLEMDE eşitler. * * ⚠️ NEDEN "bir sonraki girişte" DEĞİL, ŞİMDİ: * * Yetki eskiden yalnızca kişi giriş yaptığında güncelleniyordu. Bu, * yönetici grubu DEĞİŞTİĞİNDE sessiz bir sızıntı bırakıyor: eski gruptan * gelen kişi bir daha hiç giriş yapmasa da yönetici KALIYOR. "Grubu * değiştirdim" ile "yetki değişti" arasındaki fark, kimsenin bakmadığı * bir yerde süresiz açık duruyordu. * * Ayrıca onay ekranını dürüst yapan şey bu: ekran "bu kişiler yönetici * oluyor" diyorsa, kaydettikten sonra gerçekten öyle olmalı — "herkes * bir dahaki girişinde" değil. * * members'ın DB'de karşılığı olmayanları ATLANIR (hata değil): dizinde * var ama postern'e hiç girmemiş kişinin hesabı yok. İlk girişinde * applyGroupAdmin onu zaten yakalar. * * CLI'ın verdiği yöneticiliğe DOKUNMAZ — ne verirken ne alırken.
func (*Store) ApprovePending ¶
* ApprovePending, hesabı AÇAR ve kimliği bağlar. * * ⚠️ ROL VERMİYOR. Roller kişinin bir sonraki girişinde CANLI kaynaktan * çözülüyor; kuyruktaki grup listesi onay ekranında ne görüldüğünü * gösteriyor, bir yetki kaydı değil. Bayat bir fotoğrafa göre rol * yazmak, yetkiyi geçmişe bağlamak olurdu. * * Hesap ve bağ AYNI transaction'da: arada kalan bir hata, kimliği * bağlanmamış bir hesap bırakır ve o hesap sonra ADLA devralınabilir * hâle gelirdi.
func (*Store) ArchiveBacklog ¶
func (s *Store) ArchiveBacklog(ctx context.Context) (b ArchiveBacklogReport, err error)
ArchiveBacklog, bekleyen kayıt sayısı ve EN ESKİSİNİN yaşı.
⚠️ YAŞ, SAYIDAN DAHA ÖNEMLİ. Ölmüş bir yükleyicinin belirtisi "sayı artıyor" değil, "en eskisi yaşlanıyor": sabit bir sayı da hiçbir şeyin ilerlemediği anlamına gelebilir.
func (*Store) ArchiveStateOf ¶
ArchiveStateOf, panelin gösterdiği durum.
func (*Store) ArchivedIDs ¶
* ArchivedIDs, verilen oturumlardan HANGİLERİNİN doğrulanmış şekilde * arşivlendiğini döner. * * ⚠️ BUDAYICININ KAPISI BU ve varsayılan REDDETME: dönen kümede * OLMAYAN her kimlik "silme" demek. Sorgu hata verirse çağıran koşuyu * iptal ediyor — hiçbir şey silmeden. "Çözemedim" ile "güvende" aynı * şey değil ve burada karıştırmanın bedeli kanıtın yok olması.
func (*Store) AssignRole ¶
func (s *Store) AssignRole(ctx context.Context, username, roleName string, expiresAt time.Time) error
AssignRole, kullanıcıya ELLE rol verir (source='manual').
expiresAt sıfır ise süresiz. Zaten verilmiş bir rolü tekrar vermek hata değil — ama artık tam olarak no-op da değil: expires_at GÜNCELLENİR, çünkü "bu yetkiyi uzat" doğal bir istek ve ayrı bir komut gerektirmesi için sebep yok.
Kullanıcı ya da rol yoksa ErrNotFound.
func (*Store) BeginTOTP ¶
* BeginTOTP, kayıt başlatır (ya da BAŞTAN başlatır). * * ⚠️ Doğrulanmış bir kaydın üzerine YAZMIYOR. Yazsaydı, oturumu çalınan * bir hesapta saldırgan kaydı sıfırlayıp kendi telefonunu bağlar ve * ikinci faktör sessizce el değiştirirdi. Doğrulanmış kaydı değiştirmek * ancak önce onu kapatmakla (DisableTOTP, kod ister) mümkün.
func (*Store) BindDirIdentity ¶
* BindDirIdentity, bir postern hesabını bir dizin kimliğine bağlar. * * ⚠️ YALNIZCA HENÜZ BAĞLI DEĞİLSE (`dir_subject IS NULL`). Var olan bir * bağı sessizce değiştirmek, tam olarak önlenmeye çalışılan devralmayı * geri getirirdi — 011'in BindIdPSubject'teki aynı kuralı. * * Zaten başka bir kimliğe bağlıysa ErrConflict; başka bir HESAP o * kimliği tutuyorsa benzersiz indeks ihlali yine ErrConflict'e çevrilir. * İki durum da "buradan devam etme" demek.
func (*Store) BindIdPSubject ¶
BindIdPSubject, bir postern hesabını bir IdP kimliğine bağlar.
SADECE HENÜZ BAĞLI DEĞİLSE: WHERE koşulu idp_subject IS NULL. Var olan bir bağı sessizce değiştirmek, tam olarak önlemeye çalıştığımız devralmayı geri getirirdi. Zaten bağlıysa ErrConflict.
func (*Store) ClaimArchives ¶
func (s *Store) ClaimArchives(ctx context.Context, limit int, now time.Time, claimTimeout, retryAfter time.Duration) ([]ArchivePending, error)
* ClaimArchives, yüklenecek işleri üstlenir. * * ⚠️ ÜSTLENME ZAMAN AŞIMIYLA SERBEST KALIYOR, temizlikle değil. * Öldürülen bir süreç hiçbir şey temizleyemez; claimed_at'i eski olan * satırı yeniden üstlenilebilir saymak, yeniden başlatmadan sonra işin * kendiliğinden devam etmesinin tek yolu. * * ⚠️ GERİ ÇEKİLME last_attempt_at ÜZERİNDEN: az önce denenmiş ve * başarısız olmuş bir satırı hemen yeniden almak, kesinti sırasında * depoyu ve log'u boğardı. * * ⚠️ GERİ ÇEKİLME ÜSTEL — VE SABİTTİ. Her başarısız satır her turda * yeniden alınıyordu; arşivleyici hatanın kalıcı mı geçici mi olduğunu * HESAPLIYOR (objstore.ErrTransient) ama sonucu yalnızca log cümlesini * seçmek için kullanıyordu. Yanlış yazılmış bir kova adı ya da * reddedilen bir imza, düzeltilene kadar her turda yeniden denenip * log'u dolduruyordu — ve içindeki gerçek, geçici arızayı görünmez * yapıyordu. * * attempts ile katlanıyor, altıncıda duruyor: retryAfter=1dk ile * 1, 2, 4, 8, 16, 32, 64 dakika. Kalıcı olarak "vazgeçildi" diye * işaretlemiyoruz ve bu bilinçli — operatör kovayı düzelttiğinde * yeni bir komut çalıştırmak zorunda kalmasın; sıra kendiliğinden * ilerlesin.
func (*Store) ClaimByVerifiedEmail ¶
func (s *Store) ClaimByVerifiedEmail(ctx context.Context, email, issuer, subject string, adminGroupMember bool) (model.User, error)
* ClaimByVerifiedEmail, giriş yollarının E-POSTA dalı için: hesabı * bulur ve aynı kapıdan geçirir. * * ⚠️ ProvisionUser KULLANILAMAZ, çünkü o gruplar çözülemediğinde * REDDEDİYOR — ve haklı: yeni bir hesap açıp açmamaya karar verecek * bilgi yok. Ama burada hesap ZATEN VAR; verilecek karar "bu kimlik bu * hesabı alabilir mi", ve o karar gruplara bağlı değil.
func (*Store) CloseOrphanSessions ¶
func (s *Store) CloseOrphanSessions(ctx context.Context, at time.Time) (closed, queued int64, err error)
* CloseOrphanSessions, açılışta sahipsiz kalmış oturum satırlarını kapatır. * * ⚠️ ÖLÇÜLEN ARIZA: postern SIGKILL alırsa (çökme, güç kesintisi, * `kill -9`) açık oturumların ended_at'i SONSUZA DEK NULL kalıyor. * Ölçüldü: bir oturum açıkken süreç öldürülüp yeniden başlatıldıktan * sonra satır hâlâ açıktı. Panel onu süresiz "çalışıyor" gösteriyor. * Kesme düğmesi bunu pasif bir görüntü hatasından aktif bir yalana * çeviriyordu: yönetici var olmayan bir oturumu kesmeye çalışırdı. * * ⚠️ YENİ BAŞLAYAN SÜREÇ HİÇBİR OTURUMA SAHİP DEĞİLDİR — kuralın * dayandığı tek önerme bu ve TEK DÜĞÜM varsayımıyla geçerli. İkinci bir * postern aynı veritabanına bağlıysa bu çağrı ONUN canlı oturumlarını * kapatır. 1.0 tek düğüm olduğu için kabul ediliyor; belgelerde * "bilinen sınırlar" altında yazılı. * * ⚠️ SATIR SİLİNMİYOR, KAPATILIYOR. Denetim izi kalmalı: "ne zaman * bittiğini bilmiyoruz" ile "hiç olmadı" ayrı şeyler. ended_at * açılış anı — gerçek bitişten sonra, yani süre OLDUĞUNDAN UZUN * görünebilir; bu yüzden çağıran kaç satır kapandığını LOG'A yazmalı.
func (*Store) ConfirmAccount ¶
* ConfirmAccount, kaynağın bu kişiyi ŞU AN doğruladığını kaydeder. * * ⚠️ HER BAŞARILI GİRİŞTE çağrılmalı — OIDC, dizin, hepsi. Zaman * temelli iptalin tek girdisi bu damga; koyulmayan bir kapı, o kapıdan * girenleri yavaş yavaş pasifleştirirdi. * * ⚠️ VE HESABI GERİ AKTİF EDİYOR. Pasifleşme "kaynak bunu bir süredir * doğrulamadı" demek; kaynak yeniden doğruladığı anda sebep ortadan * kalkıyor. Elle müdahale gerektirseydi, tatilden dönen herkes * yöneticiye başvururdu. * * 'deleted' hesap KENDİLİĞİNDEN geri gelmiyor: orada bir insan kararı * var (ya da uzun bir sessizlik) ve onu bir girişin sessizce bozması * doğru olmaz.
func (*Store) ConfirmTOTP ¶
* ConfirmTOTP, kaydı DOĞRULANMIŞ işaretler. * * Yalnızca doğrulanmamış bir kayıt onaylanabilir: ikinci bir onay * çağrısı, kullanılmış bir adımı geri açmamalı.
func (*Store) CreateFromDirectory ¶
* CreateFromDirectory, dizin kimliğinden hesap açar ve BAĞLAR. * * ⚠️ ROL EŞLEMESİ KAPIDA. Hiçbir grup bir role eşleşmiyorsa hesap * AÇILMIYOR (ErrAccessDenied). Bu, OIDC yolundaki ProvisionUser'ın * aynı sözleşmesi: "IdP'de hesabın olması postern'de hesabın olması * demek değil" kuralının otomatik açılıştaki karşılığı. Onsuz users * tablosu, hiçbir yere erişemeyen kayıtlarla dizinin kopyasına * dönüşürdü. * * ⚠️ Hesap ve bağ AYNI transaction'da: bağlanmamış bir hesap, adla * devralınabilir bir hesaptır.
func (*Store) CreateRole ¶
func (*Store) CreateTarget ¶
func (*Store) CreateUser ¶
func (*Store) DeleteRole ¶
DeleteRole: rolün bağları (user_roles, role_targets) CASCADE ile gider; sessions rolü referanslamadığı için 787 bu yoldan çıkmaz — kontrol yine de duruyor, şema yarın değişirse sessizce yanlış hataya düşmeyelim.
func (*Store) DeleteSetting ¶
Setting, tek bir ayarı döner; şifreliyse çözer. Yoksa ErrNotFound.
Anahtar yapılandırılmamışken şifreli bir ayara dokunmak AÇIK hata verir: boş string dönmek sırrı silinmiş gibi gösterir ve LDAP'ın parolasız bağlanmaya çalışmasına yol açardı. DeleteSetting, bir ayarı siler. Yoksa ErrNotFound.
Sır düşürmek için var: LDAP adresi değişince saklanan bind parolası düşürülüyor (bkz. httpapi.adminSetSetting). Değeri boşa çekmek yerine SATIRI silmek gerekiyor — boş bir değer "ayarlanmış ama boş" demek ve LoadConfig onu farklı yorumluyor.
func (*Store) DeleteTarget ¶
DeleteTarget, hedefi ve rol bağlarını (CASCADE) kaldırır. Yoksa ErrNotFound; oturum kaydı varsa ErrConflict — denetim kaydı olan varlık silinmez, bu bir kısıt değil özellik (ayrıntı: isFKRestrict).
func (*Store) DeleteTargetLabel ¶
DeleteTargetLabel, etiketi kaldırır. Yoksa ErrNotFound.
func (*Store) DeleteUser ¶
DeleteUser: kullanıcıyı, bağlarını ve anahtarlarını kaldırır. Oturum kaydı olan kullanıcı için ErrConflict. Erişimi kesmenin doğru yolu zaten silmek değil: anahtarlarını ve rollerini almak — kayıt kalır, kapı kapanır.
func (*Store) DirSubjectOf ¶
DirSubjectOf, hesabın bağlı olduğu dizin kimliğini döner; bağlı değilse boş dize.
func (*Store) DisableTOTP ¶
DisableTOTP, ikinci faktörü kaldırır.
func (*Store) EndSession ¶
func (*Store) FileHistory ¶
* FileHistory, ölçütlere uyan dosya olaylarını en yeniden eskiye döner. * * Soruşturmanın sorusu bu: "/etc/shadow'u kim aldı". Oturumdan dosyaya * bakan bir arayüz bu soruyu cevaplayamaz — soruşturma dosyayı bilir, * oturumu bilmez. * * ⚠️ HEDEF YOLA DA BAKIYOR. Bir dosya bir yere rename ile gelmiş * olabilir ve o satırda aranan yol `path`te değil `new_path`te durur. * Yalnızca `path`e bakan bir arama, "/tmp/exfil buraya nereden geldi" * sorusuna "hiç dokunulmamış" cevabını verirdi — dosyayı oraya taşıyan * satır elimizdeyken. * * ⚠️ BOŞ ÖLÇÜT REDDEDİLİYOR — VE SEBEBİ ÖLÇÜLDÜ. Yalnızca yol * korumasını kaldırıp denedik: sorgu boş bir yol için BOŞ LİSTE * dönüyor (`new_path <> ”` koşulu, satırların çoğundaki boş * new_path'in eşleşmesini engelliyor). Yani tehlike rastgele bir liste * değil, boş bir liste: hiç sorulmamış bir soru "bu dosyaya * dokunulmamış" diye cevaplanmış görünürdü. * * ⚠️ ZAMAN SINIRLI ÇALIŞIYOR (searchtimeout.go). Ölçütler dışarıdan * geliyor ve havuzu SSH girişleri paylaşıyor.
func (*Store) FinishSyncRun ¶
FinishSyncRun, koşuyu sonuçlandırır.
Satır 'failed' olarak AÇILIYOR ve burada güncelleniyor: süreç ortasında ölürse kayıt "başarılı" değil "başarısız" kalır — sessizce başarılı görünen bir yarım koşu, olmayan bir senkronizasyona güvenilmesi demek olurdu.
func (*Store) FirstKeyAdded ¶
* FirstKeyAdded, hesabın ilk anahtarını EKLEMİŞ olup olmadığı. * * ⚠️ SAYIYA DEĞİL DAMGAYA BAKIYOR. "Şu an anahtarı var mı" diye sorsaydık * sil-ve-ekle kuralı tamamen atlardı: oturumu ele geçiren kişi mevcut * anahtarı siler, sayaç sıfırlanır, yeni anahtarı bedavaya ekler. Damga * bir kez konuyor ve bir daha kalkmıyor.
func (*Store) ForgetPending ¶
ForgetPending, satırı tamamen siler — reddi geri almanın yolu.
Var olması şart: yanlışlıkla reddedilen biri, aksi hâlde bir daha hiç başvuramazdı.
func (*Store) GrantTarget ¶
func (*Store) GroupMappings ¶
func (s *Store) GroupMappings(ctx context.Context) ([]GroupMapping, error)
GroupMappings, tüm eşlemeleri grup adına göre sıralı döner.
func (*Store) HasIdPIdentity ¶
HasIdPIdentity, hesabın bir OIDC kimliğine bağlı olup olmadığı.
hasIdPIdentity'nin dışa açık eşi: sihirbaz "bu yönetici kaynağı çevirince kendini kilitler mi" sorusunu buradan soruyor.
func (*Store) ListPending ¶
func (s *Store) ListPending(ctx context.Context) ([]PendingUser, error)
ListPending, kuyruğu döner (bekleyenler önce, en yeni başta).
func (*Store) LocalCredential ¶
LocalCredential, hesabın kimlik bilgisini döner. Yoksa ErrNotFound.
func (*Store) LocalCredentialHolders ¶
func (s *Store) LocalCredentialHolders(ctx context.Context) ([]LocalCredentialHolder, error)
* LocalCredentialHolders, yerel kimlik bilgisi olan hesapları döner. * * ⚠️ GÖRÜNÜRLÜK BİR GÜVENLİK ÖZELLİĞİ. Bu hesaplar bir acil durum * kapısı ve kullanılmayan bir acil durum kapısı unutulmuş bir kapıdır. * Operatörün "kimlerde var, en son ne zaman kullanıldı" sorusunu * veritabanına girmeden cevaplayabilmesi gerekiyor.
func (*Store) LogAdmin ¶
func (s *Store) LogAdmin(ctx context.Context, e AdminLogEntry) error
LogAdmin, bir yönetici işlemini deftere yazar (sıfır At damgalanır).
Çağıran, işlemi BAŞARIYLA bitirdikten sonra çağırır — başarısız denemeler HTTP log'unda zaten var; defter, "ne değişti"nin kaydı.
func (*Store) MarkArchiveFailed ¶
func (s *Store) MarkArchiveFailed(ctx context.Context, sessionID, reason string, permanent bool, at time.Time) error
MarkArchiveFailed, denemeyi ve sebebini kaydeder.
archived_at'e DOKUNMUYOR: bir kez doğrulanmış kayıt, sonradan gelen bir hata yüzünden "güvende değil"e dönmemeli.
⚠️ permanent: bu kayıt hiç yüklenemeyecek (ör. dosyası yok). true ise satır candidate kümesinden çıkıyor; yoksa her turda yeniden claim edilip kuyruğu ve "disk dolacak" alarmını sonsuza dek meşgul ederdi.
func (*Store) MarkArchived ¶
func (s *Store) MarkArchived(ctx context.Context, sessionID, bucket, key, sha string, size int64, at time.Time) error
* MarkArchived, yüklemenin DOĞRULANDIĞINI kaydeder. * * ⚠️ SIRA: yükle → deponun kendisine sor → BURAYA yaz → budayıcıya * silme izni doğ. Bu satır atıldığı andan itibaren kayıt yerelden * silinebilir hâle geliyor, dolayısıyla "gönderdim" ile "orada" * arasındaki farkı burada kapatmak zorundayız.
func (*Store) MarkDirectoryMissing ¶
MarkDirectoryMissing, kullanıcının bulunamadığını kaydeder.
COALESCE: kayıp saati YALNIZCA henüz kurulmamışsa kuruluyor. Her koşuda üzerine yazmak, grace penceresini gerçek bir saat olmaktan çıkarıp hiç dolmayan bir sayaca çevirirdi.
func (*Store) MarkDirectorySeen ¶
MarkDirectorySeen, kullanıcının dizinde bulunduğunu kaydeder ve kayıp saatini SIFIRLAR.
func (*Store) MarkFirstKeyAdded ¶
MarkFirstKeyAdded, damgayı koyar. Zaten varsa DOKUNMAZ — ilk anahtarın anı, sonradan eklenenlerle kaymamalı.
func (*Store) OpenSessions ¶
* OpenSessions, bitişi kaydedilmemiş bütün oturumları döner. * * ⚠️ AYRI BİR SORGU, Sessions(...200) ÜZERİNDE SÜZGEÇ DEĞİL. * * ÖLÇÜLEN ARIZA: panel "Active sessions" kartını en yeni 200 satırı * çekip istemcide `!ended_at` diye süzerek kuruyordu (Overview.tsx:158, * admin.go:739). Sabahtan beri açık duran bir oturumun üstüne 200 yeni * oturum bindiğinde, o oturum karttan tamamen düşüyor: yönetici onu * göremiyor, dolayısıyla kesemiyor da. Açık oturumları saymak için * geçmişin ilk 200 satırına bakmak, yanlış soruyu sormaktı. * * ⚠️ SINIRSIZ DEĞİL. Açık oturum sayısı bağlantı sınırlarıyla zaten * bağlı (listen.max_conns), ama uzlaştırılmamış hayalet satırlar * birikebiliyor (bkz. CloseOrphanSessions). Tavan, panelin bir kazayla * bütün tabloyu çekmesini engelliyor.
func (*Store) PendingByID ¶
PendingByID, tek satır.
func (*Store) PendingMigrations ¶
func (*Store) Ping ¶
Ping, veritabanına ulaşılabildiğini doğrular.
⚠️ Sağlık ucu için var ve BAŞKA HİÇBİR ŞEY YAPMIYOR: bir sorgu çalıştırmak, kimlik istemeyen bir uçtan tetiklenebilen iş demekti.
func (*Store) ProvisionUser ¶
ProvisionUser, IdP kimliğinden kullanıcıyı oluşturur/günceller ve SSO rollerini senkronize eder. Dönen değer yetkileriyle birlikte kullanıcıdır.
SÖZLEŞME: hiçbir grup role eşleşmiyorsa kullanıcı OLUŞTURULMAZ ve ErrAccessDenied döner. "IdP'de hesabın olması postern'de hesabın olması demek değil" kuralının JIT çağındaki hâli — sadece "elle ekle" yerine "grubunu eşle" oldu. Yan faydası: users tablosu IdP'nin tüm dizinine dönüşmez, yalnızca gerçekten erişimi olanları içerir.
Var olan kullanıcı için: eşleşme kalmadıysa kullanıcı SİLİNMEZ (denetim kaydı ona bağlı) ama SSO rolleri temizlenir — erişim biter, iz kalır.
func (*Store) PublicKeyCounts ¶
* PublicKeyCounts, kullanıcı adı → anahtar sayısı. * * ⚠️ TEK SORGU, KULLANICI BAŞINA BİR SORGU DEĞİL. * * Liste bu sayıyı eskiden satır başına PublicKeys() çağırarak * topluyordu: 200 kullanıcılı bir kurulumda tek bir sayfa açılışı 201 * sorgu demekti ve dönen anahtarların BLOB'ları da okunup atılıyordu — * ekranda görünen tek şey bir sayıyken. * * Sayı ekranda kalmak zorunda: "kim hiç bağlanamıyor" sorusunun cevabı * bu ve onu göstermeyen bir liste, yöneticiyi her kullanıcıyı tek tek * açmaya gönderiyordu. * * Adı serbest bırakılmış satırlar dışarıda: onları Users() da * göstermiyor ve aynı ürünün iki farklı cevabı olmamalı.
func (*Store) PublicKeys ¶
func (*Store) PurgeAccount ¶
func (s *Store) PurgeAccount(ctx context.Context, username string, at time.Time) (PurgeResult, error)
* PurgeAccount, kullanıcı ADINI ve diğer tanımlayıcıları serbest * bırakır — SATIRI SİLMEDEN. * * ⚠️ SATIR NEDEN KALIYOR: denetim kaydı ve oturum kayıtları kullanıcı * adını METİN olarak saklıyor. Satır yok olursa geçmişteki * "ayse.yilmaz" satırlarının kime ait olduğu cevapsız kalır — ve aynı * adı alan yeni kişiyle karışır. Kalan satır, "o ad şu tarihte * boşaltıldı" sorusunun cevabı. * * ⚠️ YALNIZCA 'deleted' HESAPLAR. Purge yaşam döngüsünün son adımı, bir * kısayol değil: aktif bir hesabın adını serbest bırakmak, o kişi hâlâ * kullanıyorken kimliğini elinden almak olurdu. * * Serbest bırakılanlar: kullanıcı adı, e-posta, iki kimlik bağı, * anahtarlar ve roller. Hepsi benzersizlik taşıyor ya da erişim * veriyor; biri kalırsa geri dönen kişi kendi hesabını açamaz.
func (*Store) PurgedAccounts ¶
func (s *Store) PurgedAccounts(ctx context.Context) ([]PurgedAccount, error)
* PurgedAccounts, purge edilmiş kayıtları döner. * * ⚠️ Bu liste denetimin bir parçası: geçmişteki bir kullanıcı adının * kime ait olduğu sorusu ancak "o ad şu tarihte boşaltıldı" bilgisiyle * cevaplanabiliyor. Satırların silinmemesinin sebebi de bu.
func (*Store) QueueArchive ¶
* QueueArchive, oturum için bekleyen bir arşiv satırı açar. * * Oturum kapanışında çağrılıyor. İkinci çağrı zararsız: satır zaten * varsa dokunulmuyor — özellikle archived_at'e, çünkü onu silmek * yüklenmiş bir kaydı yeniden bekleyene çevirirdi.
func (*Store) RecordPending ¶
* RecordPending, bir başvuruyu kaydeder ve GÜNCEL durumu döner. * * ⚠️ RED YAPIŞKAN. Reddedilmiş bir kimlik yeniden giriş denediğinde * satır 'waiting'e DÖNMÜYOR; yalnızca last_seen ilerliyor. Dönseydi, * reddedilen kişi tekrar tekrar deneyerek kuyruğu doldurur ve * yöneticiyi aynı kararı vermeye zorlardı. * * ⚠️ Ad DEĞİŞSE de aynı satır: anahtar kimlik. Adla anahtarlanan bir * kuyrukta reddedilen kişi dizinde adını değiştirip yeniden * başvurabilirdi.
func (*Store) RecordTargetError ¶
RecordTargetError, başarısız bir bağlantı denemesini işaretler.
func (*Store) RecordTargetProbe ¶
func (s *Store) RecordTargetProbe(ctx context.Context, targetName string, p model.TargetProbe) error
* RecordTargetProbe, hedefte KOMUT ÇALIŞTIRILARAK öğrenilenleri yazar. * * ⚠️ Yalnızca target_probe.enabled ile çağrılır. probed_at ayrı bir * damga: last_seen_at "bağlandık" demek, probed_at "makineye dokunduk" * demek ve ikisi aynı şey değil.
func (*Store) RecordTargetProbeAttempt ¶
func (s *Store) RecordTargetProbeAttempt(ctx context.Context, targetName string, at time.Time) error
* RecordTargetProbeAttempt, hedefe DOKUNULDUĞUNU kaydeder — ne * öğrenildiğini değil. * * ⚠️ NEDEN VAR: probed_at yalnızca BAŞARILI yoklamada yazılıyordu, oysa * target_probe.refresh kapısı ona bakıyor. Yani cevap üretmeyen bir * yoklama kapıyı hiç kapatmıyor ve HER KANALDA yeniden koşuyordu: * ölçüldü, tek bağlantıda beş kanal = beş yoklama ve (denetim satırı * denemeye taşındıktan sonra) beş defter satırı, oysa başarılı yoklamada * beş kanal = bir satır. * * Bedeli üç yerde: hedefin günlüğüne kullanıcının adına tekrar tekrar * komut düşüyor, denetim defteri aynı cümleyle şişiyor, ve refresh * ayarı söylediği şeyi yapmıyor. * * ⚠️ SEMANTİK DOĞRU: "ProbedAt sıfırsa hedefe hiç dokunulmadı" diyor * (model.TargetFacts) — cevapsız kalan bir yoklama da DOKUNUYOR: exec * kanalı açılıyor ve komutlar çalışıyor. Zaten denetlenmesinin sebebi * bu. Facts'e dokunulmuyor: öğrenilmemiş bir şey yazılmış gibi * görünmesin.
func (*Store) RecordTargetSeen ¶
RecordTargetSeen, başarılı bir bağlantıdan sonra öğrenilenleri yazar.
⚠️ ÇAĞIRAN BU HATAYI OTURUMA YANSITMAMALI. Burası bir gözlem kaydı; yazılamaması can sıkıcıdır ama kullanıcının oturumunu düşürmek için sebep değil. Denetim kaydı (sessions, admin_log) başka bir şey ve onun yazılamaması oturumu düşürür — ayrım kasıtlı.
func (*Store) RecordUnmappedGroups ¶
RecordUnmappedGroups, eşlenmemiş grupları teşhis tablosuna işler.
Hata döndürmez: bu bir teşhis kaydı, girişi düşürmesi için sebep yok. Sorun çıkarsa çağıran loglar.
func (*Store) RefuseIfDeleted ¶
* RefuseIfDeleted, silinmiş bir hesabın giriş yapmasını engeller. * * ⚠️ 'inactive' BURADA REDDEDİLMİYOR ve bu tasarımın kendisi: * pasifleşme "kaynak bir süredir doğrulamadı" demek ve BAŞARILI GİRİŞİN * kendisi o doğrulama. Reddetseydik, geri dönüş yolu bir yöneticiden * geçerdi ve tatilden dönen herkes kuyruğa girerdi. * * 'deleted' farklı: orada uzun bir sessizlik ya da bir insan kararı var * ve onu bir girişin sessizce bozması, "silindi" demenin anlamını yok * ederdi.
func (*Store) RefuseIfDeletedByID ¶
* RefuseIfDeletedByID, RefuseIfDeleted'in KİMLİK ile çalışan hâli. * * ⚠️ NEDEN AD DEĞİL KİMLİK: purge, adı serbest bırakıp satırı * 'purged:<id>' + deleted yapıyor. Ada bakan bir kontrol, ad yeniden * yaratıldığında YENİ satıra çözülüp nil döner — ölçülen sızıntı buydu * (CLI purge ayrı süreç, bellekteki oturumu düşüremiyor). Kimliğe bakan * kontrol, oturumun bağlı olduğu satırı görüyor: purge sonrası o satır * deleted, yani ret KALICI. * * Kimlik hiç yoksa (satır gerçekten silinmiş) ErrNotFound.
func (*Store) RejectPending ¶
* RejectPending, başvuruyu reddeder ve SATIRI BIRAKIR. * * ⚠️ Silinmiyor: silinseydi aynı kişi bir sonraki girişinde yeniden * 'waiting' olarak belirir ve red hiçbir şey ifade etmezdi. Sebep de * saklanıyor — aynı kararı ikinci kez veren yönetici, ilkinin niye * verildiğini görmeli.
func (*Store) RemoveGroupMapping ¶
RemoveGroupMapping, eşlemeyi kaldırır. Yoksa ErrNotFound.
⚠️ Bu, kullanıcıların rollerini ANINDA değiştirmez: mevcut SSO atamaları bir sonraki girişte yenilenir. Yetkiyi hemen kesmek gerekiyorsa rolü ya da kullanıcının erişimini ayrıca ele almak gerekir.
func (*Store) RemoveLocalCredential ¶
RemoveLocalCredential, kimlik bilgisini siler. Hesap kalır.
func (*Store) RemovePublicKey ¶
RemovePublicKey, anahtarı kullanıcıdan kaldırır. Kullanıcı yoksa ya da anahtar BU kullanıcıya ait değilse ErrNotFound — başka birinin anahtarını "benimkiymiş gibi" silmek sessizce başarılı OLMAMALI. keyBlob ham bayt; base64 çevrimi içeride, AddPublicKey ile simetrik.
func (*Store) ReplaceLocalCredential ¶
func (s *Store) ReplaceLocalCredential(ctx context.Context, username, verifier, by string) (replaced bool, err error)
* ReplaceLocalCredential, panelden verilen kimlik bilgisi. Var olanın * ÜSTÜNE YAZAR ve yalnızca YÖNETİCİ OLMAYAN hesaplar için çalışır. * * ⚠️ AddLocalCredential'IN ÜSTÜNE YAZMAMA KURALI KALDIRILMADI, YALNIZCA * BURADA GEÇERLİ DEĞİL — ve iki fonksiyonun ayrı durmasının sebebi tam * olarak bu. Oradaki kural şunu koruyordu: yazma yetkisi olan biri, * kurulumun tek yöneticisinin kimlik bilgisini sessizce döndüremesin. * Aşağıdaki `is_admin = FALSE` koşulu o korumayı aynen sürdürüyor — * yöneticiye bu yoldan dokunulamıyor, hiç. * * Üstüne yazmak burada ise ZORUNLU: "kullanıcı parolasını unuttu" * panelden çözülemezse, panelden sır verme özelliğinin var olma sebebi * — yöneticiyi host kabuğuna göndermemek — ilk gerçek olayda çöker. * * ⚠️ KOŞUL SQL'İN İÇİNDE, ÇAĞIRANDA DEĞİL. Çağıranın `if u.Admin` * yazması unutulabilir; buradaki WHERE unutulamaz. Üstüne bir de göç * 026'nın bileşik yabancı anahtarı var: holder_is_admin uydurulamıyor. * * Dönen değer: var olan bir kimlik bilgisinin üstüne mi yazıldı. * Denetim kaydı için — "verildi" ile "değiştirildi" farklı olaylar.
func (*Store) RevokeRole ¶
RevokeRole, kullanıcıdan rolü geri alır. Kullanıcı ya da rol yoksa ErrNotFound; bağ zaten yoksa SESSİZ no-op (AssignRole'un aynası).
func (*Store) RevokeTarget ¶
RevokeTarget, rolden hedef erişimini geri alır. GrantTarget'ın aynası.
func (*Store) RoleGrantSource ¶
func (s *Store) RoleGrantSource(ctx context.Context, username, roleName string) (source string, found bool, err error)
* RoleGrantSource, bir atamanın NEREDEN geldiğini söyler: "manual" ya * da "sso". found=false, böyle bir atama yok demek. * * ⚠️ NEDEN GEREKLİ: AssignRole'un ON CONFLICT dalı source'u koşulsuz * 'manual' yapıyor, SyncRoles ise yalnızca source='sso' satırlarını * siliyor. Yani dizinden gelen bir rolü elle "yeniden vermek", o rolü * senkronizasyonun erişemeyeceği bir yere taşıyor: kişi gruptan * çıkarıldığında rol ÜZERİNDE KALIYOR ve hiçbir otomatik yol onu geri * alamıyor. Bu okuma olmadan çağıran, sessizce kalıcı yetki üretiyor. * * Kimseyi engellemek için değil, SÖYLEYEBİLMEK için var.
func (*Store) Roles ¶
Roles, tüm rolleri hedefleriyle, ada göre sıralı döner; hedefsiz rol boş Targets ile gelir.
func (*Store) RolesForGroups ¶
func (s *Store) RolesForGroups(ctx context.Context, groups []string) (roles, unmapped []string, err error)
RolesForGroups, verilen dış grup adlarının karşılığı rolleri ve eşleşmeyen grupları döner.
Eşleşmeyenler çağırana veriliyor ki kaydedebilsin (RecordUnmappedGroups) ve yönetici neyi eşlemediğini görebilsin.
func (*Store) SeenGroupNames ¶
* SeenGroupNames, postern'in BUGÜNE KADAR gördüğü grup adları. * * İki kaynaktan: kullanıcılara gerçekten atanmış SSO rollerinin * eşlemeleri, ve eşlenmemiş grup teşhis tablosu. İkisi birlikte, * "bu ad hiç geldi mi" sorusunun elimizdeki en iyi cevabı. * * ⚠️ Kesin bir liste DEĞİL ve öyle sunulmamalı: bir kaynağa "hangi * gruplar var" diye genel olarak sorulamıyor (OIDC claim'i * listelenemez). Bu yüzden çağıran bunu bir teşhis olarak kullanıyor, * bir iddia olarak değil.
func (*Store) Session ¶
Session, tek bir oturumu kimlik ADLARIYLA döner. Yoksa ErrNotFound.
Sessions'ın sorgusunun WHERE s.id = $1 hâli; NULL/zaman çevrimleri de birebir aynı desen.
func (*Store) SessionFiles ¶
SessionFiles, bir oturumun dosya olaylarını zaman sırasıyla döner.
func (*Store) SetAccountState ¶
* SetAccountState, durumu elle değiştirir (panel/CLI). * * ⚠️ 'deleted'ten 'active'e dönüş SERBEST: yanlışlıkla silinmiş bir * hesabın geri gelememesi, tek tıkla kalıcı bir kayıp demekti. Fiziki * silme zaten yok.
func (*Store) SetChosenPassword ¶
func (s *Store) SetChosenPassword(ctx context.Context, username, verifier string, at time.Time) error
* SetChosenPassword, kullanıcının SEÇTİĞİ parolayı yazar. * * ⚠️ AddLocalCredential'DAN AYRI. O, üstüne yazmayı REDDEDİYOR ve bu * kasıtlı (bkz. oradaki not): var olan bir sırrı sessizce döndürmek, * elindeki değerle çalışan operatörü dışarıda bırakırdı. Burada tam * tersi isteniyor — amaç zaten üstüne yazmak. İki niyeti tek fonksiyona * bayrakla toplamak, o korumayı bir gün yanlışlıkla açık bırakırdı. * * ⚠️ YÖNETİCİ KONTROLÜ BURADA YOK. Kasıtlı: kuralı veritabanı tutuyor * (göç 026'daki CHECK). Buraya bir `if` yazmak, kuralın ikinci bir * kopyası olurdu ve iki kopyadan biri er ya da geç geride kalır. * Yönetici hesabında bu çağrı 23514 ile düşüyor ve çağıran onu * ErrAdminPasswordRefused olarak görüyor.
func (*Store) SetGroupAdmin ¶
* SetGroupAdmin, dizin GRUBUNDAN gelen yönetici yetkisini uygular. * * ⚠️ CLI'IN VERDİĞİNE DOKUNMAZ. WHERE koşulundaki * `admin_via IS DISTINCT FROM 'cli'` bunun için: acil durum diye elle * açılmış bir yöneticinin, dizinde o grubu görülmediği için sessizce * yetkisini kaybetmesi, tam olarak kaçınılması gereken şey — ve * kaybettiği an, onu geri verecek kişinin de kapısı kapanmış olurdu. * * Rol modelindeki source='sso' / 'manual' ayrımının aynısı: her * mekanizma yalnızca KENDİ verdiğini geri alabiliyor.
func (*Store) SetRecordingPathForTest ¶
* SetRecordingPathForTest, kayıt yolunu doğrudan değiştirir. * * ⚠️ YALNIZCA TESTLER İÇİN. Üretimde bu sütunu yazan tek yer * StartSession; keyfi bir yol yazabilen bir API, veritabanına * ulaşan birine dosya okuma/yükleme yetkisi vermek olurdu. Test, * arşivleyicinin tam da o saldırıyı reddettiğini ölçüyor.
func (*Store) SetSearchTimeoutForTest ¶
* SetSearchTimeoutForTest, sunucu tarafı sınırı kısaltır. * * ⚠️ YALNIZCA TESTLER İÇİN. Sınırın gerçekten UYGULANDIĞINI ölçmenin * tek yolu onu aşan bir sorgu çalıştırmak; 5 saniyelik varsayılanla o * test her CI koşusuna beş saniye eklerdi ve büyük ihtimalle hiç * yazılmazdı. Ölçülmeyen bir koruma, olmayan bir korumadır.
func (*Store) SetSetting ¶
func (s *Store) SetSetting(ctx context.Context, key, value string, encrypt bool, actor string) error
SetSetting, ayarı yazar. encrypt=true ise değer mühürlenerek saklanır.
encrypt=true iken anahtar yoksa REDDEDİLİR — düz metin yazıp "şifreledim" sanmak bu paketin bütün amacını sessizce boşa çıkarır.
func (*Store) SetTargetLabel ¶
func (s *Store) SetTargetLabel(ctx context.Context, targetName, key, value, actor, via string) error
SetTargetLabel, etiketi ekler ya da değerini değiştirir.
Denetim satırı BURADA yazılıyor, çağıranda değil: etiket hedefin nasıl bulunacağını belirliyor ve "prod" etiketini bir makineden alıp başkasına takan kişinin izi kalmalı.
func (*Store) SetUserAdmin ¶
SetUserAdmin, uygulama yönetim yetkisini verir ya da alır. Kullanıcı yoksa ErrNotFound.
func (*Store) SetUserEmail ¶
SetUserEmail, kullanıcının e-postasını değiştirir; boş string adresi SİLER (NULL). Kullanıcı yoksa ErrNotFound; adres başka bir kullanıcıda kayıtlıysa ErrConflict (users.email UNIQUE — OIDC eşleşmesi tekil kalmalı).
"user add"in reddettiği örtük değişikliğin AÇIK hâli: yönetici ne yaptığını komutun adıyla söylüyor.
func (*Store) SetUserOSUser ¶
SetUserOSUser, kullanıcının hedeflerdeki hesabını değiştirir. Boş değer şemadaki CHECK'e takılır; kullanıcı yoksa ErrNotFound.
⚠️ Bu, bir sonraki oturumdan itibaren kesilecek SERTİFİKALARIN principal'ını değiştirir — geçmiş denetim kayıtlarına dokunmaz (sessions.os_user o günkü kararı saklar; sebebi şemada yazıyor).
func (*Store) SetUserSSOOnly ¶
SetUserSSOOnly, kullanıcının yalnızca kimlik sağlayıcı üzerinden girebilmesini açar/kapatır. Kullanıcı yoksa ErrNotFound.
func (*Store) Settings ¶
func (s *Store) Settings(ctx context.Context) ([]SettingView, error)
Settings, ada göre sıralı ayar listesi döner — ŞİFRELİ DEĞERLER MASKELENMİŞ olarak.
⚠️ Bu fonksiyonun çıktısı admin API'sine gidiyor: şifreli bir ayarın değeri ASLA dönmez, maskelenir. Sır yazılır ama okunmaz.
func (*Store) SourceAccountCount ¶
SourceAccountCount, kaynaktan gelen toplam hesap sayısı — patlama yarıçapı oranının paydası.
func (*Store) StaleAccounts ¶
func (s *Store) StaleAccounts(ctx context.Context, olderThan time.Time, state string) ([]StaleAccount, error)
* StaleAccounts, kaynağın BELİRLİ BİR SÜREDİR doğrulamadığı hesapları * döner. * * ⚠️ KAPSAM: yalnızca kaynaktan gelen hesaplar (sso_only ya da dizine * bağlı). Yerel hesaplar DIŞARIDA ve bu kapsam daraltması özelliğin * otomasyon için güvenli olmasının tek sebebi: CI ve servis hesapları * yerel açılıyor, hiçbir kaynağa sorulamıyor ve "doğrulanmamış olmaları" * normal. Onları da kapsayan bir sayaç, her otomasyonu süre dolunca * keserdi.
func (*Store) StartSession ¶
func (s *Store) StartSession(ctx context.Context, rec SessionStart) error
func (*Store) StartSyncRun ¶
func (s *Store) StartSyncRun(ctx context.Context, source, trigger string, dryRun bool) (int64, error)
StartSyncRun, koşuyu açar ve id'sini döner.
func (*Store) SyncCandidates ¶
func (s *Store) SyncCandidates(ctx context.Context) ([]SyncCandidate, error)
SyncCandidates, senkronizasyona TABİ kullanıcıları döner.
- ⚠️ KAPSAM: sso_only OLANLAR ARTI DİZİNE BAĞLI OLANLAR. *
- Eskiden yalnızca sso_only = TRUE idi ve bu, freshen'da düzeltilen
- hatanın buradaki eşiydi: yetkisi dizinden gelen bir kullanıcı
- (dir_subject dolu, sso_only false) HİÇ senkronize edilmiyordu. Yani
- dizinden silinen kişi, bir daha hiç giriş yapmadığı sürece rollerini
- süresiz koruyordu — ve döngünün var olma sebebi tam olarak o kişiydi. *
- ⚠️ Servis hesapları (otomasyon, CI) HÂLÂ DIŞARIDA ve genişletme bunu
- bozmuyor: onların ne sso_only'si var ne dizin kimliği. Dizinde
- "bulunamamaları" normal ve döngünün onlara dokunmaması şart (göç 008
- tam olarak bu ayrım için).
func (*Store) SyncRoles ¶
SyncRoles, kullanıcının SSO kaynaklı rollerini IdP'nin söylediğiyle DEĞİŞTİRİR. Elle atanmış roller (source='manual') etkilenmez.
Her SSO girişinde çağrılır: gruptan çıkarılan kullanıcı yetkisini o an kaybeder, yeni gruba eklenen o an kazanır.
func (*Store) TargetFacts ¶
TargetFacts, tek bir hedefin gözlemleri. Hiç bağlanılmamışsa sıfır değer döner — ErrNotFound DEĞİL: "henüz bağlanılmadı" bir hata değil, hedefin geçerli bir hâli.
func (*Store) TargetLabels ¶
TargetLabels, tek bir hedefin etiketleri.
func (*Store) TouchLocalCredential ¶
TouchLocalCredential, son kullanım anını damgalar.
Hatası girişi DÜŞÜRMEZ: çağıran loglar. Kullanım damgası bir teşhis bilgisi ve onun yazılamaması, kimliği doğrulanmış bir kullanıcıyı dışarıda bırakmak için sebep değil.
func (*Store) TryLockSync ¶
TryLockSync, senkronizasyon kilidini DENEYEREK alır.
İki postern süreci aynı veritabanına bakıyorsa ikisi de senkronize eder ve patlama yarıçapı sayaçlarını BAĞIMSIZ hesaplar — yani tavanlar ikiye bölünmüş olur ve ikisi birden geçebilir.
pg_try_advisory_lock BEKLEMEZ: alamadıysa bu koşu atlanır. Beklemek, zamanlayıcı tikleri kuyruğa dizmek demek olurdu.
⚠️ Kilit SABİTLENMİŞ bir bağlantıda tutuluyor: havuzdan alınan bir bağlantı koşunun ortasında geri verilebilir ve kilit sessizce düşerdi.
func (*Store) UnbindDirIdentity ¶
UnbindDirIdentity, bağı koparır.
⚠️ Kurtarma yolu ve var olması ŞART: dizinde silinip yeniden açılan bir kişi YENİ bir kimlik alır (ölçüldü) ve eski bağ onu kendi hesabından kilitler. Bunu çözecek bir komut olmazsa tek çıkış veritabanına elle girmek olurdu.
func (*Store) UnmappedGroups ¶
func (s *Store) UnmappedGroups(ctx context.Context) ([]UnmappedGroup, error)
UnmappedGroups, eşlenmemiş grupları en çok görülenden aza doğru döner.
func (*Store) UseSecretBox ¶
UseSecretBox, şifreli ayarları açıp mühürleyecek anahtarı bağlar.
Store bunsuz da çalışır: şifresiz ayarlar okunur/yazılır, şifreli olana dokunulduğunda hata verilir. CLI'ın çoğu komutu sır gerektirmiyor ve anahtar dosyası olmadan da çalışabilmeli.
func (*Store) UseTOTPStep ¶
* UseTOTPStep, bir adımı TÜKETİR ve daha önce kullanılmışsa reddeder. * * ⚠️ TEK BİR İFADEDE KARŞILAŞTIR-VE-YAZ. Önce okuyup sonra yazan bir * uygulama, aynı kodla gönderilen İKİ eşzamanlı isteğin ikisini de * geçirirdi: her ikisi de eski değeri okur, her ikisi de kabul eder. * Tekrar korumasının bütün anlamı tam olarak o yarışı kapatmak. * * `last_step < $2` aynı zamanda pencere içindeki DAHA ESKİ adımları da * kapatıyor: adım N kullanıldıysa, hâlâ geçerli olan N-1 kodu da ölür.
func (*Store) UserByDirSubject ¶
UserByDirSubject, dizin kimliğine bağlı kullanıcıyı döner. Bağlı hesap yoksa ErrNotFound.
func (*Store) UserByEmail ¶
func (*Store) UserByIdPSubject ¶
UserByIdPSubject, (issuer, subject) çiftine bağlı kullanıcıyı döner.
func (*Store) UserByNameFold ¶
* UserByNameFold, adı HARF DUYARSIZ arar ve bulunan gerçek adı döner. * * ⚠️ KULLANICI ADLARI 019'DAN BERİ HARF DUYARSIZ BENZERSİZ. Eski yorum * bunun tersini söylüyordu ("Ops ile ops iki ayrı hesap olabilir") ve * o artık yanlış: göç 019 lower(username) üzerinde tekil bir indeks * kurdu, tam da bir harf farkıyla ikinci bir yönetici ve ikinci bir * canlı sır yaratılmasını önlemek için. * * Bu fonksiyon o tekilliğin okuma tarafı: bootstrap, adı ne yazımla * yazılmış olursa olsun tek hesabı bulmalı. * * lower() indeksi VAR (019) ve users.username ciColumns'ta — sorgu bir * tablo taraması yapmıyor. Eski yorum "indeks yok" diyordu; o da yanlış.
func (*Store) UserByPublicKey ¶
func (*Store) UserProfile ¶
UserProfile, detay alanlarını TEK sorguda döner.
func (*Store) Users ¶
Users, tüm kullanıcıları rolleriyle birlikte, ada göre sıralı döner.
User'ın sorgusunun WHERE'siz hâli; gruplama iki seviyeli — önce kullanıcıya, sonra role. Desen User'dakiyle aynı, yalnızca indeks map'leri kullanıcı boyutu kazanıyor.
Hiç kullanıcı yoksa boş dilim, hata değil.
type SyncCandidate ¶
type SyncCandidate struct {
Username string
Email string
// MissingSince sıfırsa kullanıcı en son bakıldığında dizinde vardı.
MissingSince time.Time
SSORoles int
ManualRoles int
/*
* DirSubject, hesabın bağlı olduğu KARARLI dizin kimliği; bağlı
* değilse boş.
*
* ⚠️ Döngü, varsa BUNUNLA aramalı. Adla arama, dizinde yeniden
* adlandırılan kişiyi SİLİNMİŞ kişiden ayırt edemiyor — ikisi de
* PresenceAbsent döner ve döngü ikincisini rol iptaline çevirir.
* Yani İK'nın bir soyadı güncellemesi, kimsenin fark etmediği bir
* yerde erişim kaybına dönüşüyordu.
*/
DirSubject string
}
SyncCandidate, senkronizasyonun bakacağı bir kullanıcı.
type SyncRun ¶
type SyncRun struct {
ID int64
StartedAt time.Time
FinishedAt time.Time
Source string
Trigger string
Outcome string
Reason string
Considered int
Present int
Absent int
Unknown int
Revoked int
RolesChanged int
DryRun bool
}
SyncRun, bir senkronizasyon koşusunun kaydı.
type TOTPCredential ¶
type TOTPCredential struct {
// ⚠️ Secret JSON'a ÇIKMIYOR. Bu değer kod üretmeye yeter; bir
// listeleme ucundan sızması, ikinci faktörü ikinci faktör olmaktan
// çıkarır. Yalnızca kayıt akışında, bir kez gösteriliyor.
Secret string `json:"-"`
Confirmed bool `json:"confirmed"`
ConfirmedAt time.Time `json:"confirmed_at,omitzero"`
CreatedAt time.Time `json:"created_at"`
LastUsedAt time.Time `json:"last_used_at,omitzero"`
}
TOTPCredential, bir hesabın ikinci faktörü.
type UnmappedGroup ¶
UnmappedGroup, teşhis listesindeki bir kayıt.
type UserProfile ¶
type UserProfile struct {
Email string
// AdminVia: "cli", "group" ya da boş. Yöneticiliğin KAYNAĞI, çünkü
// panelin kaldırabildiği ile kaldıramadığı ayrı şeyler.
AdminVia string
State string
Confirmed time.Time
// Purged: adı serbest bırakılmış. Satır yalnızca denetim kaydının
// okunabilir kalması için duruyor.
Purged bool
// HasCredential false ise aşağıdaki alanlar anlamsız: hesabın
// postern'de doğrulanabilir bir değeri yok, kimliği başka yerden
// geliyor.
HasCredential bool
CredChosen bool
CredMustChange bool
CredCreatedAt time.Time
CredCreatedBy string
CredLastUsed time.Time
}
* UserProfile, kullanıcı DETAY ekranının ihtiyacı. * * ⚠️ NEDEN AYRI BİR SORGU: model.User bilerek dar tutuldu — yetki * kararlarının ihtiyacı olan alanları taşıyor ve SSH kapısında her * oturumda okunuyor. E-posta, hesap durumu ve kimlik bilgisi meta * verisi orada hiçbir kararı etkilemiyor; oraya eklemek, hiç * kullanılmayan alanları en sıcak yoldan geçirmek olurdu. * * Buradaki alanların ortak yanı hepsinin bir TEŞHİS sorusuna cevap * vermesi: "neden giremiyor", "yöneticiliği nereden geliyor", "bu * hesabın nasıl bir giriş bilgisi var".