- Add EnsureConsent(db, in, out) that returns (true, nil) immediately if verify.consent==granted, otherwise prompts once, reads a line, persists 'granted' on 'yes' (case-insensitive), 'declined' otherwise. - Declined is not sticky — next call re-prompts; only granted persists. - Prompt references legal implications and directs users to 'keyhunter legal'.
71 lines
2.3 KiB
Go
71 lines
2.3 KiB
Go
package verify
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"io"
|
|
"strings"
|
|
|
|
"github.com/salvacybersec/keyhunter/pkg/storage"
|
|
)
|
|
|
|
// ConsentSettingKey is the settings table key under which the user's
|
|
// verification consent decision is persisted.
|
|
const ConsentSettingKey = "verify.consent"
|
|
|
|
// Consent decision values stored under ConsentSettingKey.
|
|
const (
|
|
ConsentGranted = "granted"
|
|
ConsentDeclined = "declined"
|
|
)
|
|
|
|
// EnsureConsent checks whether the user has previously granted consent to run
|
|
// active key verification. If consent was previously granted it returns
|
|
// (true, nil) immediately without prompting. Otherwise it writes a warning
|
|
// and prompt to out, reads one line from in, and persists the decision via
|
|
// the settings table.
|
|
//
|
|
// Declined decisions are not sticky — a subsequent call will re-prompt. Only
|
|
// "granted" persists across runs.
|
|
func EnsureConsent(db *storage.DB, in io.Reader, out io.Writer) (bool, error) {
|
|
val, found, err := db.GetSetting(ConsentSettingKey)
|
|
if err != nil {
|
|
return false, fmt.Errorf("reading verify.consent: %w", err)
|
|
}
|
|
if found && val == ConsentGranted {
|
|
return true, nil
|
|
}
|
|
|
|
fmt.Fprintln(out, "⚠ Active Key Verification — Legal Notice")
|
|
fmt.Fprintln(out, "")
|
|
fmt.Fprintln(out, "Using --verify will send HTTP requests to third-party provider APIs")
|
|
fmt.Fprintln(out, "for every API key KeyHunter finds. You are responsible for the")
|
|
fmt.Fprintln(out, "legal implications of these requests in your jurisdiction")
|
|
fmt.Fprintln(out, "(CFAA, Computer Misuse Act, GDPR, provider ToS).")
|
|
fmt.Fprintln(out, "")
|
|
fmt.Fprintln(out, "Run `keyhunter legal` to read the full disclaimer.")
|
|
fmt.Fprintln(out, "")
|
|
fmt.Fprint(out, "Type 'yes' to proceed: ")
|
|
|
|
reader := bufio.NewReader(in)
|
|
line, err := reader.ReadString('\n')
|
|
if err != nil && err != io.EOF {
|
|
return false, fmt.Errorf("reading consent input: %w", err)
|
|
}
|
|
answer := strings.ToLower(strings.TrimSpace(line))
|
|
|
|
if answer == "yes" {
|
|
if err := db.SetSetting(ConsentSettingKey, ConsentGranted); err != nil {
|
|
return false, fmt.Errorf("persisting consent: %w", err)
|
|
}
|
|
fmt.Fprintln(out, "Consent recorded. Proceeding with verification.")
|
|
return true, nil
|
|
}
|
|
|
|
if err := db.SetSetting(ConsentSettingKey, ConsentDeclined); err != nil {
|
|
return false, fmt.Errorf("persisting declined consent: %w", err)
|
|
}
|
|
fmt.Fprintln(out, "Consent declined. Verification skipped.")
|
|
return false, nil
|
|
}
|