initial code base...

This commit is contained in:
Marcell Mars 2021-03-25 15:03:41 +01:00
parent 13f2427b7c
commit 7606f779fd
9 changed files with 444 additions and 0 deletions

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 John Farley
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

43
app/c.js Normal file
View file

@ -0,0 +1,43 @@
function captureFrontMatterAndMarkdown() {
console.log(location.pathname.split('/public')[0])
const formData = new FormData(document.querySelector("form"))
let frontmatter = "---\n"
for (const k of formData.keys()) {
// draft, iscjklanguage are default implicit (false) params in hugo
if (["draft", "iscjklanguage"].includes(k)){
console.log(formData.get(k))
if (formData.get(k) === "true") {
frontmatter += `${k}: true\n`
}
} else if (k.endsWith('[]')) {
formData.set(k, formData.getAll(k))
var s = JSON.stringify(formData.getAll(k)[0].split(","))
frontmatter += `${k.slice(0, -2)}: ${s}\n`
} else if (k == "relpath") {
filepath = `${location.pathname.split('/public')[0]}/content/${formData.get(k)}`
gitpath = `${location.pathname.split('/public')[0]}`
} else if (["protocol", "offline"].includes(k)) {
continue
} else {
var s = JSON.stringify(formData.get(k))
frontmatter += `${k}: ${s}\n`
}
}
frontmatter += "---\n"
const content = document.querySelector('textarea').value
let doc = frontmatter + content
let publish = formData.get("publish") == "on" ? true : false
let offline = formData.get("offline") == "on" ? true : false
return {"hugopage": doc, "filepath": filepath, "gitpath": gitpath, "publish": publish, "offline": offline, "protocol": document.location.protocol.substr(0,4)}
}
let sb = document.getElementById('sandpointsButton')
if (sb) {
sb.addEventListener(
"click", (e)=> {
e.preventDefault()
chrome.runtime.sendMessage(
captureFrontMatterAndMarkdown()
);
});
}

15
app/main.js Normal file
View file

@ -0,0 +1,15 @@
chrome.runtime.onMessage.addListener((m, n)=> {
var nh = chrome.runtime.connectNative("org.sandpoints.chromeext")
nh.onDisconnect.addListener((e, err)=> {
console.log("event:", e)
console.log("error:", err)
})
console.log("message:", m)
console.log("sender:", n)
nh.postMessage(m);
nh.onMessage.addListener((m, n)=> {
console.log("native host message:", m)
console.log("native host sender:", n)
})
})

22
app/manifest.json Normal file
View file

@ -0,0 +1,22 @@
{
"name": "Sandpoints Local Messaging Host",
"version": "1.0",
"manifest_version": 3,
"description": "Chrome extension to bridge messaging in between files open via file:// to talk to system.",
"action": {
"default_icon": "icon.png"
},
"background": {
"service_worker": "main.js"
},
"content_scripts": [
{
"matches": ["file://*"],
"all_frames": true,
"js": ["c.js"]
}
],
"permissions": [
"nativeMessaging"
]
}

View file

@ -0,0 +1,9 @@
{
"name": "org.sandpoints.chromeext",
"description": "Sandpoints Local Native Messaging Host",
"path": "/home/m/bin/natgost",
"type": "stdio",
"allowed_origins": [
"chrome-extension://bknfdkcponnfbabklbadclgaimgoaipp/"
]
}

5
native-host/src/go.mod Normal file
View file

@ -0,0 +1,5 @@
module main
go 1.15
require github.com/go-git/go-git/v5 v5.2.0

64
native-host/src/go.sum Normal file
View file

@ -0,0 +1,64 @@
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
github.com/go-git/go-billy/v5 v5.0.0 h1:7NQHvd9FVid8VL4qVUMm8XifBK+2xCoZ2lSk0agRrHM=
github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
github.com/go-git/go-git v1.0.0 h1:YcN9iDGDoXuIw0vHls6rINwV416HYa0EB2X+RBsyYp4=
github.com/go-git/go-git v4.7.0+incompatible h1:+W9rgGY4DOKKdX2x6HxSR7HNeTxqiKrOvKnuittYVdA=
github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw=
github.com/go-git/go-git/v5 v5.2.0 h1:YPBLG/3UK1we1ohRkncLjaXWLW+HKp5QNM/jTli2JgI=
github.com/go-git/go-git/v5 v5.2.0/go.mod h1:kh02eMX+wdqqxgNMEyq8YgwlIOsDOa9homkUq1PoTMs=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg=
github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY=
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 h1:xMPOj6Pz6UipU1wXLkrtqpHbR0AVFnyPEQq/wRWz9lM=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

265
native-host/src/main.go Normal file
View file

@ -0,0 +1,265 @@
package main
import (
"bufio"
"bytes"
"encoding/binary"
"encoding/json"
"fmt"
"io"
"log"
"os"
"os/exec"
"path/filepath"
"strings"
"time"
"unsafe"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing/object"
)
// this project started by copying:
// https://github.com/jfarleyx/chrome-native-messaging-golang
// constants for Logger
var (
// Trace logs general information messages.
Trace *log.Logger
// Error logs error messages.
Error *log.Logger
)
// nativeEndian used to detect native byte order
var nativeEndian binary.ByteOrder
// bufferSize used to set size of IO buffer - adjust to accommodate message payloads
var bufferSize = 8192
// IncomingMessage represents a message sent to the native host.
type IncomingMessage struct {
Hugopage string `json:"hugopage"`
Filepath string `json:"filepath"`
Gitpath string `json:"gitpath"`
Publish bool `json:"publish"`
Offline bool `json:"offline"`
Protocol string `json:"protocol"`
}
// OutgoingMessage respresents a response to an incoming message query.
type OutgoingMessage struct {
Query string `json:"query"`
Response string `json:"response"`
}
// Init initializes logger and determines native byte order.
func Init(traceHandle io.Writer, errorHandle io.Writer) {
Trace = log.New(traceHandle, "TRACE: ", log.Ldate|log.Ltime|log.Lshortfile)
Error = log.New(errorHandle, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile)
// determine native byte order so that we can read message size correctly
var one int16 = 1
b := (*byte)(unsafe.Pointer(&one))
if *b == 0 {
nativeEndian = binary.BigEndian
} else {
nativeEndian = binary.LittleEndian
}
}
func main() {
file, err := os.OpenFile(filepath.Join("/tmp", "sandpoints-chromeext-log.txt"), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
Init(os.Stdout, os.Stderr)
Error.Printf("Unable to create and/or open log file. Will log to Stdout and Stderr. Error: %v", err)
} else {
Init(file, file)
// ensure we close the log file when we're done
defer file.Close()
}
Trace.Printf("Chrome native messaging host started. Native byte order: %v.", nativeEndian)
read()
Trace.Print("Chrome native messaging host exited.")
}
// read Creates a new buffered I/O reader and reads messages from Stdin.
func read() {
v := bufio.NewReader(os.Stdin)
// adjust buffer size to accommodate your json payload size limits; default is 4096
s := bufio.NewReaderSize(v, bufferSize)
Trace.Printf("IO buffer reader created with buffer size of %v.", s.Size())
lengthBytes := make([]byte, 4)
lengthNum := int(0)
// we're going to indefinitely read the first 4 bytes in buffer, which gives us the message length.
// if stdIn is closed we'll exit the loop and shut down host
for b, err := s.Read(lengthBytes); b > 0 && err == nil; b, err = s.Read(lengthBytes) {
// convert message length bytes to integer value
lengthNum = readMessageLength(lengthBytes)
Trace.Printf("Message size in bytes: %v", lengthNum)
// If message length exceeds size of buffer, the message will be truncated.
// This will likely cause an error when we attempt to unmarshal message to JSON.
if lengthNum > bufferSize {
Error.Printf("Message size of %d exceeds buffer size of %d. Message will be truncated and is unlikely to unmarshal to JSON.", lengthNum, bufferSize)
}
// read the content of the message from buffer
content := make([]byte, lengthNum)
_, err := s.Read(content)
if err != nil && err != io.EOF {
Error.Fatal(err)
}
// message has been read, now parse and process
parseMessage(content)
}
Trace.Print("Stdin closed.")
}
// readMessageLength reads and returns the message length value in native byte order.
func readMessageLength(msg []byte) int {
var length uint32
buf := bytes.NewBuffer(msg)
err := binary.Read(buf, nativeEndian, &length)
if err != nil {
Error.Printf("Unable to read bytes representing message length: %v", err)
}
return int(length)
}
// write incoming message to file
func writeMessageToFile(fpath string, content string) {
f, err := os.Create(fpath)
if err != nil {
Error.Printf("Write to file failed: %v", err)
}
defer f.Close()
f.WriteString(content)
}
// commit edit to git repo
func commitChangeToGit(iMsg IncomingMessage) {
g, err := git.PlainOpen(iMsg.Gitpath)
if err != nil {
Error.Printf("ERROR: Go-git Plain Open:", err)
}
w, err := g.Worktree()
if err != nil {
Error.Printf("ERROR: Go-git Worktree:", err)
}
// filePath := filepath.Base(iMsg.Filepath)
// editFile := filepath.Join(iMsg.Gitpath, filePath)
relPathFile := filepath.Join(strings.ReplaceAll(iMsg.Filepath, iMsg.Gitpath+"/", ""))
// err = ioutil.WriteFile(iMsg.Filepath, []byte(iMsg.Hugopage), 0644)
// check(err)
writeMessageToFile(iMsg.Filepath, iMsg.Hugopage)
_, err = w.Add(relPathFile)
if err != nil {
Error.Printf("ERROR: Go-git Add:", err)
}
tn := time.Now()
w.Commit(fmt.Sprintf("sandpoints-ext - %s - editing via browser...", tn), &git.CommitOptions{
Author: &object.Signature{
Name: "Sandpoints Edit Page",
Email: "editpage@sandpoints.org",
When: tn,
},
})
}
// trigger git hook
func triggerGitHook(gitpath string, publish bool, offline bool, protocol string) {
cmd := exec.Command(filepath.Join(gitpath, ".git", "hooks", "post-commit"))
stdin, err := cmd.StdinPipe()
if err != nil {
Error.Printf("StdinPipe:", err)
}
pub := "nope"
if publish {
pub = "publish"
}
offl := "nope"
if offline {
offl = "offline"
}
go func() {
defer stdin.Close()
io.WriteString(stdin, fmt.Sprintf("sandpoints-ext %s %s %s", pub, offl, protocol))
}()
out, err := cmd.CombinedOutput()
if err != nil {
Error.Printf("ERROR Combined output: %s", err)
}
Trace.Printf("Git Hook Combined Output: %s", out)
}
// parseMessage parses incoming message
func parseMessage(msg []byte) {
iMsg := decodeMessage(msg)
Trace.Printf("Message received: %s", msg)
commitChangeToGit(iMsg)
triggerGitHook(iMsg.Gitpath, iMsg.Publish, iMsg.Offline, iMsg.Protocol)
// start building outgoing json message
oMsg := OutgoingMessage{
Query: iMsg.Hugopage,
}
switch iMsg.Hugopage {
case "foo":
oMsg.Response = "bar"
default:
oMsg.Response = "native host says yeah!"
}
send(oMsg)
}
// decodeMessage unmarshals incoming json request and returns query value.
func decodeMessage(msg []byte) IncomingMessage {
var iMsg IncomingMessage
err := json.Unmarshal(msg, &iMsg)
if err != nil {
Error.Printf("Unable to unmarshal json to struct: %v", err)
}
return iMsg
}
// send sends an OutgoingMessage to os.Stdout.
func send(msg OutgoingMessage) {
byteMsg := dataToBytes(msg)
writeMessageLength(byteMsg)
var msgBuf bytes.Buffer
_, err := msgBuf.Write(byteMsg)
if err != nil {
Error.Printf("Unable to write message length to message buffer: %v", err)
}
_, err = msgBuf.WriteTo(os.Stdout)
if err != nil {
Error.Printf("Unable to write message buffer to Stdout: %v", err)
}
}
// dataToBytes marshals OutgoingMessage struct to slice of bytes
func dataToBytes(msg OutgoingMessage) []byte {
byteMsg, err := json.Marshal(msg)
if err != nil {
Error.Printf("Unable to marshal OutgoingMessage struct to slice of bytes: %v", err)
}
return byteMsg
}
// writeMessageLength determines length of message and writes it to os.Stdout.
func writeMessageLength(msg []byte) {
err := binary.Write(os.Stdout, nativeEndian, uint32(len(msg)))
if err != nil {
Error.Printf("Unable to write message length to Stdout: %v", err)
}
}

BIN
native-host/src/natgost Executable file

Binary file not shown.