diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..b976e44
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,17 @@
+# EditorConfig is awesome: https://editorconfig.org
+
+# top-most EditorConfig file
+root = true
+
+# Unix-style newlines with a newline ending every file
+[*]
+end_of_line = lf
+indent_style = space
+indent_size = 2
+insert_final_newline = true
+
+[*.go]
+indent_style = tab
+
+[Makefile]
+indent_style = tab
diff --git a/auth/auth.go b/auth/auth.go
index bb7d881..d4206c4 100644
--- a/auth/auth.go
+++ b/auth/auth.go
@@ -5,16 +5,18 @@ import (
"errors"
"fmt"
"github.com/1f349/lavender/database"
+ "html/template"
"net/http"
)
type Factor byte
const (
- // FactorAuthorized defines the "authorized" state of a session
- FactorAuthorized Factor = iota
- FactorFirst
- FactorSecond
+ // FactorUnauthorized defines the "unauthorized" state of a session
+ FactorUnauthorized Factor = iota
+ FactorBasic
+ FactorExtended
+ FactorSudo
)
type Provider interface {
@@ -25,18 +27,20 @@ type Provider interface {
// Name defines a string value for the provider, useful for template switching
Name() string
- // RenderData stores values to send to the templating function
- RenderData(ctx context.Context, req *http.Request, user *database.User, data map[string]any) error
+ // RenderTemplate returns HTML to embed in the page template
+ RenderTemplate(ctx context.Context, req *http.Request, user *database.User) (template.HTML, error)
// AttemptLogin processes the login request
AttemptLogin(ctx context.Context, req *http.Request, user *database.User) error
}
var (
- // ErrRequiresSecondFactor notifies the ServeHTTP function to ask for another factor
- ErrRequiresSecondFactor = errors.New("requires second factor")
- // ErrRequiresPreviousFactor is a generic error for providers which require a previous factor
- ErrRequiresPreviousFactor = errors.New("requires previous factor")
+ // ErrRequiresBasicFactor notifies the ServeHTTP function to ask for another factor
+ ErrRequiresBasicFactor = errors.New("requires basic factor")
+ // ErrRequiresExtendedFactor is a generic error for providers which require a previous factor
+ ErrRequiresExtendedFactor = errors.New("requires extended factor")
+
+ ErrRequiresSudoFactor = errors.New("requires sudo factor")
// ErrUserDoesNotSupportFactor is a generic error for providers with are unable to support the user
ErrUserDoesNotSupportFactor = errors.New("user does not support factor")
)
diff --git a/auth/login.go b/auth/login.go
index 65baa65..f58ae2e 100644
--- a/auth/login.go
+++ b/auth/login.go
@@ -19,7 +19,7 @@ type BasicLogin struct {
DB basicLoginDB
}
-func (b *BasicLogin) Factor() Factor { return FactorFirst }
+func (b *BasicLogin) Factor() Factor { return FactorBasic }
func (b *BasicLogin) Name() string { return "basic" }
diff --git a/auth/oauth.go b/auth/oauth.go
index 8a6406e..8c4eddc 100644
--- a/auth/oauth.go
+++ b/auth/oauth.go
@@ -32,7 +32,7 @@ func (o OAuthLogin) Init() {
o.flow = cache.New[string, flowStateData]()
}
-func (o OAuthLogin) Factor() Factor { return FactorFirst }
+func (o OAuthLogin) Factor() Factor { return FactorBasic }
func (o OAuthLogin) Name() string { return "oauth" }
diff --git a/auth/otp.go b/auth/otp.go
index 27b209a..5a1e5d5 100644
--- a/auth/otp.go
+++ b/auth/otp.go
@@ -23,7 +23,7 @@ type OtpLogin struct {
DB otpLoginDB
}
-func (o *OtpLogin) Factor() Factor { return FactorSecond }
+func (o *OtpLogin) Factor() Factor { return FactorExtended }
func (o *OtpLogin) Name() string { return "basic" }
diff --git a/auth/passkey.go b/auth/passkey.go
index 9b61a8a..ec9ba11 100644
--- a/auth/passkey.go
+++ b/auth/passkey.go
@@ -16,7 +16,7 @@ type PasskeyLogin struct {
DB passkeyLoginDB
}
-func (p *PasskeyLogin) Factor() Factor { return FactorFirst }
+func (p *PasskeyLogin) Factor() Factor { return FactorBasic }
func (p *PasskeyLogin) Name() string { return "passkey" }
diff --git a/server/login.go b/server/login.go
index e64db9c..3e8a25f 100644
--- a/server/login.go
+++ b/server/login.go
@@ -49,7 +49,7 @@ func (h *httpServer) testAuthSources(req *http.Request, user *database.User, fac
if i.Factor()&factor == 0 {
continue
}
- err := i.RenderData(req.Context(), req, user, data)
+ err := i.RenderTemplate(req.Context(), req, user, data)
authSource[i.Name()] = err == nil
clear(data)
}
@@ -76,14 +76,14 @@ func (h *httpServer) loginGet(rw http.ResponseWriter, req *http.Request, _ httpr
return
}
- fmt.Printf("%#v\n", h.testAuthSources(req, userPtr, auth2.FactorFirst))
+ fmt.Printf("%#v\n", h.testAuthSources(req, userPtr, auth2.FactorBasic))
web.RenderPageTemplate(rw, "login-memory", map[string]any{
"ServiceName": h.conf.ServiceName,
"LoginName": cookie.Value,
"Redirect": req.URL.Query().Get("redirect"),
"Source": "start",
- "Auth": h.testAuthSources(req, userPtr, auth2.FactorFirst),
+ "Auth": h.testAuthSources(req, userPtr, auth2.FactorBasic),
})
return
}
@@ -94,7 +94,7 @@ func (h *httpServer) loginGet(rw http.ResponseWriter, req *http.Request, _ httpr
"LoginName": "",
"Redirect": req.URL.Query().Get("redirect"),
"Source": "start",
- "Auth": h.testAuthSources(req, nil, auth2.FactorFirst),
+ "Auth": h.testAuthSources(req, nil, auth2.FactorBasic),
})
}
diff --git a/web/.editorconfig b/web/.editorconfig
new file mode 100644
index 0000000..d7a5ca0
--- /dev/null
+++ b/web/.editorconfig
@@ -0,0 +1,6 @@
+# EditorConfig is awesome: https://editorconfig.org
+
+# Matches multiple files with brace expansion notation
+# Set default charset
+[*.js]
+charset = utf-8
diff --git a/web/src/components/Header.astro b/web/src/components/Header.astro
new file mode 100644
index 0000000..c6ee9d8
--- /dev/null
+++ b/web/src/components/Header.astro
@@ -0,0 +1,3 @@
+[[.ServiceName]]
+