Version 0.0.1
This commit is contained in:
138
ActivityPub/activity.go
Normal file
138
ActivityPub/activity.go
Normal file
@ -0,0 +1,138 @@
|
||||
package activitypub
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rsa"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/Songmu/go-httpdate"
|
||||
"github.com/yukimochi/Activity-Relay/KeyLoader"
|
||||
"github.com/yukimochi/httpsig"
|
||||
)
|
||||
|
||||
var UA_STRING = "YUKIMOCHI Toot Relay Service (golang net/http; Activity-Relay v0.0.1; " + os.Getenv("RELAY_DOMAIN") + ")"
|
||||
|
||||
func appendSignature(r *http.Request, body *[]byte, KeyID string, pKey *rsa.PrivateKey) error {
|
||||
hash := sha256.New()
|
||||
hash.Write(*body)
|
||||
b := hash.Sum(nil)
|
||||
r.Header.Set("Digest", "SHA-256="+base64.StdEncoding.EncodeToString(b))
|
||||
r.Header.Set("Host", r.Host)
|
||||
|
||||
signer, _, err := httpsig.NewSigner([]httpsig.Algorithm{httpsig.RSA_SHA256}, []string{httpsig.RequestTarget, "Host", "Date", "Digest", "Content-Type"}, httpsig.Signature)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = signer.SignRequest(pKey, KeyID, r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SendActivity : Send ActivityPub Activity.
|
||||
func SendActivity(inboxURL string, KeyID string, refBytes []byte, pKey *rsa.PrivateKey) error {
|
||||
req, _ := http.NewRequest("POST", inboxURL, bytes.NewBuffer(refBytes))
|
||||
req.Header.Set("Content-Type", "application/activity+json, application/ld+json")
|
||||
req.Header.Set("User-Agent", UA_STRING)
|
||||
req.Header.Set("Date", httpdate.Time2Str(time.Now()))
|
||||
appendSignature(req, &refBytes, KeyID, pKey)
|
||||
client := &http.Client{Timeout: time.Duration(5) * time.Second}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println(inboxURL, resp.StatusCode)
|
||||
if resp.StatusCode/100 != 2 {
|
||||
return errors.New(resp.Status)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RetrieveActor : Retrieve Remote actor
|
||||
func RetrieveActor(url string) (*Actor, 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 nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
data, _ := ioutil.ReadAll(resp.Body)
|
||||
var actor Actor
|
||||
err = json.Unmarshal(data, &actor)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &actor, nil
|
||||
}
|
||||
|
||||
// DescribeNestedActivity : Descrive Nested Activity Series
|
||||
func DescribeNestedActivity(nestedActivity interface{}) (*Activity, error) {
|
||||
mappedObject := nestedActivity.(map[string]interface{})
|
||||
|
||||
return &Activity{
|
||||
ID: mappedObject["id"].(string),
|
||||
Type: mappedObject["type"].(string),
|
||||
Actor: mappedObject["actor"].(string),
|
||||
Object: mappedObject["object"],
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GenerateActor : Generate Actor by hostname and publickey
|
||||
func GenerateActor(hostname *url.URL, publickey *rsa.PublicKey) Actor {
|
||||
return Actor{
|
||||
[]string{"https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1"},
|
||||
hostname.String() + "/actor",
|
||||
"Service",
|
||||
"relay",
|
||||
hostname.String() + "/inbox",
|
||||
nil,
|
||||
PublicKey{
|
||||
hostname.String() + "/actor#main-key",
|
||||
hostname.String() + "/actor",
|
||||
keyloader.GeneratePublicKeyPEMString(publickey),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// GenerateWebfingerResource : Generate Webfinger Resource
|
||||
func GenerateWebfingerResource(hostname *url.URL, actor *Actor) WebfingerResource {
|
||||
return WebfingerResource{
|
||||
"acct:" + actor.PreferredUsername + "@" + hostname.Host,
|
||||
[]WebfingerLink{
|
||||
WebfingerLink{
|
||||
"self",
|
||||
"application/activity+json",
|
||||
actor.ID,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// GenerateActivityResponse : Generate Responce Activity to Activity
|
||||
func GenerateActivityResponse(host *url.URL, to *url.URL, responseType string, activity Activity) Activity {
|
||||
return Activity{
|
||||
[]string{"https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1"},
|
||||
host.String() + "/actor#accepts/follows/" + to.Host,
|
||||
host.String() + "/actor",
|
||||
responseType,
|
||||
&activity,
|
||||
nil,
|
||||
nil,
|
||||
}
|
||||
}
|
55
ActivityPub/models.go
Normal file
55
ActivityPub/models.go
Normal file
@ -0,0 +1,55 @@
|
||||
package activitypub
|
||||
|
||||
// PublicKey : Activity Certificate.
|
||||
type PublicKey struct {
|
||||
ID string `json:"id"`
|
||||
Owner string `json:"owner"`
|
||||
PublicKeyPem string `json:"publicKeyPem"`
|
||||
}
|
||||
|
||||
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"`
|
||||
}
|
||||
|
||||
// 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"`
|
||||
}
|
||||
|
||||
// Signature : ActivityPub Header Signature.
|
||||
type Signature struct {
|
||||
Type string `json:"type"`
|
||||
Creator string `json:"creator"`
|
||||
Created string `json:"created"`
|
||||
SignatureValue string `json:"signatureValue"`
|
||||
}
|
||||
|
||||
// WebfingerResource : Webfinger Resource.
|
||||
type WebfingerResource struct {
|
||||
Subject string `json:"subject"`
|
||||
Links []WebfingerLink `json:"links"`
|
||||
}
|
||||
|
||||
// WebfingerLink : Webfinger Link Resource.
|
||||
type WebfingerLink struct {
|
||||
Rel string `json:"rel"`
|
||||
Type string `json:"type"`
|
||||
Href string `json:"href"`
|
||||
}
|
Reference in New Issue
Block a user