refactor(workspace): 🎨 improve structure and format of the code

master
Xeronith 2022-09-15 19:56:40 +04:30
rodzic 0af876979b
commit 1c2528ec80
17 zmienionych plików z 144 dodań i 96 usunięć

Wyświetl plik

@ -24,3 +24,15 @@ type Link struct {
Type *string `json:"type,omitempty"`
Template *string `json:"template,omitempty"`
}
func (webfinger *Webfinger) Self() string {
self := ""
for _, link := range webfinger.Links {
if link.Rel == "self" && link.Type != nil && *link.Type == "application/activity+json" {
self = *link.Href
break
}
}
return self
}

Wyświetl plik

@ -0,0 +1,26 @@
package domain
import (
"fmt"
"strings"
)
type Username string
func (u Username) IsFederated() bool {
return strings.Contains(string(u), "@")
}
func (u Username) IsEmpty() bool {
return strings.TrimSpace(string(u)) == ""
}
func (u Username) Webfinger() string {
username := string(u)
parts := strings.Split(username, "@")
return fmt.Sprintf("https://%s/.well-known/webfinger?resource=acct:%s", parts[1], username)
}
func (u Username) String() string {
return string(u)
}

Wyświetl plik

@ -23,17 +23,17 @@ var Follow = route.New(HttpGet, "/u/:name/follow", func(x IContext) error {
webfingerUrl := x.StringUtil().Format("https://%s/.well-known/webfinger?resource=acct:%s", parts[1], follower)
resp, err := http.Get(webfingerUrl)
if err != nil {
x.InternalServerError(err.Error())
x.InternalServerError(err)
}
data, err := io.ReadAll(resp.Body)
if err != nil {
x.InternalServerError(err.Error())
x.InternalServerError(err)
}
webfinger, err := activitypub.UnmarshalWebfinger(data)
if err != nil {
x.InternalServerError(err.Error())
x.InternalServerError(err)
}
template := ""

Wyświetl plik

@ -22,7 +22,7 @@ var Followers = route.New(HttpGet, "/u/:username/followers", func(x IContext) er
followers := &[]types.FollowerResponse{}
err := repos.FindFollowers(followers, actor).Error
if err != nil {
x.InternalServerError(err.Error())
x.InternalServerError(err)
}
items := []string{}
@ -51,7 +51,7 @@ var AcceptFollowRequest = route.New(HttpPut, "/u/:username/followers/:id/accept"
follower := &repos.Follower{}
if err := repos.FindFollowerById(follower, followerId).Error; err != nil {
return x.InternalServerError(err.Error())
return x.InternalServerError(err)
}
data, _ := json.Marshal(&activitypub.Activity{
@ -70,12 +70,12 @@ var AcceptFollowRequest = route.New(HttpPut, "/u/:username/followers/:id/accept"
keyId := x.StringUtil().Format("%s://%s/u/%s#main-key", config.PROTOCOL, config.DOMAIN, username)
if err := x.PostActivityStream(follower.HandleInbox, keyId, user.PrivateKey, data, nil); err != nil {
return x.InternalServerError(err.Error())
if err := x.PostActivityStreamSigned(follower.HandleInbox, keyId, user.PrivateKey, data, nil); err != nil {
return x.InternalServerError(err)
}
if err := repos.AcceptFollower(follower.ID).Error; err != nil {
return x.InternalServerError(err.Error())
return x.InternalServerError(err)
}
return x.Nothing()

Wyświetl plik

@ -17,7 +17,7 @@ var Following = route.New(HttpGet, "/u/:username/following", func(x IContext) er
followings := &[]types.FollowerResponse{}
err := repos.FindFollowing(followings, actor).Error
if err != nil {
x.InternalServerError(err.Error())
x.InternalServerError(err)
}
items := []string{}

Wyświetl plik

@ -44,8 +44,8 @@ var InboxPost = route.New(HttpPost, "/u/:username/inbox", func(x IContext) error
{
actor := &activitypub.Actor{}
if err := x.GetActivityStream(url, keyId, user.PrivateKey, nil, actor); err != nil {
return x.InternalServerError(err.Error())
if err := x.GetActivityStreamSigned(url, keyId, user.PrivateKey, nil, actor); err != nil {
return x.InternalServerError(err)
}
inbox = actor.Inbox
@ -53,7 +53,7 @@ var InboxPost = route.New(HttpPost, "/u/:username/inbox", func(x IContext) error
data, err := json.Marshal(activity)
if err != nil {
return x.InternalServerError(err.Error())
return x.InternalServerError(err)
}
follower := &repos.Follower{
@ -65,7 +65,7 @@ var InboxPost = route.New(HttpPost, "/u/:username/inbox", func(x IContext) error
}
if err := repos.CreateFollower(follower); err.Error != nil {
return x.Conflict(err.Error.Error())
return x.Conflict(err.Error)
}
if user.Access == repos.ACCESS_PUBLIC {
@ -77,13 +77,13 @@ var InboxPost = route.New(HttpPost, "/u/:username/inbox", func(x IContext) error
Object: activity,
})
if err := x.PostActivityStream(inbox, keyId, user.PrivateKey, data, nil); err != nil {
return x.InternalServerError(err.Error())
if err := x.PostActivityStreamSigned(inbox, keyId, user.PrivateKey, data, nil); err != nil {
return x.InternalServerError(err)
}
err := repos.AcceptFollower(follower.ID).Error
if err != nil {
return x.InternalServerError(err.Error())
return x.InternalServerError(err)
}
}
@ -112,7 +112,7 @@ var InboxPost = route.New(HttpPost, "/u/:username/inbox", func(x IContext) error
}
if err := repos.CreateIncomingActivity(message); err.Error != nil {
return x.Conflict(err.Error.Error())
return x.Conflict(err.Error)
}
return x.Nothing()

Wyświetl plik

@ -19,7 +19,7 @@ var OutboxPost = route.New(HttpPost, "/u/:username/outbox", func(x IContext) err
object := &activitypub.Object{}
if err := x.ParseBodyAndValidate(object); err != nil {
return x.BadRequest(err.Error())
return x.BadRequest(err)
}
key := &types.KeyResponse{}
@ -35,7 +35,7 @@ var OutboxPost = route.New(HttpPost, "/u/:username/outbox", func(x IContext) err
{
note := &activitypub.Note{}
if err := x.ParseBodyAndValidate(note); err != nil {
return x.BadRequest(err.Error())
return x.BadRequest(err)
}
activity := note.Wrap(username)
@ -44,16 +44,16 @@ var OutboxPost = route.New(HttpPost, "/u/:username/outbox", func(x IContext) err
if to != activitypub.Public {
recipient := &activitypub.Actor{}
if err := x.GetActivityStream(to, keyId, key.PrivateKey, nil, recipient); err != nil {
return x.InternalServerError(err.Error())
if err := x.GetActivityStreamSigned(to, keyId, key.PrivateKey, nil, recipient); err != nil {
return x.InternalServerError(err)
}
to = recipient.ID
data, _ := json.Marshal(activity)
output := &struct{}{}
if err := x.PostActivityStream(recipient.Inbox, keyId, key.PrivateKey, data, output); err != nil {
return x.InternalServerError(err.Error())
if err := x.PostActivityStreamSigned(recipient.Inbox, keyId, key.PrivateKey, data, output); err != nil {
return x.InternalServerError(err)
}
}
@ -66,7 +66,7 @@ var OutboxPost = route.New(HttpPost, "/u/:username/outbox", func(x IContext) err
}
if err := repos.CreateOutgoingActivity(message); err.Error != nil {
return x.Conflict(err.Error.Error())
return x.Conflict(err.Error)
}
return x.Nothing()

Wyświetl plik

@ -28,7 +28,7 @@ var GetProfile = route.New(HttpGet, "/api/v1/profile", func(x IContext) error {
if errors.Is(err, gorm.ErrRecordNotFound) {
return x.Unauthorized("not_found")
} else {
return x.InternalServerError(err.Error())
return x.InternalServerError(err)
}
}

Wyświetl plik

@ -44,7 +44,7 @@ var Signup = route.New(HttpPost, "/api/v1/signup", func(x IContext) error {
}
if err := repos.CreateUser(user); err.Error != nil {
return x.Conflict(err.Error.Error())
return x.Conflict(err.Error)
}
token := jwt.Generate(&jwt.TokenPayload{

Wyświetl plik

@ -12,7 +12,7 @@ import (
var Upload = route.New(contracts.HttpPost, "/upload", func(x contracts.IContext) error {
file, err := x.Request().FormFile("file")
if err != nil {
return x.InternalServerError(err.Error())
return x.InternalServerError(err)
}
uuid := uuid.New().String()
@ -21,7 +21,7 @@ var Upload = route.New(contracts.HttpPost, "/upload", func(x contracts.IContext)
filePath := path.Join(config.UPLOAD_PATH, fileName)
if err = x.SaveFile(file, filePath); err != nil {
return x.InternalServerError(err.Error())
return x.InternalServerError(err)
}
return x.Json(struct {

Wyświetl plik

@ -2,58 +2,53 @@ package routes
import (
"activitypub"
"app/models/domain"
"app/models/repos"
"config"
. "contracts"
"contracts"
"errors"
"fmt"
"server/mime"
"server/route"
"strings"
"gorm.io/gorm"
)
var User = route.New(HttpGet, "/u/:username", func(x IContext) error {
username := x.Request().Params("username")
if username == "" {
return x.BadRequest("Bad request")
var User = route.New(contracts.HttpGet, "/u/:username", func(x contracts.IContext) error {
username := domain.Username(x.Request().Params("username"))
if username.IsEmpty() {
return x.BadRequest("username required.")
}
if x.StringUtil().Contains(username, "@") {
parts := x.StringUtil().Split(username, "@")
url := x.StringUtil().Format("https://%s/.well-known/webfinger?resource=acct:%s", parts[1], username)
if username.IsFederated() {
webfinger := activitypub.Webfinger{}
if err := x.GetActivityStream(url, "", "", nil, &webfinger); err != nil {
return x.InternalServerError(err.Error())
if err := x.GetActivityStream(username.Webfinger(), nil, &webfinger); err != nil {
return x.InternalServerError(err)
}
actor := activitypub.Actor{}
if err := x.GetActivityStream(webfinger.Aliases[0], "activitystream", "", nil, &actor); err != nil {
return x.InternalServerError(err.Error())
if err := x.GetActivityStream(webfinger.Self(), nil, &actor); err != nil {
return x.InternalServerError(err)
}
return x.Activity(actor)
}
user := &repos.User{}
err := repos.FindUserByUsername(user, username).Error
if errors.Is(err, gorm.ErrRecordNotFound) {
return x.NotFound("No record found for %s.", username)
}
actor := createActor(user)
if strings.Contains(x.Request().Header("Accept"), mime.ActivityJson) {
return x.Activity(actor)
} else if config.DOMAIN == config.CLIENT_DOMAIN {
return x.Render("user", ViewData{
"Title": fmt.Sprintf("%s's Public Profile", user.DisplayName),
"Username": user.Username,
"Actor": actor,
})
} else {
client := x.StringUtil().Format("%s://%s/u/%s", config.PROTOCOL, config.CLIENT_DOMAIN, user.Username)
return x.Redirect(client)
user := &repos.User{}
err := repos.FindUserByUsername(user, username.String()).Error
if errors.Is(err, gorm.ErrRecordNotFound) {
return x.NotFound("No record found for %s.", username)
}
str := x.StringUtil()
actor := createActor(user)
if x.Request().AcceptsActivityStream() {
return x.Activity(actor)
} else if config.ExternalClient() {
return x.Redirect(str.Format("%s://%s/u/%s", config.PROTOCOL, config.CLIENT_DOMAIN, user.Username))
} else {
return x.Render("user", contracts.ViewData{
"Title": str.Format("%s's Public Profile", user.DisplayName),
"Username": user.Username,
"Actor": actor,
})
}
}
})

Wyświetl plik

@ -25,7 +25,7 @@ var WebFinger = route.New(HttpGet, "/.well-known/webfinger", func(x IContext) er
if errors.Is(err, gorm.ErrRecordNotFound) {
return x.NotFound("No record found for %s.", name)
} else {
return x.InternalServerError(err.Error())
return x.InternalServerError(err)
}
}

Wyświetl plik

@ -50,3 +50,7 @@ func BodyLimit() int {
return int(maxFileSize) * 1024 * 1024
}
func ExternalClient() bool {
return DOMAIN != CLIENT_DOMAIN
}

Wyświetl plik

@ -23,14 +23,15 @@ type (
Activity(interface{}) error
File(string) error
GetActivityStream(url, keyId, privateKey string, data []byte, output interface{}) error
PostActivityStream(url, keyId, privateKey string, data []byte, output interface{}) error
GetActivityStream(url string, data []byte, output interface{}) error
PostActivityStream(url string, data []byte, output interface{}) error
GetActivityStreamSigned(url, keyId, privateKey string, data []byte, output interface{}) error
PostActivityStreamSigned(url, keyId, privateKey string, data []byte, output interface{}) error
// Error(int, string, ...any) IServerError
BadRequest(string, ...any) IServerError
NotFound(string, ...any) IServerError
InternalServerError(string, ...any) IServerError
Unauthorized(string, ...any) IServerError
Conflict(string, ...any) IServerError
BadRequest(interface{}, ...any) IServerError
NotFound(interface{}, ...any) IServerError
InternalServerError(interface{}, ...any) IServerError
Unauthorized(interface{}, ...any) IServerError
Conflict(interface{}, ...any) IServerError
}
)

Wyświetl plik

@ -115,6 +115,7 @@ type (
FormValue(string) string
FormFile(key string) (*multipart.FileHeader, error)
Header(string) string
AcceptsActivityStream() bool
}
IResponse interface {

Wyświetl plik

@ -123,27 +123,34 @@ func (context *httpServerContext) GetUser() uint {
}
// Error create a server error with status code and message
func (context *httpServerContext) Error(code int, format string, args ...any) IServerError {
return newError(code, fmt.Sprintf(format, args...))
func (context *httpServerContext) Error(code int, format interface{}, args ...any) IServerError {
switch arg := format.(type) {
case string:
return newError(code, fmt.Sprintf(arg, args...))
case error:
return newError(code, arg.Error())
default:
return newError(code, fmt.Sprintf("%v", arg))
}
}
func (context *httpServerContext) BadRequest(format string, args ...any) IServerError {
func (context *httpServerContext) BadRequest(format interface{}, args ...any) IServerError {
return context.Error(StatusBadRequest, format, args...)
}
func (context *httpServerContext) NotFound(format string, args ...any) IServerError {
func (context *httpServerContext) NotFound(format interface{}, args ...any) IServerError {
return context.Error(StatusNotFound, format, args...)
}
func (context *httpServerContext) InternalServerError(format string, args ...any) IServerError {
func (context *httpServerContext) InternalServerError(format interface{}, args ...any) IServerError {
return context.Error(StatusInternalServerError, format, args...)
}
func (context *httpServerContext) Unauthorized(format string, args ...any) IServerError {
func (context *httpServerContext) Unauthorized(format interface{}, args ...any) IServerError {
return context.Error(StatusUnauthorized, format, args...)
}
func (context *httpServerContext) Conflict(format string, args ...any) IServerError {
func (context *httpServerContext) Conflict(format interface{}, args ...any) IServerError {
return context.Error(StatusConflict, format, args...)
}
@ -164,8 +171,6 @@ func (context *httpServerContext) signRequest(keyId, privateKey string, data []b
req.Header.Set("Digest", digest)
}
req.Header.Set("Accept", mime.ActivityJson)
if err := signer.Sign(req); err != nil {
return err
}
@ -184,16 +189,14 @@ func (context *httpServerContext) requestActivityStream(method, url, keyId, priv
return err
}
req.Header.Set("Accept", mime.ActivityJson)
if privateKey != "" {
if err := context.signRequest(keyId, privateKey, data, req); err != nil {
return err
}
}
if keyId == "activitystream" {
req.Header.Add("Accept", "application/activity+json")
}
res, err := context.httpClient.Do(req)
if err != nil {
return err
@ -208,27 +211,27 @@ func (context *httpServerContext) requestActivityStream(method, url, keyId, priv
return fmt.Errorf("%s", res.Status)
}
j, err := io.ReadAll(res.Body)
if err != nil {
return err
}
fmt.Println(string(j))
if output != nil {
if err := json.Unmarshal(j, output); err != nil {
if err := json.NewDecoder(res.Body).Decode(output); err != nil {
return err
}
}
return nil
}
func (context *httpServerContext) GetActivityStream(url, keyId, privateKey string, data []byte, output interface{}) error {
func (context *httpServerContext) GetActivityStream(url string, data []byte, output interface{}) error {
return context.requestActivityStream(http.MethodGet, url, "", "", data, output)
}
func (context *httpServerContext) PostActivityStream(url string, data []byte, output interface{}) error {
return context.requestActivityStream(http.MethodPost, url, "", "", data, output)
}
func (context *httpServerContext) GetActivityStreamSigned(url, keyId, privateKey string, data []byte, output interface{}) error {
return context.requestActivityStream(http.MethodGet, url, keyId, privateKey, data, output)
}
func (context *httpServerContext) PostActivityStream(url, keyId, privateKey string, data []byte, output interface{}) error {
func (context *httpServerContext) PostActivityStreamSigned(url, keyId, privateKey string, data []byte, output interface{}) error {
return context.requestActivityStream(http.MethodPost, url, keyId, privateKey, data, output)
}

Wyświetl plik

@ -3,6 +3,8 @@ package server
import (
"contracts"
"mime/multipart"
"server/mime"
"strings"
"github.com/gofiber/fiber/v2"
)
@ -41,3 +43,7 @@ func (request *httpRequest) FormValue(key string) string {
func (request *httpRequest) FormFile(key string) (*multipart.FileHeader, error) {
return request.context.FormFile(key)
}
func (request *httpRequest) AcceptsActivityStream() bool {
return strings.Contains(request.Header("Accept"), mime.ActivityJson)
}