Finished Prototype

This commit is contained in:
Hoernschen 2020-10-17 12:13:15 +02:00
parent ea54a27796
commit 6de476260d
30 changed files with 2189 additions and 0 deletions

View file

@ -0,0 +1,117 @@
package database
import (
"database/sql"
"fmt"
_ "github.com/mattn/go-sqlite3"
)
var DB *sql.DB
// TODO: Change DB Structure
func InitDB(filepath string) (err error) {
DB, err = sql.Open("sqlite3", filepath)
if err != nil {
panic(err)
}
if DB == nil {
panic("DB couldn't be initialized")
}
handleError(initObjectTable())
handleError(initCollectionTable())
handleError(initActorTable())
handleError(initUserTable())
return
}
func initObjectTable() (err error) {
statement, err := DB.Prepare(`CREATE TABLE IF NOT EXISTS object (
id TEXT PRIMARY KEY,
type TEXT,
attributedTo TEXT,
content TEXT,
published INTEGER,
toActor TEXT
)`)
if err != nil {
return
}
statement.Exec()
return
}
func initCollectionTable() (err error) {
statement, err := DB.Prepare(`CREATE TABLE IF NOT EXISTS collection (
id TEXT PRIMARY KEY
)`)
if err != nil {
return
}
statement.Exec()
statement, err = DB.Prepare(`CREATE TABLE IF NOT EXISTS collectionObject (
collectionId TEXT,
objectId TEXT,
PRIMARY KEY (collectionId, objectId)
)`)
if err != nil {
return
}
statement.Exec()
return
}
func initActorTable() (err error) {
statement, err := DB.Prepare(`CREATE TABLE IF NOT EXISTS actor (
id TEXT PRIMARY KEY,
type TEXT,
name TEXT,
preferredUsername TEXT,
summary TEXT,
inbox TEXT,
outbox TEXT,
followers TEXT,
following TEXT,
liked TEXT
)`)
if err != nil {
return
}
statement.Exec()
return
}
func initUserTable() (err error) {
statement, err := DB.Prepare(`CREATE TABLE IF NOT EXISTS user (
id TEXT PRIMARY KEY,
password TEXT,
actor TEXT
)`)
if err != nil {
return
}
statement.Exec()
statement, err = DB.Prepare(`CREATE TABLE IF NOT EXISTS session (
token TEXT PRIMARY KEY,
userId TEXT
)`)
if err != nil {
return
}
statement.Exec()
return
}
func handleError(err error) {
if err != nil {
panic(fmt.Sprintf("Could not execute Database Query: %s", err))
}
}

View file

@ -0,0 +1,76 @@
package utils
import (
"crypto/ed25519"
"crypto/rand"
"crypto/sha256"
"encoding/base64"
"fmt"
"log"
"git.nutfactory.org/hoernschen/ActivityPub/config"
)
func CreateToken() (err error, token string) {
b := make([]byte, 8)
_, err = rand.Read(b)
if err != nil {
log.Fatal(err)
return
}
token = fmt.Sprintf("%x", b)
return
}
func CreateUUID() (err error, uuid string) {
b := make([]byte, 16)
_, err = rand.Read(b)
if err != nil {
log.Fatal(err)
return
}
uuid = fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
return
}
// TODO: Check if needed
func Hash(s []byte) (err error, hashString string) {
h := sha256.New()
_, err = h.Write(s)
if nil != err {
return
}
hash := h.Sum(nil)
hashString = base64.StdEncoding.EncodeToString(hash)
return
}
//TODO: Signing Mechanism?
func GenerateKeyPair() (publicKey ed25519.PublicKey, privateKey ed25519.PrivateKey, err error) {
publicKey, privateKey, err = ed25519.GenerateKey(nil)
return
}
func Sign(message []byte) string {
signatureBytes := ed25519.Sign(config.PrivateKey, message)
return base64.RawStdEncoding.EncodeToString(signatureBytes)
}
func SignContent(content []byte) (signatures map[string]map[string]string) {
if !config.Signing {
return
}
signatures = make(map[string]map[string]string)
signatures[config.Homeserver] = make(map[string]string)
signatures[config.Homeserver][config.KeyId] = Sign(content)
return
}
func VerifySignature(publicKey []byte, message []byte, signature string) bool {
signatureBytes, err := base64.RawStdEncoding.DecodeString(signature)
if err != nil {
return false
}
ed25519.Verify(config.PublicKey, message, signatureBytes)
return true
}

23
utils/logger.go Normal file
View file

@ -0,0 +1,23 @@
package utils
import (
"log"
"net/http"
"time"
)
func APILogger(inner http.Handler, name string) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
inner.ServeHTTP(w, r)
log.Printf(
"%s\t%s\t%s\t%s",
r.Method,
r.RequestURI,
name,
time.Since(start),
)
})
}

89
utils/requestChecker.go Normal file
View file

@ -0,0 +1,89 @@
package utils
import (
"bytes"
"errors"
"fmt"
"net/http"
"strings"
"git.nutfactory.org/hoernschen/ActivityPub/config"
)
type ErrorResponse struct {
ErrorCode string `json:"errcode,omitempty"`
ErrorMessage string `json:"error,omitempty"`
RetryTime int `json:"retry_after_ms,omitempty"`
}
func CheckRequest(r *http.Request) (err error) {
if !strings.Contains(r.Header.Get("Content-Type"), "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"") {
err = errors.New("Content Type not JSON")
}
return
}
func GetContentTypeString() string {
return "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""
}
func GetDefaultContext() string {
return "https://www.w3.org/ns/activitystreams"
}
func GenerateProfileUrl(userId string) string {
return fmt.Sprintf("%s://%s/%s/", config.HttpString, config.Homeserver, userId)
}
func GenerateInboxUrl(userId string) string {
return fmt.Sprintf("%s://%s/%s/inbox/", config.HttpString, config.Homeserver, userId)
}
func GenerateOutboxUrl(userId string) string {
return fmt.Sprintf("%s://%s/%s/outbox/", config.HttpString, config.Homeserver, userId)
}
func GenerateFollowersUrl(userId string) string {
return fmt.Sprintf("%s://%s/%s/followers/", config.HttpString, config.Homeserver, userId)
}
func GenerateFollowingUrl(userId string) string {
return fmt.Sprintf("%s://%s/%s/following/", config.HttpString, config.Homeserver, userId)
}
func GenerateLikedUrl(userId string) string {
return fmt.Sprintf("%s://%s/%s/liked/", config.HttpString, config.Homeserver, userId)
}
func GetAccessToken(r *http.Request) (token string, err error) {
token = r.URL.Query().Get("access_token")
if token == "" {
token = r.Header.Get("Authorization")
if token == "" || !strings.Contains(token, "Bearer") {
err = errors.New("Missing Token")
} else {
token = strings.Split(token, " ")[1]
}
}
return
}
func HandleHTTPError(res *http.Response) (err error) {
buf := new(bytes.Buffer)
buf.ReadFrom(res.Body)
err = errors.New(fmt.Sprintf("%s (%s)", buf.String(), res.Status))
return
}
func RemoveDuplicates(array []string) []string {
keys := make(map[string]bool)
list := []string{}
for _, entry := range array {
if _, value := keys[entry]; !value {
keys[entry] = true
list = append(list, entry)
}
}
return list
}

12
utils/router/route.go Normal file
View file

@ -0,0 +1,12 @@
package router
import "net/http"
type Route struct {
Name string
Method string
Pattern string
HandlerFunc http.HandlerFunc
}
type Routes []Route

27
utils/router/router.go Normal file
View file

@ -0,0 +1,27 @@
package router
import (
"net/http"
"git.nutfactory.org/hoernschen/ActivityPub/utils"
"github.com/gorilla/mux"
)
func NewRouter(routes Routes) *mux.Router {
router := mux.NewRouter().StrictSlash(true)
for _, route := range routes {
var handler http.Handler
handler = route.HandlerFunc
handler = utils.APILogger(handler, route.Name)
router.
Methods(route.Method).
Path(route.Pattern).
Name(route.Name).
Handler(handler)
}
return router
}