refactor(server): rename stuff from Lysand to Versia

Big diff energy
This commit is contained in:
DevMiner 2024-08-27 19:59:12 +02:00
parent 03e01548dc
commit cb135706e2
29 changed files with 103 additions and 96 deletions

2
.env
View file

@ -4,7 +4,7 @@ VERSIA_PORT=8080
#VERSIA_TLS_CERT=
VERSIA_INSTANCE_ADDRESS=http://localhost:8080
VERSIA_INSTANCE_NAME=lysand-test
VERSIA_INSTANCE_NAME=My Versia
VERSIA_INSTANCE_DESCRIPTION=Versia-Go Instance
NATS_URI=nats://localhost:4222

View file

@ -38,14 +38,15 @@ go run .
- [ ] Follows
- [ ] API
- [x] Automatic follows for public users
- [ ] Unfollows (scheduled for Lysand Working Draft 4)
- [ ] Unfollows (scheduled for Versia Working Draft 4)
- [ ] API
- [ ] Users
- [ ] API
- [x] Create user
- [ ] Lysand API
- [ ] Versia API
- [x] Get user (from local)
- [x] Webfinger
- [ ] User discovery
- [ ] Inbox handling
- [ ] Federated notes
- [ ] Federated unfollows

View file

@ -23,30 +23,15 @@ services:
versia-1:
<<: *versia-default
hostname: lysand-test.i.devminer.xyz
hostname: versia.localhost
volumes:
- type: bind
source: ./1.db
target: /app/test.db
environment:
VERSIA_PORT: 8080
VERSIA_INSTANCE_ADDRESS: https://lysand-test.i.devminer.xyz:8080
VERSIA_INSTANCE_ADDRESS: http://versia.localhost:8080
NATS_URI: nats://nats:4222
NATS_STREAM_NAME: versia-go-1
NATS_STREAM_NAME: versia-go
ports:
- "8080:8080"
versia-2:
<<: *versia-default
hostname: lysand-test-2.i.devminer.xyz
volumes:
- type: bind
source: ./2.db
target: /app/test.db
environment:
VERSIA_PORT: 8081
VERSIA_INSTANCE_ADDRESS: https://lysand-test-2.i.devminer.xyz:8081
NATS_URI: nats://nats:4222
NATS_STREAM_NAME: versia-go-2
ports:
- "8081:8081"

View file

@ -9,35 +9,32 @@ import (
type Follow struct {
*ent.Follow
URI *versiautils.URL
FollowerURI *versiautils.URL
FolloweeURI *versiautils.URL
URI *versiautils.URL
Follower *User
Followee *User
}
func NewFollow(dbFollow *ent.Follow) (*Follow, error) {
f := &Follow{Follow: dbFollow}
func NewFollow(dbData *ent.Follow) (*Follow, error) {
f := &Follow{Follow: dbData}
var err error
f.URI, err = versiautils.ParseURL(dbFollow.URI)
if err != nil {
if f.URI, err = versiautils.ParseURL(dbData.URI); err != nil {
return nil, err
}
f.FollowerURI, err = versiautils.ParseURL(dbFollow.Edges.Follower.URI)
if err != nil {
if f.Follower, err = NewUser(dbData.Edges.Follower); err != nil {
return nil, err
}
f.FolloweeURI, err = versiautils.ParseURL(dbFollow.Edges.Followee.URI)
if err != nil {
if f.Followee, err = NewUser(dbData.Edges.Followee); err != nil {
return nil, err
}
return f, nil
}
func (f Follow) ToLysand() *versia.Follow {
func (f Follow) ToVersia() *versia.Follow {
return &versia.Follow{
Entity: versia.Entity{
ID: f.ID,
@ -45,12 +42,12 @@ func (f Follow) ToLysand() *versia.Follow {
CreatedAt: versiautils.Time(f.CreatedAt),
Extensions: f.Extensions,
},
Author: f.FollowerURI,
Followee: f.FolloweeURI,
Author: f.Follower.URI,
Followee: f.Followee.URI,
}
}
func (f Follow) ToLysandAccept() *versia.FollowAccept {
func (f Follow) ToVersiaAccept() *versia.FollowAccept {
return &versia.FollowAccept{
Entity: versia.Entity{
ID: f.ID,
@ -58,12 +55,12 @@ func (f Follow) ToLysandAccept() *versia.FollowAccept {
CreatedAt: versiautils.Time(f.CreatedAt),
Extensions: f.Extensions,
},
Author: f.FolloweeURI,
Follower: f.FollowerURI,
Author: f.Followee.URI,
Follower: f.Follower.URI,
}
}
func (f Follow) ToLysandReject() *versia.FollowReject {
func (f Follow) ToVersiaReject() *versia.FollowReject {
return &versia.FollowReject{
Entity: versia.Entity{
ID: f.ID,
@ -71,7 +68,7 @@ func (f Follow) ToLysandReject() *versia.FollowReject {
CreatedAt: versiautils.Time(f.CreatedAt),
Extensions: f.Extensions,
},
Author: f.FolloweeURI,
Follower: f.FollowerURI,
Author: f.Followee.URI,
Follower: f.Follower.URI,
}
}

View file

@ -46,7 +46,7 @@ func NewNote(dbNote *ent.Note) (*Note, error) {
return n, nil
}
func (n Note) ToLysand() versia.Note {
func (n Note) ToVersia() versia.Note {
return versia.Note{
Entity: versia.Entity{
ID: n.ID,

View file

@ -70,7 +70,7 @@ func NewInstanceMetadata(dbData *ent.InstanceMetadata) (*InstanceMetadata, error
return n, nil
}
func (m InstanceMetadata) ToLysand() versia.InstanceMetadata {
func (m InstanceMetadata) ToVersia() versia.InstanceMetadata {
return versia.InstanceMetadata{
CreatedAt: versiautils.TimeFromStd(m.CreatedAt),
Extensions: m.Extensions,

View file

@ -23,10 +23,10 @@ type User struct {
Followers *versiautils.URL
Following *versiautils.URL
DisplayName string
LysandAvatar versiautils.ImageContentTypeMap
LysandBiography versiautils.TextContentTypeMap
Signer versiacrypto.Signer
DisplayName string
Avatar versiautils.ImageContentTypeMap
Biography versiautils.TextContentTypeMap
Signer versiacrypto.Signer
}
func NewUser(dbData *ent.User) (*User, error) {
@ -38,8 +38,8 @@ func NewUser(dbData *ent.User) (*User, error) {
},
DisplayName: dbData.Username,
LysandAvatar: lysandAvatar(dbData),
LysandBiography: lysandBiography(dbData),
Avatar: userAvatar(dbData),
Biography: userBiography(dbData),
}
if dbData.DisplayName != nil {
@ -81,7 +81,7 @@ func NewUser(dbData *ent.User) (*User, error) {
return u, nil
}
func (u User) ToLysand() *versia.User {
func (u User) ToVersia() *versia.User {
return &versia.User{
Entity: versia.Entity{
ID: u.ID,
@ -91,7 +91,7 @@ func (u User) ToLysand() *versia.User {
},
DisplayName: helpers.StringPtr(u.DisplayName),
Username: u.Username,
Avatar: u.LysandAvatar,
Avatar: u.Avatar,
Header: imageMap(u.Edges.HeaderImage),
Indexable: u.Indexable,
PublicKey: versia.UserPublicKey{
@ -99,7 +99,7 @@ func (u User) ToLysand() *versia.User {
Algorithm: u.PublicKeyAlgorithm,
Key: u.PublicKey,
},
Bio: u.LysandBiography,
Bio: u.Biography,
Fields: u.Fields,
Inbox: u.Inbox,
@ -110,7 +110,7 @@ func (u User) ToLysand() *versia.User {
}
}
func lysandAvatar(u *ent.User) versiautils.ImageContentTypeMap {
func userAvatar(u *ent.User) versiautils.ImageContentTypeMap {
if avatar := imageMap(u.Edges.AvatarImage); avatar != nil {
return avatar
}
@ -122,7 +122,7 @@ func lysandAvatar(u *ent.User) versiautils.ImageContentTypeMap {
}
}
func lysandBiography(u *ent.User) versiautils.TextContentTypeMap {
func userBiography(u *ent.User) versiautils.TextContentTypeMap {
if u.Biography == nil {
return nil
}

View file

@ -29,5 +29,5 @@ func New(followService service.FollowService, federationService service.Federati
}
func (i *Handler) Register(r fiber.Router) {
r.Get("/api/follows/:id", i.GetLysandFollow)
r.Get("/api/follows/:id", i.GetVersiaFollow)
}

View file

@ -6,7 +6,7 @@ import (
"github.com/lysand-org/versia-go/internal/api_schema"
)
func (i *Handler) GetLysandFollow(c *fiber.Ctx) error {
func (i *Handler) GetVersiaFollow(c *fiber.Ctx) error {
parsedRequestedFollowID, err := uuid.Parse(c.Params("id"))
if err != nil {
return api_schema.ErrBadRequest(map[string]any{"reason": "Invalid follow ID"})
@ -24,5 +24,5 @@ func (i *Handler) GetLysandFollow(c *fiber.Ctx) error {
})
}
return c.JSON(f.ToLysand())
return c.JSON(f.ToVersia())
}

View file

@ -27,9 +27,9 @@ func New(instanceMetadataService service.InstanceMetadataService, log logr.Logge
}
func (i *Handler) Register(r fiber.Router) {
r.Get("/.well-known/versia", i.GetLysandInstanceMetadata)
r.Get("/.well-known/versia/admins", i.GetLysandInstanceMetadata)
r.Get("/.well-known/versia/moderators", i.GetLysandInstanceMetadata)
r.Get("/.well-known/versia", i.GetVersiaInstanceMetadata)
r.Get("/.well-known/versia/admins", i.GetVersiaInstanceMetadata)
r.Get("/.well-known/versia/moderators", i.GetVersiaInstanceMetadata)
// Webfinger host meta spec
r.Get("/.well-known/host-meta", i.GetHostMeta)

View file

@ -4,11 +4,12 @@ import (
"github.com/gofiber/fiber/v2"
)
func (i *Handler) GetLysandInstanceMetadata(c *fiber.Ctx) error {
func (i *Handler) GetVersiaInstanceMetadata(c *fiber.Ctx) error {
m, err := i.instanceMetadataService.Ours(c.UserContext())
if err != nil {
return err
}
return c.JSON(m.ToLysand())
// TODO: Sign with the instance private key
return c.JSON(m.ToVersia())
}

View file

@ -14,15 +14,26 @@ func (i *Handler) GetNote(c *fiber.Ctx) error {
})
}
u, err := i.noteService.GetNote(c.UserContext(), parsedRequestedNoteID)
n, err := i.noteService.GetNote(c.UserContext(), parsedRequestedNoteID)
if err != nil {
i.log.Error(err, "Failed to query note", "id", parsedRequestedNoteID)
return api_schema.ErrInternalServerError(map[string]any{"reason": "Failed to query note"})
}
if u == nil {
if n == nil {
return api_schema.ErrNotFound(nil)
}
return c.JSON(u.ToLysand())
if !n.Author.IsRemote {
// For local authors we can also sign the note
if err := i.requestSigner.SignAndSend(c, n.Author.Signer, n.ToVersia()); err != nil {
i.log.Error(err, "Failed to sign response body", "id", parsedRequestedNoteID)
return api_schema.ErrInternalServerError(map[string]any{
"reason": "failed to sign response body",
})
}
}
return c.JSON(n.ToVersia())
}

View file

@ -12,16 +12,18 @@ import (
type Handler struct {
noteService service.NoteService
bodyValidator validators.BodyValidator
requestSigner service.RequestSigner
hostMeta webfinger.HostMeta
log logr.Logger
}
func New(noteService service.NoteService, bodyValidator validators.BodyValidator, log logr.Logger) *Handler {
func New(noteService service.NoteService, bodyValidator validators.BodyValidator, requestSigner service.RequestSigner, log logr.Logger) *Handler {
return &Handler{
noteService: noteService,
bodyValidator: bodyValidator,
requestSigner: requestSigner,
hostMeta: webfinger.NewHostMeta(config.C.PublicAddress),

View file

@ -50,5 +50,5 @@ func (i *Handler) SearchUser(c *fiber.Ctx) error {
return api_schema.ErrNotFound(nil)
}
return c.JSON((*api_schema.VersiaUser)(u.ToLysand()))
return c.JSON((*api_schema.VersiaUser)(u.ToVersia()))
}

View file

@ -46,6 +46,6 @@ func (i *Handler) Register(r fiber.Router) {
r.Get("/api/app/users/:id", i.GetUser)
r.Post("/api/app/users/", i.CreateUser)
r.Get("/api/users/:id", i.GetLysandUser)
r.Post("/api/users/:id/inbox", i.LysandInbox)
r.Get("/api/users/:id", i.GetVersiaUser)
r.Post("/api/users/:id/inbox", i.HandleVersiaInbox)
}

View file

@ -12,7 +12,7 @@ import (
"github.com/lysand-org/versia-go/internal/api_schema"
)
func (i *Handler) LysandInbox(c *fiber.Ctx) error {
func (i *Handler) HandleVersiaInbox(c *fiber.Ctx) error {
if err := i.requestValidator.ValidateFiberCtx(c.UserContext(), c); err != nil {
if errors.Is(err, val_impls.ErrInvalidSignature) {
i.log.Error(err, "Invalid signature")

View file

@ -6,7 +6,7 @@ import (
"github.com/lysand-org/versia-go/internal/api_schema"
)
func (i *Handler) GetLysandUser(c *fiber.Ctx) error {
func (i *Handler) GetVersiaUser(c *fiber.Ctx) error {
parsedRequestedUserID, err := uuid.Parse(c.Params("id"))
if err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
@ -27,5 +27,13 @@ func (i *Handler) GetLysandUser(c *fiber.Ctx) error {
return api_schema.ErrNotFound(map[string]any{"id": parsedRequestedUserID})
}
return i.requestSigner.Sign(c, u.Signer, u.ToLysand())
if err := i.requestSigner.SignAndSend(c, u.Signer, u.ToVersia()); err != nil {
i.log.Error(err, "Failed to sign response body", "id", parsedRequestedUserID)
return api_schema.ErrInternalServerError(map[string]any{
"reason": "failed to sign response body",
})
}
return nil
}

View file

@ -50,8 +50,8 @@ func (i *InstanceMetadataRepositoryImpl) GetByHost(ctx context.Context, host str
return entity.NewInstanceMetadata(m)
}
func (i *InstanceMetadataRepositoryImpl) ImportFromLysandByURI(ctx context.Context, uri *versiautils.URL) (*entity.InstanceMetadata, error) {
s := i.telemetry.StartSpan(ctx, "function", "repo_impls/InstanceMetadataRepositoryImpl.ImportFromLysandByURI").
func (i *InstanceMetadataRepositoryImpl) ImportFromVersiaByURI(ctx context.Context, uri *versiautils.URL) (*entity.InstanceMetadata, error) {
s := i.telemetry.StartSpan(ctx, "function", "repo_impls/InstanceMetadataRepositoryImpl.ImportFromVersiaByURI").
AddAttribute("uri", uri.String())
defer s.End()
ctx = s.Context()

View file

@ -62,8 +62,8 @@ func (i *NoteRepositoryImpl) NewNote(ctx context.Context, author *entity.User, c
return entity.NewNote(n)
}
func (i *NoteRepositoryImpl) ImportLysandNote(ctx context.Context, lNote *versia.Note) (*entity.Note, error) {
s := i.telemetry.StartSpan(ctx, "function", "repo_impls/NoteRepositoryImpl.ImportLysandNote")
func (i *NoteRepositoryImpl) ImportVersiaNote(ctx context.Context, lNote *versia.Note) (*entity.Note, error) {
s := i.telemetry.StartSpan(ctx, "function", "repo_impls/NoteRepositoryImpl.ImportVersiaNote")
defer s.End()
ctx = s.Context()

View file

@ -84,8 +84,8 @@ func (i *UserRepositoryImpl) NewUser(ctx context.Context, username, password str
return entity.NewUser(u)
}
func (i *UserRepositoryImpl) ImportLysandUserByURI(ctx context.Context, uri *versiautils.URL) (*entity.User, error) {
s := i.telemetry.StartSpan(ctx, "function", "repo_impls/UserRepositoryImpl.ImportLysandUserByURI")
func (i *UserRepositoryImpl) ImportVersiaUserByURI(ctx context.Context, uri *versiautils.URL) (*entity.User, error) {
s := i.telemetry.StartSpan(ctx, "function", "repo_impls/UserRepositoryImpl.ImportVersiaUserByURI")
defer s.End()
ctx = s.Context()
@ -201,7 +201,7 @@ func (i *UserRepositoryImpl) Resolve(ctx context.Context, uri *versiautils.URL)
if u == nil {
l.V(2).Info("User not found in DB")
u, err := i.ImportLysandUserByURI(ctx, uri)
u, err := i.ImportVersiaUserByURI(ctx, uri)
if err != nil {
l.Error(err, "Failed to import user")
return nil, err
@ -241,7 +241,7 @@ outer:
l.V(2).Info("User not found in DB")
importedUser, err := i.ImportLysandUserByURI(ctx, &uri)
importedUser, err := i.ImportVersiaUserByURI(ctx, &uri)
if err != nil {
l.Error(err, "Failed to import user")

View file

@ -12,7 +12,7 @@ import (
type UserRepository interface {
NewUser(ctx context.Context, username, password string, privateKey ed25519.PrivateKey, publicKey ed25519.PublicKey) (*entity.User, error)
ImportLysandUserByURI(ctx context.Context, uri *versiautils.URL) (*entity.User, error)
ImportVersiaUserByURI(ctx context.Context, uri *versiautils.URL) (*entity.User, error)
GetByID(ctx context.Context, id uuid.UUID) (*entity.User, error)
GetLocalByID(ctx context.Context, id uuid.UUID) (*entity.User, error)
@ -39,14 +39,14 @@ type FollowRepository interface {
type NoteRepository interface {
NewNote(ctx context.Context, author *entity.User, content string, mentions []*entity.User) (*entity.Note, error)
ImportLysandNote(ctx context.Context, lNote *versia.Note) (*entity.Note, error)
ImportVersiaNote(ctx context.Context, lNote *versia.Note) (*entity.Note, error)
GetByID(ctx context.Context, idOrUsername uuid.UUID) (*entity.Note, error)
}
type InstanceMetadataRepository interface {
GetByHost(ctx context.Context, host string) (*entity.InstanceMetadata, error)
ImportFromLysandByURI(ctx context.Context, uri *versiautils.URL) (*entity.InstanceMetadata, error)
ImportFromVersiaByURI(ctx context.Context, uri *versiautils.URL) (*entity.InstanceMetadata, error)
}
type Manager interface {

View file

@ -42,14 +42,14 @@ type NoteService interface {
CreateNote(ctx context.Context, req api_schema.CreateNoteRequest) (*entity.Note, error)
GetNote(ctx context.Context, id uuid.UUID) (*entity.Note, error)
ImportLysandNote(ctx context.Context, lNote *versia.Note) (*entity.Note, error)
ImportVersiaNote(ctx context.Context, lNote *versia.Note) (*entity.Note, error)
}
type FollowService interface {
NewFollow(ctx context.Context, follower, followee *entity.User) (*entity.Follow, error)
GetFollow(ctx context.Context, id uuid.UUID) (*entity.Follow, error)
ImportLysandFollow(ctx context.Context, lFollow *versia.Follow) (*entity.Follow, error)
ImportVersiaFollow(ctx context.Context, lFollow *versia.Follow) (*entity.Follow, error)
}
type InstanceMetadataService interface {
@ -61,5 +61,5 @@ type TaskService interface {
}
type RequestSigner interface {
Sign(c *fiber.Ctx, signer versiacrypto.Signer, body any) error
SignAndSend(c *fiber.Ctx, signer versiacrypto.Signer, body any) error
}

View file

@ -113,7 +113,7 @@ func (i InboxServiceImpl) handleFollow(ctx context.Context, o versia.Follow, u *
return err
}
if _, err := i.federationService.SendToInbox(ctx, u, author, f.ToLysandAccept()); err != nil {
if _, err := i.federationService.SendToInbox(ctx, u, author, f.ToVersiaAccept()); err != nil {
i.log.Error(err, "Failed to send follow accept to inbox", "user", user.ID, "author", author.ID)
return err
}

View file

@ -69,8 +69,8 @@ func (i FollowServiceImpl) GetFollow(ctx context.Context, id uuid.UUID) (*entity
return f, nil
}
func (i FollowServiceImpl) ImportLysandFollow(ctx context.Context, lFollow *versia.Follow) (*entity.Follow, error) {
s := i.telemetry.StartSpan(ctx, "function", "svc_impls/FollowServiceImpl.ImportLysandFollow").
func (i FollowServiceImpl) ImportVersiaFollow(ctx context.Context, lFollow *versia.Follow) (*entity.Follow, error) {
s := i.telemetry.StartSpan(ctx, "function", "svc_impls/FollowServiceImpl.ImportVersiaFollow").
AddAttribute("uri", lFollow.URI.String())
defer s.End()
ctx = s.Context()

View file

@ -89,10 +89,10 @@ func (i NoteServiceImpl) GetNote(ctx context.Context, id uuid.UUID) (*entity.Not
return i.repositories.Notes().GetByID(ctx, id)
}
func (i NoteServiceImpl) ImportLysandNote(ctx context.Context, lNote *versia.Note) (*entity.Note, error) {
s := i.telemetry.StartSpan(ctx, "function", "svc_impls/NoteServiceImpl.ImportLysandNote")
func (i NoteServiceImpl) ImportVersiaNote(ctx context.Context, lNote *versia.Note) (*entity.Note, error) {
s := i.telemetry.StartSpan(ctx, "function", "svc_impls/NoteServiceImpl.ImportVersiaNote")
defer s.End()
ctx = s.Context()
return i.repositories.Notes().ImportLysandNote(ctx, lNote)
return i.repositories.Notes().ImportVersiaNote(ctx, lNote)
}

View file

@ -27,8 +27,8 @@ func NewRequestSignerImpl(telemetry *unitel.Telemetry, log logr.Logger) *Request
}
}
func (i *RequestSignerImpl) Sign(c *fiber.Ctx, signer versiacrypto.Signer, body any) error {
s := i.telemetry.StartSpan(c.UserContext(), "function", "svc_impls/RequestSignerImpl.Sign")
func (i *RequestSignerImpl) SignAndSend(c *fiber.Ctx, signer versiacrypto.Signer, body any) error {
s := i.telemetry.StartSpan(c.UserContext(), "function", "svc_impls/RequestSignerImpl.SignAndSend")
defer s.End()
j, err := json.Marshal(body)
@ -58,5 +58,7 @@ func (i *RequestSignerImpl) Sign(c *fiber.Ctx, signer versiacrypto.Signer, body
i.log.V(2).Info("signed response", "digest", base64.StdEncoding.EncodeToString(digest), "nonce", nonce)
c.Set(fiber.HeaderContentType, fiber.MIMEApplicationJSONCharsetUTF8)
return c.Send(j)
}

View file

@ -35,7 +35,7 @@ func (t *Handler) FederateNote(ctx context.Context, data FederateNoteData) error
continue
}
res, err := t.federationService.SendToInbox(ctx, n.Author, &uu, n.ToLysand())
res, err := t.federationService.SendToInbox(ctx, n.Author, &uu, n.ToVersia())
if err != nil {
t.log.Error(err, "Failed to send note to remote user", "res", res, "user", uu.ID)
} else {

View file

@ -145,7 +145,7 @@ func main() {
// Handlers
userHandler := user_handler.New(federationService, requestSigner, userService, inboxService, bodyValidator, requestValidator, zerologr.New(&log.Logger).WithName("user-handler"))
noteHandler := note_handler.New(noteService, bodyValidator, zerologr.New(&log.Logger).WithName("notes-handler"))
noteHandler := note_handler.New(noteService, bodyValidator, requestSigner, zerologr.New(&log.Logger).WithName("notes-handler"))
followHandler := follow_handler.New(followService, federationService, zerologr.New(&log.Logger).WithName("follow-handler"))
metaHandler := meta_handler.New(instanceMetadataService, zerologr.New(&log.Logger).WithName("meta-handler"))