166 lines
4.1 KiB
Go
166 lines
4.1 KiB
Go
package activitypub
|
|
|
|
import (
|
|
"crypto/rsa"
|
|
"encoding/json"
|
|
"errors"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"net/url"
|
|
|
|
"github.com/satori/go.uuid"
|
|
"github.com/yukimochi/Activity-Relay/KeyLoader"
|
|
)
|
|
|
|
// PublicKey : Activity Certificate.
|
|
type PublicKey struct {
|
|
ID string `json:"id"`
|
|
Owner string `json:"owner"`
|
|
PublicKeyPem string `json:"publicKeyPem"`
|
|
}
|
|
|
|
//Endpoints : Contains SharedInbox address.
|
|
type Endpoints struct {
|
|
SharedInbox string `json:"sharedInbox"`
|
|
}
|
|
|
|
// Actor : ActivityPub Actor.
|
|
type Actor struct {
|
|
Context interface{} `json:"@context"`
|
|
ID string `json:"id"`
|
|
Type string `json:"type"`
|
|
PreferredUsername string `json:"preferredUsername"`
|
|
Inbox string `json:"inbox"`
|
|
Endpoints *Endpoints `json:"endpoints"`
|
|
PublicKey PublicKey `json:"publicKey"`
|
|
}
|
|
|
|
func (a *Actor) GenerateSelfKey(hostname *url.URL, publickey *rsa.PublicKey) {
|
|
a.Context = []string{"https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1"}
|
|
a.ID = hostname.String() + "/actor"
|
|
a.Type = "Service"
|
|
a.PreferredUsername = "relay"
|
|
a.Inbox = hostname.String() + "/inbox"
|
|
a.PublicKey = PublicKey{
|
|
hostname.String() + "/actor#main-key",
|
|
hostname.String() + "/actor",
|
|
keyloader.GeneratePublicKeyPEMString(publickey),
|
|
}
|
|
}
|
|
|
|
func (a *Actor) RetrieveRemoteActor(url string) error {
|
|
req, _ := http.NewRequest("GET", url, nil)
|
|
req.Header.Set("Accept", "application/activity+json, application/ld+json")
|
|
req.Header.Set("User-Agent", UA_STRING)
|
|
client := new(http.Client)
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
data, _ := ioutil.ReadAll(resp.Body)
|
|
err = json.Unmarshal(data, &a)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Activity : ActivityPub Activity.
|
|
type Activity struct {
|
|
Context interface{} `json:"@context"`
|
|
ID string `json:"id"`
|
|
Actor string `json:"actor"`
|
|
Type string `json:"type"`
|
|
Object interface{} `json:"object"`
|
|
To []string `json:"to"`
|
|
Cc []string `json:"cc"`
|
|
}
|
|
|
|
func (a *Activity) GenerateResponse(host *url.URL, responseType string) Activity {
|
|
return Activity{
|
|
[]string{"https://www.w3.org/ns/activitystreams"},
|
|
host.String() + "/activities/" + uuid.NewV4().String(),
|
|
host.String() + "/actor",
|
|
responseType,
|
|
&a,
|
|
nil,
|
|
nil,
|
|
}
|
|
}
|
|
|
|
func (a *Activity) GenerateAnnounce(host *url.URL) Activity {
|
|
return Activity{
|
|
[]string{"https://www.w3.org/ns/activitystreams"},
|
|
host.String() + "/activities/" + uuid.NewV4().String(),
|
|
host.String() + "/actor",
|
|
"Announce",
|
|
a.ID,
|
|
[]string{host.String() + "/actor/followers"},
|
|
nil,
|
|
}
|
|
}
|
|
|
|
func (a *Activity) NestedActivity() (*Activity, error) {
|
|
mappedObject := a.Object.(map[string]interface{})
|
|
if id, ok := mappedObject["id"].(string); ok {
|
|
if nestedType, ok := mappedObject["type"].(string); ok {
|
|
actor, ok := mappedObject["actor"].(string)
|
|
if !ok {
|
|
actor = ""
|
|
}
|
|
switch object := mappedObject["object"].(type) {
|
|
case string:
|
|
return &Activity{
|
|
ID: id,
|
|
Type: nestedType,
|
|
Actor: actor,
|
|
Object: object,
|
|
}, nil
|
|
default:
|
|
return &Activity{
|
|
ID: id,
|
|
Type: nestedType,
|
|
Actor: actor,
|
|
Object: mappedObject["object"],
|
|
}, nil
|
|
}
|
|
}
|
|
return nil, errors.New("Can't assart type")
|
|
}
|
|
return nil, errors.New("Can't assart id")
|
|
}
|
|
|
|
// Signature : ActivityPub Header Signature.
|
|
type Signature struct {
|
|
Type string `json:"type"`
|
|
Creator string `json:"creator"`
|
|
Created string `json:"created"`
|
|
SignatureValue string `json:"signatureValue"`
|
|
}
|
|
|
|
// WebfingerLink : Webfinger Link Resource.
|
|
type WebfingerLink struct {
|
|
Rel string `json:"rel"`
|
|
Type string `json:"type"`
|
|
Href string `json:"href"`
|
|
}
|
|
|
|
// WebfingerResource : Webfinger Resource.
|
|
type WebfingerResource struct {
|
|
Subject string `json:"subject"`
|
|
Links []WebfingerLink `json:"links"`
|
|
}
|
|
|
|
func (a *WebfingerResource) GenerateFromActor(hostname *url.URL, actor *Actor) {
|
|
a.Subject = "acct:" + actor.PreferredUsername + "@" + hostname.Host
|
|
a.Links = []WebfingerLink{
|
|
WebfingerLink{
|
|
"self",
|
|
"application/activity+json",
|
|
actor.ID,
|
|
},
|
|
}
|
|
}
|