Rename cavage singing func, add import for server
All checks were successful
/ docker (push) Successful in 4m1s
All checks were successful
/ docker (push) Successful in 4m1s
This commit is contained in:
parent
5e13817563
commit
08f6de0bd7
39 changed files with 2035 additions and 364 deletions
16
web/debug/remoteServer.go
Normal file
16
web/debug/remoteServer.go
Normal file
|
@ -0,0 +1,16 @@
|
|||
package webdebug
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/rs/zerolog/hlog"
|
||||
|
||||
"git.mstar.dev/mstar/linstrom/activitypub"
|
||||
)
|
||||
|
||||
func importServerInfo(w http.ResponseWriter, r *http.Request) {
|
||||
target := r.FormValue("target")
|
||||
if _, err := activitypub.ImportRemoteServer(target); err != nil {
|
||||
hlog.FromRequest(r).Error().Err(err).Msg("Failed to import")
|
||||
}
|
||||
}
|
|
@ -27,8 +27,9 @@ func New(addr string) *Server {
|
|||
handler.HandleFunc("GET /delete", deleteUser)
|
||||
handler.HandleFunc("POST /post-as", postAs)
|
||||
handler.HandleFunc("GET /notes-for", notesFrom)
|
||||
handler.HandleFunc("GET /import", issueUserImport)
|
||||
handler.HandleFunc("GET /import-user", issueUserImport)
|
||||
handler.HandleFunc("GET /keys-for", returnKeypair)
|
||||
handler.HandleFunc("GET /import-server", importServerInfo)
|
||||
web := http.Server{
|
||||
Addr: addr,
|
||||
Handler: webutils.ChainMiddlewares(
|
||||
|
|
|
@ -38,6 +38,7 @@ func users(w http.ResponseWriter, r *http.Request) {
|
|||
Type string `json:"type"`
|
||||
PreferredUsername string `json:"preferredUsername"`
|
||||
Inbox string `json:"inbox"`
|
||||
Outboux string `json:"outbox"`
|
||||
PublicKey OutboundKey `json:"publicKey"`
|
||||
Published time.Time `json:"published"`
|
||||
DisplayName string `json:"name"`
|
||||
|
@ -82,6 +83,7 @@ func users(w http.ResponseWriter, r *http.Request) {
|
|||
Type: "Person",
|
||||
PreferredUsername: user.Username,
|
||||
Inbox: apUrl + "/inbox",
|
||||
Outboux: apUrl + "/outbox",
|
||||
PublicKey: OutboundKey{
|
||||
Id: apUrl + "#main-key",
|
||||
Owner: apUrl,
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
"git.mstar.dev/mstar/linstrom/shared"
|
||||
"git.mstar.dev/mstar/linstrom/storage-new"
|
||||
"git.mstar.dev/mstar/linstrom/storage-new/dbgen"
|
||||
webshared "git.mstar.dev/mstar/linstrom/web/shared"
|
||||
)
|
||||
|
||||
var webfingerResourceRegex = regexp.MustCompile(`acct:(?P<username>[\w-]+)@(?<domain>[\w\.-]+)`)
|
||||
|
@ -103,7 +104,23 @@ func WellKnownWebfinger(w http.ResponseWriter, r *http.Request) {
|
|||
webutils.SendJson(w, &data)
|
||||
}
|
||||
|
||||
func Nodeinfo(w http.ResponseWriter, r *http.Request) {
|
||||
func NodeInfoOverview(w http.ResponseWriter, r *http.Request) {
|
||||
data := webshared.NodeInfoOverview{
|
||||
Links: []webshared.NodeInfoLink{
|
||||
{
|
||||
Rel: "http://nodeinfo.diaspora.software/ns/schema/2.1",
|
||||
Href: config.GlobalConfig.General.GetFullPublicUrl() + "/nodeinfo/2.1",
|
||||
},
|
||||
{
|
||||
Rel: "http://nodeinfo.diaspora.software/ns/schema/2.0",
|
||||
Href: config.GlobalConfig.General.GetFullPublicUrl() + "/nodeinfo/2.0",
|
||||
},
|
||||
},
|
||||
}
|
||||
webutils.SendJson(w, data)
|
||||
}
|
||||
|
||||
func NodeInfo21(w http.ResponseWriter, r *http.Request) {
|
||||
u := dbgen.User
|
||||
log := hlog.FromRequest(r)
|
||||
userCount, err := u.Where(u.DeletedAt.IsNull(), u.Verified.Is(true)).Count()
|
||||
|
@ -128,42 +145,81 @@ func Nodeinfo(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
data := map[string]any{
|
||||
"version": "2.1",
|
||||
"software": map[string]string{
|
||||
"name": "linstrom",
|
||||
"version": shared.Version,
|
||||
"homepage": "https://git.mstar.dev/mstar/linstrom",
|
||||
"repository": "https://git.mstar.dev/mstar/linstrom",
|
||||
data := webshared.NodeInfo2{
|
||||
Version: "2.1",
|
||||
Software: webshared.NodeInfo2Software{
|
||||
Name: "linstrom",
|
||||
Version: shared.Version,
|
||||
Homepage: other.IntoPointer("https://git.mstar.dev/mstar/linstrom"),
|
||||
Repository: other.IntoPointer("https://git.mstar.dev/mstar/linstrom"),
|
||||
},
|
||||
"protocols": []string{"activitypub"},
|
||||
"services": map[string]any{
|
||||
"inbound": []string{},
|
||||
"outbound": []string{},
|
||||
Protocols: []string{"activitypub"},
|
||||
Services: map[string][]string{
|
||||
"inbound": {},
|
||||
"outbound": {},
|
||||
},
|
||||
"openRegistrations": config.GlobalConfig.Admin.AllowRegistration,
|
||||
"usage": map[string]any{
|
||||
"users": map[string]any{
|
||||
"total": userCount,
|
||||
"activeHalfyear": nil,
|
||||
"activeMonth": nil,
|
||||
OpenRegistrations: config.GlobalConfig.Admin.AllowRegistration,
|
||||
Usage: webshared.NodeInfo2Usage{
|
||||
Users: webshared.NodeInfo2UsageUsers{
|
||||
Total: uint(userCount),
|
||||
ActiveHalfYear: nil,
|
||||
ActiveMonth: nil,
|
||||
},
|
||||
"localPosts": noteCount,
|
||||
"localComments": 0,
|
||||
},
|
||||
"metadata": map[string]any{},
|
||||
LocalPosts: uint(noteCount),
|
||||
LocalComments: 0},
|
||||
Metadata: map[string]any{},
|
||||
}
|
||||
webutils.SendJson(w, data)
|
||||
}
|
||||
|
||||
func WellKnownNodeinfo(w http.ResponseWriter, r *http.Request) {
|
||||
data := map[string]any{
|
||||
"links": []map[string]any{
|
||||
{
|
||||
"rel": "http://nodeinfo.diaspora.software/ns/schema/2.1",
|
||||
"href": config.GlobalConfig.General.GetFullPublicUrl() + "/nodeinfo/2.1",
|
||||
},
|
||||
},
|
||||
func NodeInfo20(w http.ResponseWriter, r *http.Request) {
|
||||
u := dbgen.User
|
||||
log := hlog.FromRequest(r)
|
||||
userCount, err := u.Where(u.DeletedAt.IsNull(), u.Verified.Is(true)).Count()
|
||||
if err != nil {
|
||||
webutils.ProblemDetails(w, 500, "/errors/db-failure", "internal database failure", nil, nil)
|
||||
if storage.HandleReconnectError(err) {
|
||||
log.Warn().Msg("Connection to db lost. Reconnect attempt started")
|
||||
} else {
|
||||
log.Error().Err(err).Msg("Failed to get total user count from db")
|
||||
}
|
||||
return
|
||||
}
|
||||
n := dbgen.Note
|
||||
noteCount, err := n.Where(n.DeletedAt.IsNull(), n.OriginId.Eq(1)).Count()
|
||||
if err != nil {
|
||||
webutils.ProblemDetails(w, 500, "/errors/db-failure", "internal database failure", nil, nil)
|
||||
if storage.HandleReconnectError(err) {
|
||||
log.Warn().Msg("Connection to db lost. Reconnect attempt started")
|
||||
} else {
|
||||
log.Error().Err(err).Msg("Failed to get total user count from db")
|
||||
}
|
||||
return
|
||||
}
|
||||
data := webshared.NodeInfo2{
|
||||
Version: "2.1",
|
||||
Software: webshared.NodeInfo2Software{
|
||||
Name: "linstrom",
|
||||
Version: shared.Version,
|
||||
Homepage: nil,
|
||||
Repository: nil,
|
||||
},
|
||||
Protocols: []string{"activitypub"},
|
||||
Services: map[string][]string{
|
||||
"inbound": {},
|
||||
"outbound": {},
|
||||
},
|
||||
OpenRegistrations: config.GlobalConfig.Admin.AllowRegistration,
|
||||
Usage: webshared.NodeInfo2Usage{
|
||||
Users: webshared.NodeInfo2UsageUsers{
|
||||
Total: uint(userCount),
|
||||
ActiveHalfYear: nil,
|
||||
ActiveMonth: nil,
|
||||
},
|
||||
LocalPosts: uint(noteCount),
|
||||
LocalComments: 0},
|
||||
Metadata: map[string]any{},
|
||||
}
|
||||
|
||||
webutils.SendJson(w, data)
|
||||
}
|
||||
|
|
|
@ -48,8 +48,9 @@ func New(addr string, duckImg *string) *Server {
|
|||
})
|
||||
handler.Handle("/api/", http.StripPrefix("/api", api.BuildApiRouter()))
|
||||
handler.HandleFunc("GET /.well-known/webfinger", api.WellKnownWebfinger)
|
||||
handler.HandleFunc("GET /.well-known/nodeinfo", api.WellKnownNodeinfo)
|
||||
handler.HandleFunc("GET /nodeinfo/2.1", api.Nodeinfo)
|
||||
handler.HandleFunc("GET /.well-known/nodeinfo", api.NodeInfoOverview)
|
||||
handler.HandleFunc("GET /nodeinfo/2.1", api.NodeInfo21)
|
||||
handler.HandleFunc("GET /nodeinfo/2.0", api.NodeInfo20)
|
||||
handler.HandleFunc("GET /errors/{name}", errorTypeHandler)
|
||||
handler.HandleFunc("GET /default-image", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Add("Content-Type", "image/web")
|
||||
|
|
60
web/shared/Nodeinfo.go
Normal file
60
web/shared/Nodeinfo.go
Normal file
|
@ -0,0 +1,60 @@
|
|||
package webshared
|
||||
|
||||
import (
|
||||
"git.mstar.dev/mstar/goutils/sliceutils"
|
||||
|
||||
"git.mstar.dev/mstar/linstrom/storage-new/models"
|
||||
)
|
||||
|
||||
type NodeInfoLink struct {
|
||||
Rel string
|
||||
Href string
|
||||
}
|
||||
|
||||
type NodeInfoOverview struct {
|
||||
Links []NodeInfoLink
|
||||
}
|
||||
|
||||
type NodeInfo2Software struct {
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
Homepage *string `json:"homepage,omitempty"`
|
||||
Repository *string `json:"repository,omitempty"`
|
||||
}
|
||||
|
||||
type NodeInfo2UsageUsers struct {
|
||||
Total uint `json:"total"`
|
||||
ActiveHalfYear *uint `json:"active_half_year"`
|
||||
ActiveMonth *uint `json:"active_month"`
|
||||
}
|
||||
|
||||
type NodeInfo2Usage struct {
|
||||
Users NodeInfo2UsageUsers `json:"users"`
|
||||
LocalPosts uint `json:"local_posts"`
|
||||
LocalComments uint `json:"local_comments"`
|
||||
}
|
||||
|
||||
type NodeInfo2 struct {
|
||||
Version string `json:"version"`
|
||||
Software NodeInfo2Software `json:"software"`
|
||||
Protocols []string `json:"protocols"`
|
||||
Services map[string][]string `json:"services"`
|
||||
OpenRegistrations bool `json:"open_registrations"`
|
||||
Usage NodeInfo2Usage `json:"usage"`
|
||||
Metadata map[string]any `json:"metadata"`
|
||||
}
|
||||
|
||||
func MapNodeServerTypeToModelType(nodeType string) models.ServerSoftwareType {
|
||||
if sliceutils.Contains([]string{"mastodon"}, nodeType) {
|
||||
return models.ServerSoftwareMastodon
|
||||
} else if sliceutils.Contains([]string{"sharkey", "misskey", "iceshrimp", "firefish"}, nodeType) {
|
||||
return models.ServerSoftwareMisskey
|
||||
} else if sliceutils.Contains([]string{"linstrom"}, nodeType) {
|
||||
return models.ServerSoftwareLinstrom
|
||||
} else if sliceutils.Contains([]string{"akkoma"}, nodeType) {
|
||||
return models.ServerSoftwarePlemora
|
||||
} else if sliceutils.Contains([]string{"wafrn"}, nodeType) {
|
||||
return models.ServerSoftwareWafrn
|
||||
}
|
||||
return models.ServerSoftwareUnknown
|
||||
}
|
|
@ -2,8 +2,6 @@ package webshared
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/ed25519"
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
|
@ -11,12 +9,11 @@ import (
|
|||
"slices"
|
||||
"time"
|
||||
|
||||
"github.com/go-fed/httpsig"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/yaronf/httpsign"
|
||||
|
||||
"git.mstar.dev/mstar/linstrom/config"
|
||||
"git.mstar.dev/mstar/linstrom/shared"
|
||||
"git.mstar.dev/mstar/linstrom/storage-new/models"
|
||||
)
|
||||
|
||||
/*
|
||||
|
@ -78,55 +75,32 @@ func RequestSignedRFC9421(
|
|||
func RequestSignedCavage(
|
||||
method, target string,
|
||||
body []byte,
|
||||
keyId string,
|
||||
privateKeyBytes []byte,
|
||||
useEd bool,
|
||||
actor *models.User,
|
||||
) (*http.Response, error) {
|
||||
req, err := http.NewRequest(method, target, bytes.NewBuffer(slices.Clone(body)))
|
||||
req, err := NewRequest(method, target, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
applyDefaultHeaders(req)
|
||||
var prefs []httpsig.Algorithm
|
||||
var key crypto.PrivateKey
|
||||
if useEd {
|
||||
log.Debug().Msg("Using ed25519 cavage")
|
||||
prefs = append(prefs, httpsig.ED25519)
|
||||
key = ed25519.PrivateKey(privateKeyBytes)
|
||||
req.Header.Add("Accept", "application/activity+json")
|
||||
|
||||
var keyBytes []byte
|
||||
if config.GlobalConfig.Experimental.UseEd25519Keys {
|
||||
keyBytes = actor.PrivateKeyEd
|
||||
} else {
|
||||
log.Debug().Msg("Using RSA cavage")
|
||||
// prefs = append(prefs, httpsig.RSA_SHA512, httpsig.RSA_SHA256)
|
||||
prefs = append(prefs, httpsig.RSA_SHA256)
|
||||
tempKey, err := x509.ParsePKCS1PrivateKey(privateKeyBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
key = tempKey
|
||||
keyBytes = actor.PrivateKeyRsa
|
||||
}
|
||||
digestAlgorithm := httpsig.DigestSha256
|
||||
headersToSign := []string{httpsig.RequestTarget, "date", "host", "user-agent"}
|
||||
if len(body) > 0 {
|
||||
headersToSign = append(headersToSign, "digest")
|
||||
log.Debug().Msg("Non-empty body, adding digest")
|
||||
} else {
|
||||
// Just to ensure the signer doesn't fuck up
|
||||
body = nil
|
||||
}
|
||||
signer, chosenAlgorithm, err := httpsig.NewSigner(
|
||||
prefs,
|
||||
digestAlgorithm,
|
||||
headersToSign,
|
||||
httpsig.Signature,
|
||||
int64(time.Hour),
|
||||
|
||||
// Sign and send
|
||||
err = SignRequest(
|
||||
req,
|
||||
actor.ID+"#main-key",
|
||||
keyBytes,
|
||||
body,
|
||||
)
|
||||
// err = webshared.SignRequestWithHttpsig(req, linstromActor.ID+"#main-key", keyBytes, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Debug().Any("algorithm", chosenAlgorithm).Msg("Signer chose algorithm")
|
||||
if err = signer.SignRequest(key, keyId, req, body); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Debug().Any("headers", req.Header).Msg("Request post signing")
|
||||
return RequestClient.Do(req)
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ func CreateSignatureRSA(
|
|||
return "", nil, err
|
||||
}
|
||||
encoded := base64.StdEncoding.EncodeToString(signed)
|
||||
log.Debug().
|
||||
log.Trace().
|
||||
Str("raw-message", message).
|
||||
Bytes("signed", signed).
|
||||
Str("encoded", encoded).
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue