Move stuff, keep working on authenticated fetch
All checks were successful
/ docker (push) Successful in 4m5s
All checks were successful
/ docker (push) Successful in 4m5s
This commit is contained in:
parent
f8b3a6ff06
commit
e3a97170a9
11 changed files with 81 additions and 39 deletions
|
@ -1,4 +1,4 @@
|
||||||
package types
|
package activitypub
|
||||||
|
|
||||||
var BaseLdContext = []any{
|
var BaseLdContext = []any{
|
||||||
"https://www.w3.org/ns/activitystreams",
|
"https://www.w3.org/ns/activitystreams",
|
|
@ -4,13 +4,12 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"git.mstar.dev/mstar/goutils/other"
|
||||||
"git.mstar.dev/mstar/goutils/sliceutils"
|
"git.mstar.dev/mstar/goutils/sliceutils"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
apshared "git.mstar.dev/mstar/linstrom/activitypub/shared"
|
|
||||||
"git.mstar.dev/mstar/linstrom/config"
|
"git.mstar.dev/mstar/linstrom/config"
|
||||||
"git.mstar.dev/mstar/linstrom/storage-new/dbgen"
|
"git.mstar.dev/mstar/linstrom/storage-new/dbgen"
|
||||||
webshared "git.mstar.dev/mstar/linstrom/web/shared"
|
webshared "git.mstar.dev/mstar/linstrom/web/shared"
|
||||||
|
@ -47,18 +46,18 @@ func ImportRemoteAccount(targetName string) (string, error) {
|
||||||
RestrictedFollow *bool `json:"manuallyApprovesFollowers"`
|
RestrictedFollow *bool `json:"manuallyApprovesFollowers"`
|
||||||
}
|
}
|
||||||
// Get the target user's link first
|
// Get the target user's link first
|
||||||
webfinger, err := apshared.GetAccountWebfinger(targetName)
|
webfinger, err := GetAccountWebfinger(targetName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", other.Error("activitypub", "webfinger request failed", err)
|
||||||
}
|
}
|
||||||
selfLinks := sliceutils.Filter(webfinger.Links, func(t apshared.LinkData) bool {
|
selfLinks := sliceutils.Filter(webfinger.Links, func(t LinkData) bool {
|
||||||
return t.Relation == "self"
|
return t.Relation == "self"
|
||||||
})
|
})
|
||||||
if len(selfLinks) == 0 {
|
if len(selfLinks) == 0 {
|
||||||
return "", errors.New("No self link")
|
return "", errors.New("No self link")
|
||||||
}
|
}
|
||||||
APLink := selfLinks[0]
|
APLink := selfLinks[0]
|
||||||
req, err := http.NewRequest("GET", *APLink.Href, nil)
|
req, err := webshared.NewRequest("GET", *APLink.Href, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -86,12 +85,16 @@ func ImportRemoteAccount(targetName string) (string, error) {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
defer response.Body.Close()
|
defer response.Body.Close()
|
||||||
|
body, _ := io.ReadAll(response.Body)
|
||||||
|
log.Debug().
|
||||||
|
Int("status", response.StatusCode).
|
||||||
|
Bytes("body", body).
|
||||||
|
Any("headers", response.Header).
|
||||||
|
Msg("Response information")
|
||||||
if response.StatusCode != 200 {
|
if response.StatusCode != 200 {
|
||||||
return "", errors.New("Bad status")
|
return "", errors.New("Bad status")
|
||||||
}
|
}
|
||||||
var data InboundUser
|
var data InboundUser
|
||||||
body, _ := io.ReadAll(response.Body)
|
|
||||||
log.Info().Bytes("body", body).Msg("Body from request")
|
|
||||||
err = json.Unmarshal(body, &data)
|
err = json.Unmarshal(body, &data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package apshared
|
package activitypub
|
||||||
|
|
||||||
import "strings"
|
import "strings"
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
package apshared
|
package activitypub
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
webshared "git.mstar.dev/mstar/linstrom/web/shared"
|
webshared "git.mstar.dev/mstar/linstrom/web/shared"
|
||||||
)
|
)
|
||||||
|
@ -44,7 +43,7 @@ func GetAccountWebfinger(fullHandle string) (*WebfingerData, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
webfingerRequest, err := http.NewRequest(
|
webfingerRequest, err := webshared.NewRequest(
|
||||||
// Webfinger requests are GET
|
// Webfinger requests are GET
|
||||||
"GET",
|
"GET",
|
||||||
// The webfinger url is located at <domain>/.well-known/webfinger
|
// The webfinger url is located at <domain>/.well-known/webfinger
|
|
@ -207,7 +207,7 @@ var defaultConfig Config = Config{
|
||||||
// Example: "git.mstar.dev" (with subdomain = "git" and domain = "mstar.dev")
|
// Example: "git.mstar.dev" (with subdomain = "git" and domain = "mstar.dev")
|
||||||
func (gc *ConfigGeneral) GetFullDomain() string {
|
func (gc *ConfigGeneral) GetFullDomain() string {
|
||||||
if gc.Subdomain != nil {
|
if gc.Subdomain != nil {
|
||||||
return *gc.Subdomain + gc.Domain
|
return *gc.Subdomain + "." + gc.Domain
|
||||||
}
|
}
|
||||||
return gc.Domain
|
return gc.Domain
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ const (
|
||||||
ServerSoftwareWafrn = ServerSoftwareType("Wafrn")
|
ServerSoftwareWafrn = ServerSoftwareType("Wafrn")
|
||||||
// Linstrom with no known forks
|
// Linstrom with no known forks
|
||||||
ServerSoftwareLinstrom = ServerSoftwareType("Linstrom")
|
ServerSoftwareLinstrom = ServerSoftwareType("Linstrom")
|
||||||
|
ServerSoftwareUnknown = ServerSoftwareType("Unknown")
|
||||||
)
|
)
|
||||||
|
|
||||||
// A list of all known server software systems
|
// A list of all known server software systems
|
||||||
|
@ -27,6 +28,7 @@ var AllServerSoftwareTypes = []ServerSoftwareType{
|
||||||
ServerSoftwarePlemora,
|
ServerSoftwarePlemora,
|
||||||
ServerSoftwareWafrn,
|
ServerSoftwareWafrn,
|
||||||
ServerSoftwareLinstrom,
|
ServerSoftwareLinstrom,
|
||||||
|
ServerSoftwareUnknown,
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ServerSoftwareType) Value() (driver.Value, error) {
|
func (r *ServerSoftwareType) Value() (driver.Value, error) {
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
ap "git.mstar.dev/mstar/linstrom/activitypub/shared"
|
"git.mstar.dev/mstar/linstrom/activitypub"
|
||||||
"git.mstar.dev/mstar/linstrom/shared"
|
"git.mstar.dev/mstar/linstrom/shared"
|
||||||
"github.com/go-webauthn/webauthn/webauthn"
|
"github.com/go-webauthn/webauthn/webauthn"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
@ -121,7 +121,7 @@ func (s *Storage) FindAccountByFullHandle(handle string) (*Account, error) {
|
||||||
|
|
||||||
// Failed to find in cache, go the slow route of hitting the db
|
// Failed to find in cache, go the slow route of hitting the db
|
||||||
log.Debug().Str("account-handle", handle).Msg("Didn't hit account in cache, going to db")
|
log.Debug().Str("account-handle", handle).Msg("Didn't hit account in cache, going to db")
|
||||||
name, server, err := ap.SplitFullHandle(handle)
|
name, server, err := activitypub.SplitFullHandle(handle)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn().Err(err).Str("account-handle", handle).Msg("Failed to split up account handle")
|
log.Warn().Err(err).Str("account-handle", handle).Msg("Failed to split up account handle")
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
"git.mstar.dev/mstar/goutils/sliceutils"
|
"git.mstar.dev/mstar/goutils/sliceutils"
|
||||||
"github.com/rs/zerolog/hlog"
|
"github.com/rs/zerolog/hlog"
|
||||||
|
|
||||||
"git.mstar.dev/mstar/linstrom/activitypub/shared/types"
|
"git.mstar.dev/mstar/linstrom/activitypub"
|
||||||
"git.mstar.dev/mstar/linstrom/config"
|
"git.mstar.dev/mstar/linstrom/config"
|
||||||
"git.mstar.dev/mstar/linstrom/storage-new"
|
"git.mstar.dev/mstar/linstrom/storage-new"
|
||||||
"git.mstar.dev/mstar/linstrom/storage-new/dbgen"
|
"git.mstar.dev/mstar/linstrom/storage-new/dbgen"
|
||||||
|
@ -53,6 +53,7 @@ func users(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
log := hlog.FromRequest(r)
|
log := hlog.FromRequest(r)
|
||||||
userId := r.PathValue("id")
|
userId := r.PathValue("id")
|
||||||
|
log.Debug().Any("headers", r.Header).Msg("request headers")
|
||||||
user, err := dbgen.User.Where(dbgen.User.ID.Eq(userId)).
|
user, err := dbgen.User.Where(dbgen.User.ID.Eq(userId)).
|
||||||
Preload(dbgen.User.Icon).Preload(dbgen.User.Banner).
|
Preload(dbgen.User.Icon).Preload(dbgen.User.Banner).
|
||||||
Preload(dbgen.User.BeingTypes).
|
Preload(dbgen.User.BeingTypes).
|
||||||
|
@ -75,7 +76,7 @@ func users(w http.ResponseWriter, r *http.Request) {
|
||||||
keyBytes = keyBytesToPem(user.PublicKeyRsa)
|
keyBytes = keyBytesToPem(user.PublicKeyRsa)
|
||||||
}
|
}
|
||||||
data := Outbound{
|
data := Outbound{
|
||||||
Context: types.BaseLdContext,
|
Context: activitypub.BaseLdContext,
|
||||||
Id: apUrl,
|
Id: apUrl,
|
||||||
Type: "Person",
|
Type: "Person",
|
||||||
PreferredUsername: user.Username,
|
PreferredUsername: user.Username,
|
||||||
|
@ -136,7 +137,12 @@ func userInbox(w http.ResponseWriter, r *http.Request) {
|
||||||
log := hlog.FromRequest(r)
|
log := hlog.FromRequest(r)
|
||||||
userId := r.PathValue("id")
|
userId := r.PathValue("id")
|
||||||
data, err := io.ReadAll(r.Body)
|
data, err := io.ReadAll(r.Body)
|
||||||
log.Info().Err(err).Str("userId", userId).Bytes("body", data).Msg("Inbox message")
|
log.Info().
|
||||||
|
Err(err).
|
||||||
|
Str("userId", userId).
|
||||||
|
Bytes("body", data).
|
||||||
|
Any("headers", r.Header).
|
||||||
|
Msg("Inbox message")
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
|
|
||||||
func userIdToApUrl(id string) string {
|
func userIdToApUrl(id string) string {
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
"%s/api/ap/users/%s",
|
"%s/api/activitypub/user/%s",
|
||||||
config.GlobalConfig.General.GetFullPublicUrl(),
|
config.GlobalConfig.General.GetFullPublicUrl(),
|
||||||
id,
|
id,
|
||||||
)
|
)
|
||||||
|
|
|
@ -2,17 +2,20 @@ package webshared
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.mstar.dev/mstar/goutils/maputils"
|
"git.mstar.dev/mstar/goutils/maputils"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
"git.mstar.dev/mstar/linstrom/config"
|
"git.mstar.dev/mstar/linstrom/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
// No init needed, zero value is good
|
// No init needed, zero value is good
|
||||||
|
|
||||||
var RequestClient http.Client
|
var RequestClient = http.Client{}
|
||||||
|
|
||||||
const xRandomHeader = "X-Auth-Random"
|
const xRandomHeader = "X-Auth-Random"
|
||||||
|
|
||||||
|
@ -36,35 +39,40 @@ func SignRequest(r *http.Request, keyId string, privateKeyBytes, postBody []byte
|
||||||
host = hostString
|
host = hostString
|
||||||
} else {
|
} else {
|
||||||
host = config.GlobalConfig.General.GetFullDomain()
|
host = config.GlobalConfig.General.GetFullDomain()
|
||||||
headers.Set("Date", host)
|
headers.Set("Host", host)
|
||||||
}
|
}
|
||||||
applyBodyHash(headers, postBody)
|
applyBodyHash(headers, postBody)
|
||||||
mappedHeaders := maputils.MapSameKeys(headers, func(k string, v []string) string {
|
mappedHeaders := maputils.MapNewKeys(headers, func(k string, v []string) (string, string) {
|
||||||
if len(v) > 0 {
|
if len(v) > 0 {
|
||||||
return v[0]
|
return strings.ToLower(k), v[0]
|
||||||
} else {
|
} else {
|
||||||
return ""
|
return strings.ToLower(k), ""
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
var signedString string
|
var signedString string
|
||||||
|
var usedHeaders []string
|
||||||
if config.GlobalConfig.Experimental.UseEd25519Keys {
|
if config.GlobalConfig.Experimental.UseEd25519Keys {
|
||||||
tmp, err := CreateSignatureED(method, r.URL.RawPath, mappedHeaders, privateKeyBytes)
|
tmp, tmp2, err := CreateSignatureED(method, r.URL.Path, mappedHeaders, privateKeyBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
signedString = tmp
|
signedString = tmp
|
||||||
|
usedHeaders = tmp2
|
||||||
} else {
|
} else {
|
||||||
tmp, err := CreateSignatureRSA(method, r.URL.RawPath, mappedHeaders, privateKeyBytes)
|
tmp, tmp2, err := CreateSignatureRSA(method, r.URL.Path, mappedHeaders, privateKeyBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
signedString = tmp
|
signedString = tmp
|
||||||
|
usedHeaders = tmp2
|
||||||
}
|
}
|
||||||
|
log.Debug().Str("string-to-sign", signedString).Any("headers", mappedHeaders).Send()
|
||||||
signature := CreateSignatureHeaderContent(
|
signature := CreateSignatureHeaderContent(
|
||||||
keyId,
|
keyId,
|
||||||
signedString,
|
signedString,
|
||||||
maputils.KeysFromMap(mappedHeaders)...,
|
usedHeaders...,
|
||||||
)
|
)
|
||||||
|
log.Debug().Str("signature-header", signature).Send()
|
||||||
headers.Set("Signature", signature)
|
headers.Set("Signature", signature)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -77,3 +85,17 @@ func applyBodyHash(headers http.Header, body []byte) error {
|
||||||
headers.Set("Digest", string(hash[:]))
|
headers.Set("Digest", string(hash[:]))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewRequest(method string, url string, body io.Reader) (*http.Request, error) {
|
||||||
|
req, err := http.NewRequest(method, url, body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
req.Header.Add(
|
||||||
|
"User-Agent",
|
||||||
|
"Linstrom v0.0.0-pre-alpha ("+config.GlobalConfig.General.GetFullDomain()+")",
|
||||||
|
)
|
||||||
|
req.Header.Add("Date", time.Now().Format(time.RFC1123))
|
||||||
|
req.Header.Add("Host", config.GlobalConfig.General.GetFullDomain())
|
||||||
|
return req, nil
|
||||||
|
}
|
||||||
|
|
|
@ -4,6 +4,9 @@ import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
|
"git.mstar.dev/mstar/linstrom/config"
|
||||||
"git.mstar.dev/mstar/linstrom/shared"
|
"git.mstar.dev/mstar/linstrom/shared"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -15,10 +18,10 @@ func CreateSignatureRSA(
|
||||||
target string,
|
target string,
|
||||||
headers map[string]string,
|
headers map[string]string,
|
||||||
privateKeyBytes []byte,
|
privateKeyBytes []byte,
|
||||||
) (string, error) {
|
) (string, []string, error) {
|
||||||
message := genPreSignatureString(method, target, headers)
|
message, usedHeaders := genPreSignatureString(method, target, headers)
|
||||||
signed, err := shared.Sign(message, privateKeyBytes, true)
|
signed, err := shared.Sign(message, privateKeyBytes, true)
|
||||||
return base64.StdEncoding.EncodeToString(signed), err
|
return base64.StdEncoding.EncodeToString(signed), usedHeaders, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate the signed string of the headers, method and target
|
// Generate the signed string of the headers, method and target
|
||||||
|
@ -29,24 +32,29 @@ func CreateSignatureED(
|
||||||
target string,
|
target string,
|
||||||
headers map[string]string,
|
headers map[string]string,
|
||||||
privateKeyBytes []byte,
|
privateKeyBytes []byte,
|
||||||
) (string, error) {
|
) (string, []string, error) {
|
||||||
message := genPreSignatureString(method, target, headers)
|
message, usedHeaders := genPreSignatureString(method, target, headers)
|
||||||
signed, err := shared.Sign(message, privateKeyBytes, false)
|
signed, err := shared.Sign(message, privateKeyBytes, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", nil, err
|
||||||
}
|
}
|
||||||
return base64.StdEncoding.EncodeToString(signed), nil
|
return base64.StdEncoding.EncodeToString(signed), usedHeaders, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func genPreSignatureString(method, target string, headers map[string]string) string {
|
func genPreSignatureString(method, target string, headers map[string]string) (string, []string) {
|
||||||
dataBuilder := strings.Builder{}
|
dataBuilder := strings.Builder{}
|
||||||
dataBuilder.WriteString("(request-target) ")
|
dataBuilder.WriteString("(request-target): ")
|
||||||
dataBuilder.WriteString(strings.ToLower(method) + " ")
|
dataBuilder.WriteString(strings.ToLower(method) + " ")
|
||||||
dataBuilder.WriteString(target + "\n")
|
dataBuilder.WriteString(target + "\n")
|
||||||
|
dataBuilder.WriteString("algorithm: rsa-sha256\n")
|
||||||
|
usedHeaders := []string{"(request-target)", "algorithm"}
|
||||||
for k, v := range headers {
|
for k, v := range headers {
|
||||||
dataBuilder.WriteString(k + ": " + v + "\n")
|
dataBuilder.WriteString(k + ": " + v + "\n")
|
||||||
|
usedHeaders = append(usedHeaders, k)
|
||||||
}
|
}
|
||||||
return dataBuilder.String()
|
tmp := dataBuilder.String()
|
||||||
|
log.Debug().Str("Raw signature string", tmp).Send()
|
||||||
|
return tmp, usedHeaders
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate the content of the "Signature" header based on
|
// Generate the content of the "Signature" header based on
|
||||||
|
@ -55,6 +63,8 @@ func genPreSignatureString(method, target string, headers map[string]string) str
|
||||||
func CreateSignatureHeaderContent(userId string, hash string, headerNames ...string) string {
|
func CreateSignatureHeaderContent(userId string, hash string, headerNames ...string) string {
|
||||||
builder := strings.Builder{}
|
builder := strings.Builder{}
|
||||||
builder.WriteString("keyId=\"")
|
builder.WriteString("keyId=\"")
|
||||||
|
builder.WriteString(config.GlobalConfig.General.GetFullPublicUrl())
|
||||||
|
builder.WriteString("/api/activitypub/user/")
|
||||||
builder.WriteString(userId)
|
builder.WriteString(userId)
|
||||||
builder.WriteString("\",headers=\"")
|
builder.WriteString("\",headers=\"")
|
||||||
for i, header := range headerNames {
|
for i, header := range headerNames {
|
||||||
|
@ -63,7 +73,7 @@ func CreateSignatureHeaderContent(userId string, hash string, headerNames ...str
|
||||||
builder.WriteRune(' ')
|
builder.WriteRune(' ')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
builder.WriteString("\",signature=\"")
|
builder.WriteString("\",algorithm=\"rsa-sha256\",signature=\"")
|
||||||
builder.WriteString(hash)
|
builder.WriteString(hash)
|
||||||
builder.WriteRune('"')
|
builder.WriteRune('"')
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue