mirror of https://github.com/jlelse/GoBlog
Automatic ActivityPub key generation, doesn't need config anymore
This commit is contained in:
parent
eeba1967e1
commit
e62e4f32d6
|
@ -1,6 +1,8 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
|
@ -11,7 +13,6 @@ import (
|
|||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -54,15 +55,7 @@ func (a *goBlog) initActivityPub() error {
|
|||
a.webfingerAccts[a.apIri(blog)] = acct
|
||||
}
|
||||
// Read key and prepare signing
|
||||
pkfile, err := os.ReadFile(a.cfg.ActivityPub.KeyPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
privateKeyDecoded, _ := pem.Decode(pkfile)
|
||||
if privateKeyDecoded == nil {
|
||||
return errors.New("failed to decode private key")
|
||||
}
|
||||
a.apPrivateKey, err = x509.ParsePKCS1PrivateKey(privateKeyDecoded.Bytes)
|
||||
err := a.loadActivityPubPrivateKey()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -422,3 +415,39 @@ func (a *goBlog) apIri(b *configBlog) string {
|
|||
func apRequestIsSuccess(code int) bool {
|
||||
return code == http.StatusOK || code == http.StatusCreated || code == http.StatusAccepted || code == http.StatusNoContent
|
||||
}
|
||||
|
||||
// Load or generate key for ActivityPub communication
|
||||
func (a *goBlog) loadActivityPubPrivateKey() error {
|
||||
// Check if already loaded
|
||||
if a.apPrivateKey != nil {
|
||||
return nil
|
||||
}
|
||||
// Check if already generated
|
||||
if keyData, err := a.db.retrievePersistentCache("activitypub_key"); err == nil && keyData != nil {
|
||||
privateKeyDecoded, _ := pem.Decode(keyData)
|
||||
if privateKeyDecoded == nil {
|
||||
log.Println("failed to decode cached private key")
|
||||
// continue
|
||||
} else {
|
||||
key, err := x509.ParsePKCS1PrivateKey(privateKeyDecoded.Bytes)
|
||||
if err == nil && key != nil {
|
||||
a.apPrivateKey = key
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
// Generate and cache key
|
||||
key, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
encodedKey := x509.MarshalPKCS1PrivateKey(key)
|
||||
pemEncoded := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: encodedKey})
|
||||
err = a.db.cachePersistently("activitypub_key", pemEncoded)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.apPrivateKey = key
|
||||
// Return key
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func Test_loadActivityPubPrivateKey(t *testing.T) {
|
||||
|
||||
app := &goBlog{
|
||||
cfg: &config{
|
||||
Db: &configDb{
|
||||
File: filepath.Join(t.TempDir(), "test.db"),
|
||||
},
|
||||
},
|
||||
}
|
||||
_ = app.initDatabase(false)
|
||||
|
||||
// Generate
|
||||
err := app.loadActivityPubPrivateKey()
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.NotNil(t, app.apPrivateKey)
|
||||
|
||||
oldEncodedKey := x509.MarshalPKCS1PrivateKey(app.apPrivateKey)
|
||||
oldPemEncoded := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: oldEncodedKey})
|
||||
|
||||
// Reset and reload
|
||||
err = app.loadActivityPubPrivateKey()
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.NotNil(t, app.apPrivateKey)
|
||||
|
||||
newEncodedKey := x509.MarshalPKCS1PrivateKey(app.apPrivateKey)
|
||||
newPemEncoded := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: newEncodedKey})
|
||||
|
||||
assert.Equal(t, string(oldPemEncoded), string(newPemEncoded))
|
||||
|
||||
}
|
|
@ -232,7 +232,6 @@ type configRegexRedirect struct {
|
|||
|
||||
type configActivityPub struct {
|
||||
Enabled bool `mapstructure:"enabled"`
|
||||
KeyPath string `mapstructure:"keyPath"`
|
||||
TagsTaxonomies []string `mapstructure:"tagsTaxonomies"`
|
||||
}
|
||||
|
||||
|
@ -288,7 +287,6 @@ func (a *goBlog) initConfig() error {
|
|||
viper.SetDefault("micropub.photoParam", "images")
|
||||
viper.SetDefault("micropub.photoDescriptionParam", "imagealts")
|
||||
viper.SetDefault("micropub.locationParam", "location")
|
||||
viper.SetDefault("activityPub.keyPath", "data/private.pem")
|
||||
viper.SetDefault("activityPub.tagsTaxonomies", []string{"tags"})
|
||||
// Unmarshal config
|
||||
a.cfg = &config{}
|
||||
|
|
|
@ -69,6 +69,8 @@ hooks:
|
|||
# ActivityPub
|
||||
activityPub:
|
||||
enabled: true # Enable ActivityPub
|
||||
tagsTaxonomies: # Post taxonomies to use as "Hashtags"
|
||||
- tags
|
||||
|
||||
# Webmention
|
||||
webmention:
|
||||
|
|
Loading…
Reference in New Issue