Initial commit
This commit is contained in:
commit
7c48322d3a
|
@ -0,0 +1,14 @@
|
||||||
|
# MastoGem : a Mastodon proxy for Gemini
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
```
|
||||||
|
$ go build
|
||||||
|
```
|
||||||
|
|
||||||
|
## Generate key and certificate
|
||||||
|
|
||||||
|
```
|
||||||
|
$ openssl genrsa -out key.rsa 4096
|
||||||
|
$ openssl req -x509 -key key.rsa -out cert.pem -days 365 -subj "/CN=localhost"
|
||||||
|
```
|
|
@ -0,0 +1,136 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"fmt"
|
||||||
|
"mime"
|
||||||
|
"encoding/json"
|
||||||
|
"io/ioutil"
|
||||||
|
"strings"
|
||||||
|
"html"
|
||||||
|
"regexp"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Blog struct {
|
||||||
|
Id string `json:"id"`
|
||||||
|
Content string `json:"content"`
|
||||||
|
Date string `json:"created_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
err := mime.AddExtensionType(".gmi", "text/gemini")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("mime: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
listener := listen("0.0.0.0:1965", "cert.pem", "key.rsa")
|
||||||
|
log.Println("Server successfully started")
|
||||||
|
log.Println("Server is listening at 0.0.0.0:1956")
|
||||||
|
|
||||||
|
serve(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
func listen(address, certFile, keyFile string) net.Listener {
|
||||||
|
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("loadkeys: %s", err)
|
||||||
|
}
|
||||||
|
config := &tls.Config{
|
||||||
|
ClientAuth: tls.RequestClientCert,
|
||||||
|
Certificates: []tls.Certificate{cert},
|
||||||
|
MinVersion: tls.VersionTLS12,
|
||||||
|
InsecureSkipVerify: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
listener, err := tls.Listen("tcp", address, config)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("failed to listen on 0.0.0.0:1965: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return listener
|
||||||
|
}
|
||||||
|
|
||||||
|
func serve(listener net.Listener) {
|
||||||
|
for {
|
||||||
|
conn, err := listener.Accept()
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
go handleConn(conn.(*tls.Conn))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleConn(conn *tls.Conn) {
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
blogs := getBlog("https://mamot.fr", "138624")
|
||||||
|
|
||||||
|
_, err := fmt.Fprintf(conn, "20 text/gemini\r\n# Picasoft account toots\n")
|
||||||
|
if err != nil {
|
||||||
|
log.Println("handleConn: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, blog := range blogs {
|
||||||
|
date := "```\n* Posted at " + blog.Date + "\n```\n"
|
||||||
|
|
||||||
|
text := blog.Content + "\n"
|
||||||
|
text = strings.ReplaceAll(text, "<p>", "")
|
||||||
|
text = strings.ReplaceAll(text, "</p>", "\n\n")
|
||||||
|
text = strings.ReplaceAll(text, "<br />", "\n")
|
||||||
|
text = strings.ReplaceAll(text, "</a>", "")
|
||||||
|
text = strings.ReplaceAll(text, "</span>", "")
|
||||||
|
regexString := "<a( [^>]*)?>"
|
||||||
|
regex, err := regexp.Compile(regexString)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("regex: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
text = regex.ReplaceAllLiteralString(text, "")
|
||||||
|
regexString = "<span( [^>]*)?>"
|
||||||
|
regex, err = regexp.Compile(regexString)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("regex: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
text = regex.ReplaceAllLiteralString(text, "")
|
||||||
|
text = html.UnescapeString(text)
|
||||||
|
|
||||||
|
_, err = fmt.Fprintf(conn, date + text)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("read blogs: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getBlog(baseURL, account string) []Blog {
|
||||||
|
if baseURL == "" || account == "" {
|
||||||
|
log.Println("baseURL or account is empty")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := http.Get(baseURL + "/api/v1/accounts/" + account + "/statuses?exclude_reblogs=true")
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Mastodon API request: %s", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if resp.StatusCode != 200 {
|
||||||
|
log.Println("Mastodon API response: %s", resp.Status)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Mastodon response body: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var blogs []Blog
|
||||||
|
json.Unmarshal(body, &blogs)
|
||||||
|
|
||||||
|
return blogs
|
||||||
|
}
|
Loading…
Reference in New Issue