Add users and network settings tabs with admin protections.
List and delete accounts with last-admin and Administrators-group guards, and expose editable network settings via the configuration UI.
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
package settings
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
type encryptedBlob struct {
|
||||
Nonce string `json:"nonce"`
|
||||
Ciphertext string `json:"ciphertext"`
|
||||
}
|
||||
|
||||
func loadEncryptedJSON(dir string, fileName string, key []byte, destination any) error {
|
||||
path := filepath.Join(dir, fileName)
|
||||
payload, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("read %s: %w", fileName, err)
|
||||
}
|
||||
|
||||
var blob encryptedBlob
|
||||
if err := json.Unmarshal(payload, &blob); err != nil {
|
||||
return fmt.Errorf("parse %s envelope: %w", fileName, err)
|
||||
}
|
||||
|
||||
nonce, err := base64.StdEncoding.DecodeString(blob.Nonce)
|
||||
if err != nil {
|
||||
return fmt.Errorf("decode nonce: %w", err)
|
||||
}
|
||||
ciphertext, err := base64.StdEncoding.DecodeString(blob.Ciphertext)
|
||||
if err != nil {
|
||||
return fmt.Errorf("decode ciphertext: %w", err)
|
||||
}
|
||||
|
||||
plaintext, err := open(nonce, ciphertext, key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(plaintext, destination); err != nil {
|
||||
return fmt.Errorf("parse %s: %w", fileName, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func saveEncryptedJSON(dir string, fileName string, key []byte, value any) error {
|
||||
if err := ensureConfigDir(dir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
plaintext, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("encode %s: %w", fileName, err)
|
||||
}
|
||||
|
||||
nonce, ciphertext, err := seal(plaintext, key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
blob := encryptedBlob{
|
||||
Nonce: base64.StdEncoding.EncodeToString(nonce),
|
||||
Ciphertext: base64.StdEncoding.EncodeToString(ciphertext),
|
||||
}
|
||||
payload, err := json.MarshalIndent(blob, "", " ")
|
||||
if err != nil {
|
||||
return fmt.Errorf("encode %s envelope: %w", fileName, err)
|
||||
}
|
||||
payload = append(payload, '\n')
|
||||
|
||||
path := filepath.Join(dir, fileName)
|
||||
if err := os.WriteFile(path, payload, 0o600); err != nil {
|
||||
return fmt.Errorf("write %s: %w", fileName, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user