summaryrefslogtreecommitdiff
path: root/files.go
diff options
context:
space:
mode:
authortjp <tjp@ctrl-c.club>2024-01-08 11:10:24 -0700
committertjp <tjp@ctrl-c.club>2024-01-08 11:10:24 -0700
commita90327bcc0f46171e30a4a549fb5b44f8e91e303 (patch)
tree8595b256c8e9fa2232525199c51021e0efbebac4 /files.go
parent230933ee0e4bce6ddf25e0816fff0bd30e3c8864 (diff)
identity management and use
Diffstat (limited to 'files.go')
-rw-r--r--files.go141
1 files changed, 141 insertions, 0 deletions
diff --git a/files.go b/files.go
index e602fca..f9be89a 100644
--- a/files.go
+++ b/files.go
@@ -2,6 +2,8 @@ package main
import (
"bufio"
+ "crypto/tls"
+ "encoding/pem"
"errors"
"fmt"
"net/url"
@@ -264,3 +266,142 @@ func ensurePath(fpath string) error {
}
return nil
}
+
+func getIdentities() (Identities, error) {
+ idents := Identities{
+ ByName: map[string]*tls.Config{},
+ ByDomain: map[string]*tls.Config{},
+ ByFolder: map[string]*tls.Config{},
+ ByPage: map[string]*tls.Config{},
+ }
+
+ manifest, err := dataFilePath("identities")
+ if err != nil {
+ return idents, err
+ }
+
+ f, err := os.Open(manifest)
+ if err != nil {
+ return idents, err
+ }
+ defer func() { _ = f.Close() }()
+
+ var curident *tls.Config
+ rdr := bufio.NewScanner(f)
+ for rdr.Scan() {
+ line := rdr.Text()
+ if strings.HasPrefix(line, ":") {
+ kind, location, _ := strings.Cut(line[1:], " ")
+ switch kind {
+ case "domain":
+ idents.ByDomain[location] = curident
+ case "folder":
+ idents.ByFolder[location] = curident
+ case "page":
+ idents.ByPage[location] = curident
+ }
+ } else {
+ name := strings.TrimSuffix(line, ":")
+ curident, err = getIdentity(name)
+ if err != nil {
+ return idents, err
+ }
+ idents.ByName[name] = curident
+ }
+ }
+ if err := rdr.Err(); err != nil {
+ return idents, err
+ }
+
+ return idents, nil
+}
+
+func saveIdentities(idents Identities) error {
+ manifest, err := dataFilePath("identities")
+ if err != nil {
+ return err
+ }
+
+ f, err := os.OpenFile(manifest, os.O_WRONLY|os.O_TRUNC, 0o600)
+ if err != nil {
+ return err
+ }
+ defer func() { _ = f.Close() }()
+
+ for name, ident := range idents.ByName {
+ if _, err := fmt.Fprintf(f, "%s:\n", name); err != nil {
+ return err
+ }
+
+ for domain, id := range idents.ByDomain {
+ if id != ident {
+ continue
+ }
+ if _, err := fmt.Fprintf(f, ":domain %s\n", domain); err != nil {
+ return err
+ }
+ }
+ for folder, id := range idents.ByFolder {
+ if id != ident {
+ continue
+ }
+ if _, err := fmt.Fprintf(f, ":folder %s\n", folder); err != nil {
+ return err
+ }
+ }
+ for page, id := range idents.ByPage {
+ if id != ident {
+ continue
+ }
+ if _, err := fmt.Fprintf(f, ":page %s\n", page); err != nil {
+ return err
+ }
+ }
+ }
+
+ return nil
+}
+
+func getIdentity(name string) (*tls.Config, error) {
+ fpath, err := dataFilePath("ident/" + name)
+ if err != nil {
+ return nil, err
+ }
+
+ cert, err := tls.LoadX509KeyPair(fpath, fpath)
+ if err != nil {
+ return nil, err
+ }
+
+ return identityForCert(cert), nil
+}
+
+func saveIdentity(name string, privkeyDER, certDER []byte) (string, error) {
+ fpath, err := dataFilePath("ident/" + name)
+ if err != nil {
+ return "", err
+ }
+
+ f, err := os.OpenFile(fpath, os.O_WRONLY|os.O_TRUNC, 0o600)
+ if err != nil {
+ return "", err
+ }
+ defer func() { _ = f.Close() }()
+
+ if err := pem.Encode(f, &pem.Block{Type: "PRIVATE KEY", Bytes: privkeyDER}); err != nil {
+ return "", err
+ }
+ if err := pem.Encode(f, &pem.Block{Type: "CERTIFICATE", Bytes: certDER}); err != nil {
+ return "", err
+ }
+
+ return fpath, nil
+}
+
+func removeIdentity(name string) error {
+ fpath, err := dataFilePath("ident/" + name)
+ if err != nil {
+ return err
+ }
+ return os.Remove(fpath)
+}