Merge branch 'main' of gitlab.com:mstarongitlab/linstrom
also delete server-old with all its problems
This commit is contained in:
commit
d99efca667
47 changed files with 2200 additions and 694 deletions
85
ap/getRemoteUser.go
Normal file
85
ap/getRemoteUser.go
Normal file
|
@ -0,0 +1,85 @@
|
|||
package ap
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"gitlab.com/mstarongitlab/goap"
|
||||
)
|
||||
|
||||
var ErrNoApUrl = errors.New("no Activitypub url in webfinger")
|
||||
|
||||
func GetRemoteUser(fullHandle string) (goap.BaseApChain, error) {
|
||||
webfinger, err := GetAccountWebfinger(fullHandle)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
apUrl := ""
|
||||
for _, link := range webfinger.Links {
|
||||
if link.Relation == "self" {
|
||||
apUrl = *link.Href
|
||||
}
|
||||
}
|
||||
if apUrl == "" {
|
||||
return nil, ErrNoApUrl
|
||||
}
|
||||
apRequest, err := http.NewRequest("GET", apUrl, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
apRequest.Header.Add("Accept", "application/activity+json,application/ld+json,application/json")
|
||||
client := http.Client{Timeout: time.Second * 30}
|
||||
res, err := client.Do(apRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if res.StatusCode != 200 {
|
||||
return nil, fmt.Errorf("bad status code: %d", res.StatusCode)
|
||||
}
|
||||
body, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
apObject, _ := goap.Unmarshal(body, nil, nil)
|
||||
// Check if Id exists
|
||||
if _, ok := goap.FindAttribute[*goap.UDIdData](apObject); !ok {
|
||||
return nil, fmt.Errorf("missing attribute for account: Id")
|
||||
}
|
||||
// Check that it has the correct object type for an account
|
||||
if objTypePtr, ok := goap.FindAttribute[*goap.UDTypeData](apObject); !ok {
|
||||
return nil, fmt.Errorf("missing attribute for account: Type")
|
||||
} else if objType := *objTypePtr; objType.Type != goap.KEY_ACTIVITYSTREAMS_ACTOR {
|
||||
return nil, fmt.Errorf("wrong ap object type: %s", objType.Type)
|
||||
}
|
||||
// And finally check for inbox
|
||||
if _, ok := goap.FindAttribute[*goap.W3InboxData](apObject); !ok {
|
||||
return nil, fmt.Errorf("missing attribute for account: Inbox")
|
||||
}
|
||||
return apObject, nil
|
||||
}
|
||||
|
||||
func GetRemoteObject(target string) (goap.BaseApChain, error) {
|
||||
apRequest, err := http.NewRequest("GET", target, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
apRequest.Header.Add("Accept", "application/activity+json,application/ld+json,application/json")
|
||||
client := http.Client{Timeout: time.Second * 30}
|
||||
res, err := client.Do(apRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if res.StatusCode != 200 {
|
||||
return nil, fmt.Errorf("bad status code: %d", res.StatusCode)
|
||||
}
|
||||
body, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
apObject, _ := goap.Unmarshal(body, nil, nil)
|
||||
return apObject, nil
|
||||
}
|
19
ap/util.go
Normal file
19
ap/util.go
Normal file
|
@ -0,0 +1,19 @@
|
|||
package ap
|
||||
|
||||
import "strings"
|
||||
|
||||
type InvalidFullHandleError struct {
|
||||
Raw string
|
||||
}
|
||||
|
||||
func (i InvalidFullHandleError) Error() string {
|
||||
return "Invalid full handle"
|
||||
}
|
||||
|
||||
func SplitFullHandle(full string) (string, string, error) {
|
||||
splits := strings.Split(strings.TrimPrefix(full, "@"), "@")
|
||||
if len(splits) != 2 {
|
||||
return "", "", InvalidFullHandleError{}
|
||||
}
|
||||
return splits[0], splits[1], nil
|
||||
}
|
87
ap/webfinger.go
Normal file
87
ap/webfinger.go
Normal file
|
@ -0,0 +1,87 @@
|
|||
package ap
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Data returned from a webfinger response (and also sent when asked for an account via webfinger)
|
||||
type WebfingerData struct {
|
||||
// What this webfinger data refers to. Accounts are usually `acct:username@host`
|
||||
Subject string `json:"subject"`
|
||||
// List of links related to the account
|
||||
Links []struct {
|
||||
// What type of link this is
|
||||
// - `self` refers to the activitypub object and has Type and Href set
|
||||
// - `http://webfinger.net/rel/profile-page` refers to the public webpage of the account and has Type and Href set
|
||||
// - `http://ostatus.org/schema/1.0/subscribe` provides a template for subscribing/following the account. Has Template set
|
||||
// Template will contain a `{uri}` part with which to replace idk yet
|
||||
Relation string `json:"rel"`
|
||||
// The content type of the url
|
||||
Type *string `json:"type"`
|
||||
// The url
|
||||
Href *string `json:"href"`
|
||||
// Template to use for something
|
||||
Template *string `json:"template"`
|
||||
} `json:"links"`
|
||||
}
|
||||
|
||||
var ErrAccountNotFound = errors.New("account not found")
|
||||
var ErrRemoteServerFailed = errors.New("remote server errored out")
|
||||
|
||||
// Get the webfinger data for a given full account handle (like @bob@example.com or bob@example.com)
|
||||
func GetAccountWebfinger(fullHandle string) (*WebfingerData, error) {
|
||||
// First get the handle and server domain from the full handle (and ensure it's a correctly formatted one)
|
||||
handle, server, err := SplitFullHandle(fullHandle)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
webfingerRequest, err := http.NewRequest(
|
||||
// Webfinger requests are GET
|
||||
"GET",
|
||||
// The webfinger url is located at <domain>/.well-known/webfinger
|
||||
// The url parameter `resource` tells the remote server what data we want, should always be an account
|
||||
// The prefix `acct:<full-handle>` (where full-handle is in the form of bob@example.com)
|
||||
// tells the remote server that we want the account data of the given account handle
|
||||
"https://"+server+"/.well-known/webfinger?resource=acct:"+handle+"@"+server,
|
||||
// No request body since it's a get request and we only need the url parameter
|
||||
nil,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Make a http client with a timeout limit of 30 seconds
|
||||
client := http.Client{Timeout: time.Second * 30}
|
||||
// Then send the request
|
||||
result, err := client.Do(webfingerRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Code 404 indicates that the account doesn't exist
|
||||
if result.StatusCode == 404 {
|
||||
return nil, ErrAccountNotFound
|
||||
} else if result.StatusCode != 200 {
|
||||
// And anything other than 200 or 404 is an error for now
|
||||
// TODO: Add information gathering here to figure out what the remote server's problem is
|
||||
return nil, ErrRemoteServerFailed
|
||||
}
|
||||
|
||||
// Get the body data from the response
|
||||
data, err := io.ReadAll(result.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Then try and parse it into webfinger data
|
||||
webfinger := WebfingerData{}
|
||||
err = json.Unmarshal(data, &webfinger)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &webfinger, nil
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue