// Copyright 2023 wanderer // SPDX-License-Identifier: AGPL-3.0-only package localbreach import ( "bytes" "context" "io" "os" "git.dotya.ml/mirre-mt/pcmt/ent" "git.dotya.ml/mirre-mt/pcmt/ent/schema" "git.dotya.ml/mirre-mt/pcmt/slogging" "golang.org/x/exp/slog" "gopkg.in/yaml.v3" ) type CtxKey struct{} // Load loads local breach data and returns a pointer to the slice of the // structs, of which each holds one YAML document on successful import, error // otherwise. func Load(path string) (*[]schema.ImportSchema, error) { b, err := os.ReadFile(path) if err != nil { return nil, err } lb, err := loadLocalBreach(b) if err != nil { return nil, err } return lb, nil } func loadLocalBreach(b []byte) (*[]schema.ImportSchema, error) { r := bytes.NewReader(b) decoder := yaml.NewDecoder(r) lb := make([]schema.ImportSchema, 0) var is schema.ImportSchema for { if err := decoder.Decode(&is); err != nil { if err != io.EOF { return nil, err } break // get out when there are no more documents to read. } lb = append(lb, is) } return &lb, nil } // ImportLocalBreach imports data that from YAML files into the database. The // data must adhere to the ImportSchema. func ImportLocalBreach(ctx context.Context, db *ent.Client, b *[]schema.ImportSchema) ([]*ent.LocalBreach, error) { slogger := ctx.Value(CtxKey{}).(*slogging.Slogger) log := *slogger log.Logger = log.With( slog.Group("pcmt extra", slog.String("module", "modules/localbreach")), ) var err error var lbs []*ent.LocalBreach // go through the documents, abort saving to DB on err of one. for _, breach := range *b { lb, err := db.LocalBreach. Create(). SetName(breach.Name). SetNillableDescription(&breach.Description). SetIsVerified(breach.IsVerified). SetContainsEmails(breach.ContainsEmails). SetContainsUsernames(breach.ContainsUsernames). SetContainsPasswords(breach.ContainsPasswords). SetContainsHashes(breach.ContainsHashes). SetNillableHashSalted(&breach.HashSalted). SetNillableHashPeppered(&breach.HashPeppered). SetNillableHashType(&breach.HashType). SetNillableDate(&breach.Date). SetData(&breach.Data). Save(ctx) if err != nil { break } lbs = append(lbs, lb) } switch { case lbs == nil && err != nil: return nil, err case ent.IsConstraintError(err): return nil, err case err == nil && lbs != nil: return lbs, nil } return nil, err }