summaryrefslogtreecommitdiff
path: root/server/admin/handler.go
diff options
context:
space:
mode:
Diffstat (limited to 'server/admin/handler.go')
-rw-r--r--server/admin/handler.go119
1 files changed, 119 insertions, 0 deletions
diff --git a/server/admin/handler.go b/server/admin/handler.go
new file mode 100644
index 0000000..5fd1fee
--- /dev/null
+++ b/server/admin/handler.go
@@ -0,0 +1,119 @@
+package admin
+
+import (
+ "encoding/json"
+ "net/http"
+ "os"
+ "time"
+
+ "git.huntm.net/wedding/server/guest"
+ "github.com/golang-jwt/jwt/v5"
+)
+
+type AdminHandler struct {
+ adminStore adminStore
+ guestStore guest.GuestStore
+}
+
+type adminStore interface {
+ Find(admin Admin) (Admin, error)
+}
+
+type appError struct {
+ Error error
+ Message string
+ Code int
+}
+
+func NewAdminHandler(adminStore adminStore, guestStore guest.GuestStore) *AdminHandler {
+ return &AdminHandler{adminStore, guestStore}
+}
+
+func (adminHandler *AdminHandler) ServeHTTP(responseWriter http.ResponseWriter, request *http.Request) {
+ switch {
+ case request.Method == http.MethodOptions:
+ responseWriter.WriteHeader(http.StatusOK)
+ case request.Method == http.MethodPost && request.URL.Path == "/admin/login":
+ adminHandler.handleLogIn(responseWriter, request)
+ default:
+ responseWriter.WriteHeader(http.StatusNotFound)
+ }
+}
+
+func (adminHandler *AdminHandler) handleLogIn(responseWriter http.ResponseWriter, request *http.Request) {
+ token, err := adminHandler.logIn(request)
+ if err != nil {
+ http.Error(responseWriter, err.Message, err.Code)
+ } else {
+ responseWriter.Write(token)
+ }
+}
+
+func (adminHandler *AdminHandler) logIn(request *http.Request) ([]byte, *appError) {
+ requestAdmin, err := adminHandler.decodeCredentials(request)
+ if err != nil {
+ return []byte{}, &appError{err, "failed to unmarshal request", http.StatusBadRequest}
+ }
+ _, err = adminHandler.adminStore.Find(requestAdmin)
+ if err != nil {
+ return []byte{}, &appError{err, "admin not found", http.StatusUnauthorized}
+ }
+ expirationTime := adminHandler.setExpirationTime()
+ claims := adminHandler.createClaims(requestAdmin, expirationTime)
+ key, err := adminHandler.readKey()
+ if err != nil {
+ return []byte{}, &appError{err, "failed to read secret key", http.StatusInternalServerError}
+ }
+ token, err := adminHandler.createToken(claims, key)
+ if err != nil {
+ return []byte{}, &appError{err, "failed to create token", http.StatusInternalServerError}
+ }
+ guests, err := adminHandler.guestStore.Get()
+ if err != nil {
+ return []byte{}, &appError{err, "failed to get guests", http.StatusInternalServerError}
+ }
+ jsonBytes, err := adminHandler.marshalResponse(guests, token)
+ if err != nil {
+ return []byte{}, &appError{err, "failed to marshal response", http.StatusInternalServerError}
+ }
+ return jsonBytes, nil
+}
+
+func (adminHandler *AdminHandler) decodeCredentials(request *http.Request) (Admin, error) {
+ var admin Admin
+ err := json.NewDecoder(request.Body).Decode(&admin)
+ defer request.Body.Close()
+ return admin, err
+}
+
+func (adminHandler *AdminHandler) setExpirationTime() time.Time {
+ return time.Now().Add(15 * time.Minute)
+}
+
+func (adminHandler *AdminHandler) createClaims(admin Admin, expirationTime time.Time) *Claims {
+ return &Claims{
+ admin,
+ jwt.RegisteredClaims{
+ ExpiresAt: jwt.NewNumericDate(expirationTime),
+ },
+ }
+}
+
+func (adminHandler *AdminHandler) readKey() ([]byte, error) {
+ // TODO: use properties file
+ return os.ReadFile("C:\\Users\\mhunt\\admin.pem")
+}
+
+func (adminHandler *AdminHandler) createToken(claims *Claims, key []byte) (string, error) {
+ token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
+ return token.SignedString(key)
+}
+
+func (adminHandler *AdminHandler) marshalResponse(guests []guest.Guest, token string) ([]byte, error) {
+ loginResponse := adminHandler.createLoginResponse(guests, token)
+ return json.Marshal(loginResponse)
+}
+
+func (adminHandler *AdminHandler) createLoginResponse(guests []guest.Guest, token string) *LoginResponse {
+ return &LoginResponse{guests, token}
+}