summaryrefslogtreecommitdiff
path: root/identity.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 /identity.go
parent230933ee0e4bce6ddf25e0816fff0bd30e3c8864 (diff)
identity management and use
Diffstat (limited to 'identity.go')
-rw-r--r--identity.go205
1 files changed, 205 insertions, 0 deletions
diff --git a/identity.go b/identity.go
new file mode 100644
index 0000000..891c01b
--- /dev/null
+++ b/identity.go
@@ -0,0 +1,205 @@
+package main
+
+import (
+ "bytes"
+ "crypto/tls"
+ "errors"
+ "fmt"
+ "io"
+ "net/url"
+ "os"
+ "strings"
+)
+
+type Identities struct {
+ ByName map[string]*tls.Config
+ ByDomain map[string]*tls.Config
+ ByPage map[string]*tls.Config
+ ByFolder map[string]*tls.Config
+}
+
+func findIdentity(state *BrowserState, prefix string) (string, error) {
+ found := 0
+ value := ""
+ for name := range state.Identities.ByName {
+ if strings.HasPrefix(name, prefix) {
+ found += 1
+ value = name
+ }
+ }
+
+ switch found {
+ case 0:
+ return "", errors.New("no matching identity found")
+ case 1:
+ return value, nil
+ default:
+ return "", fmt.Errorf("too ambiguous - that name matched %d identities", found)
+ }
+}
+
+func (ids Identities) Get(u *url.URL) *tls.Config {
+ if conf, ok := ids.ByPage[u.String()]; ok {
+ return conf
+ }
+
+ pathsegments := strings.Split(strings.TrimLeft(u.Path, "/"), "/")
+ for len(pathsegments) > 0 {
+ pathsegments = pathsegments[0 : len(pathsegments)-1]
+ if conf, ok := ids.ByFolder[u.Hostname()+"/"+strings.Join(pathsegments, "/")]; ok {
+ return conf
+ }
+ }
+
+ if conf, ok := ids.ByDomain[u.Hostname()]; ok {
+ return conf
+ }
+
+ return nil
+}
+
+func IdentityCreate(state *BrowserState, name string) error {
+ ident, err := createIdentity(state, name)
+ if err != nil {
+ return err
+ }
+ state.Identities.ByName[name] = ident
+ return saveIdentities(state.Identities)
+}
+
+func IdentityList(state *BrowserState) error {
+ buf := &bytes.Buffer{}
+ for name, ident := range state.Identities.ByName {
+ if _, err := fmt.Fprintf(buf, "%s:\n", name); err != nil {
+ return err
+ }
+
+ for domain, id := range state.Identities.ByDomain {
+ if id == ident {
+ if _, err := fmt.Fprintf(buf, " domain %s\n", domain); err != nil {
+ return err
+ }
+ }
+ }
+ for folder, id := range state.Identities.ByFolder {
+ if id == ident {
+ if _, err := fmt.Fprintf(buf, " folder %s\n", folder); err != nil {
+ return err
+ }
+ }
+ }
+ for page, id := range state.Identities.ByPage {
+ if id == ident {
+ if _, err := fmt.Fprintf(buf, " page %s\n", page); err != nil {
+ return err
+ }
+ }
+ }
+ }
+
+ _, err := io.Copy(os.Stdout, buf)
+ return err
+}
+
+func IdentityDelete(state *BrowserState, name string) error {
+ name, err := findIdentity(state, name)
+ if err != nil {
+ return err
+ }
+
+ ident := state.Identities.ByName[name]
+ delete(state.Identities.ByName, name)
+
+ for domain, id := range state.Identities.ByDomain {
+ if id == ident {
+ delete(state.Identities.ByDomain, domain)
+ }
+ }
+ for folder, id := range state.Identities.ByFolder {
+ if id == ident {
+ delete(state.Identities.ByFolder, folder)
+ }
+ }
+ for page, id := range state.Identities.ByPage {
+ if id == ident {
+ delete(state.Identities.ByPage, page)
+ }
+ }
+
+ if err := removeIdentity(name); err != nil {
+ return err
+ }
+ return saveIdentities(state.Identities)
+}
+
+func IdentityUseDomain(state *BrowserState, name string, domain string) error {
+ name, err := findIdentity(state, name)
+ if err != nil {
+ return err
+ }
+ ident := state.Identities.ByName[name]
+
+ u, _, err := parseURL(domain, state, "gemini")
+ if errors.Is(err, ErrInvalidLink) {
+ u, err = url.Parse(domain)
+ if err != nil {
+ return ErrInvalidLink
+ }
+ if u.Hostname() == "" {
+ u.Host = domain
+ }
+ } else if err != nil {
+ return err
+ }
+
+ state.Identities.ByDomain[u.Hostname()] = ident
+ return saveIdentities(state.Identities)
+}
+
+func IdentityUseFolder(state *BrowserState, name string, domain string) error {
+ name, err := findIdentity(state, name)
+ if err != nil {
+ return err
+ }
+ ident := state.Identities.ByName[name]
+
+ u, _, err := parseURL(domain, state, "gemini")
+ if errors.Is(err, ErrInvalidLink) {
+ u, err = url.Parse(domain)
+ if err != nil {
+ return ErrInvalidLink
+ }
+ if u.Hostname() == "" {
+ u.Host = domain
+ }
+ } else if err != nil {
+ return err
+ }
+
+ state.Identities.ByFolder[fmt.Sprintf("%s/%s", u.Hostname(), u.Path)] = ident
+ return saveIdentities(state.Identities)
+}
+
+func IdentityUsePage(state *BrowserState, name string, domain string) error {
+ name, err := findIdentity(state, name)
+ if err != nil {
+ return err
+ }
+ ident := state.Identities.ByName[name]
+
+ u, _, err := parseURL(domain, state, "gemini")
+ if errors.Is(err, ErrInvalidLink) {
+ u, err = url.Parse(domain)
+ if err != nil {
+ return ErrInvalidLink
+ }
+ if u.Hostname() == "" {
+ u.Host = domain
+ }
+ } else if err != nil {
+ return err
+ }
+
+ state.Identities.ByPage[u.String()] = ident
+ return saveIdentities(state.Identities)
+}