aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/mirumd/server_admin.go')
-rw-r--r--cmd/mirumd/server_admin.go86+86 −0
1 files changed, 86 insertions, 0 deletions
diff --git a/cmd/mirumd/server_admin.go b/cmd/mirumd/server_admin.go
new file mode 100644
--- /dev/null
+++ b/cmd/mirumd/server_admin.go
@@ -0,0 +1,86 @@
+// Copyright (c) 2026 Nikolay Govorov
+// SPDX-License-Identifier: AGPL-3.0-or-later
+
+package main
+
+import (
+ "context"
+ "crypto/ed25519"
+ "fmt"
+ "net/http"
+
+ "connectrpc.com/connect"
+ "google.golang.org/protobuf/types/known/timestamppb"
+
+ "dimidiumlabs/mirum/internal/protocol/pb"
+ "dimidiumlabs/mirum/internal/protocol/pb/pbconnect"
+)
+
+func NewAdminServer(srv *server) *http.Server {
+ as := &adminService{srv: srv}
+ path, handler := pbconnect.NewAdminHandler(as)
+ mux := http.NewServeMux()
+ mux.Handle(path, handler)
+ return &http.Server{Handler: mux}
+}
+
+type adminService struct {
+ pbconnect.UnimplementedAdminHandler
+ srv *server
+}
+
+func (a *adminService) CreateUser(ctx context.Context, req *connect.Request[pb.CreateUserRequest]) (*connect.Response[pb.CreateUserResponse], error) {
+ id, err := a.srv.db.CreateUser(ctx, req.Msg.Email, req.Msg.Password, []byte(a.srv.cfg.Pepper))
+ if err != nil {
+ return nil, err
+ }
+ return connect.NewResponse(&pb.CreateUserResponse{Id: id}), nil
+}
+
+func (a *adminService) SetPassword(ctx context.Context, req *connect.Request[pb.SetPasswordRequest]) (*connect.Response[pb.SetPasswordResponse], error) {
+ if err := a.srv.db.SetPassword(ctx, req.Msg.Email, req.Msg.Password, []byte(a.srv.cfg.Pepper)); err != nil {
+ return nil, err
+ }
+ return connect.NewResponse(&pb.SetPasswordResponse{}), nil
+}
+
+func (a *adminService) DeleteUser(ctx context.Context, req *connect.Request[pb.DeleteUserRequest]) (*connect.Response[pb.DeleteUserResponse], error) {
+ if err := a.srv.db.DeleteUser(ctx, req.Msg.Email); err != nil {
+ return nil, err
+ }
+ return connect.NewResponse(&pb.DeleteUserResponse{}), nil
+}
+
+func (a *adminService) WorkerAdd(ctx context.Context, req *connect.Request[pb.WorkerAddRequest]) (*connect.Response[pb.WorkerAddResponse], error) {
+ if len(req.Msg.PublicKey) != ed25519.PublicKeySize {
+ return nil, fmt.Errorf("invalid public key: expected %d bytes, got %d", ed25519.PublicKeySize, len(req.Msg.PublicKey))
+ }
+ id, err := a.srv.db.AddWorker(ctx, req.Msg.PublicKey)
+ if err != nil {
+ return nil, err
+ }
+ return connect.NewResponse(&pb.WorkerAddResponse{Id: id}), nil
+}
+
+func (a *adminService) WorkerRevoke(ctx context.Context, req *connect.Request[pb.WorkerRevokeRequest]) (*connect.Response[pb.WorkerRevokeResponse], error) {
+ if err := a.srv.db.RevokeWorker(ctx, req.Msg.Id); err != nil {
+ return nil, err
+ }
+ return connect.NewResponse(&pb.WorkerRevokeResponse{}), nil
+}
+
+func (a *adminService) WorkerList(ctx context.Context, req *connect.Request[pb.WorkerListRequest]) (*connect.Response[pb.WorkerListResponse], error) {
+ workers, err := a.srv.db.ListWorkers(ctx)
+ if err != nil {
+ return nil, err
+ }
+ pbWorkers := make([]*pb.Worker, len(workers))
+ for i, w := range workers {
+ pbWorkers[i] = &pb.Worker{
+ Id: w.ID,
+ PublicKey: w.PublicKey,
+ CreatedAt: timestamppb.New(w.CreatedAt),
+ }
+ }
+ return connect.NewResponse(&pb.WorkerListResponse{Workers: pbWorkers}), nil
+}