Initial commit

remotes/origin/documentation
Adam Veldhousen 5 years ago
commit 0d6b6e07a1
Signed by: adam
GPG Key ID: 6DB29003C6DD1E4B

2
.gitignore vendored

@ -0,0 +1,2 @@
.bin
.vscode

@ -0,0 +1,28 @@
FROM golang:1.13.3-alpine AS build
WORKDIR /go/src/riffraff
COPY . /go/src/riffraff
RUN apk add --no-cache make
RUN make clean build
FROM alpine
ARG VERSION=dev
LABEL maintainer="Adam Veldhousen <adam@vdhsn.com>"
LABEL version=${VERSION}
WORKDIR /usr/local/bin
COPY --from=build /go/src/riffraff/.bin/riffraff /usr/local/bin/
RUN apk add --no-cache ca-certificates
RUN adduser -u 1000 -D -s /bin/ash riffraff \
&& chown -R riffraff:riffraff /usr/local/bin/riffraff
USER riffraff
EXPOSE 8080
ENTRYPOINT [ "/usr/local/bin/riffraff", "-port", "8080", "-accesslog"]

@ -0,0 +1,15 @@
Riff Raff
Copyright (C) 2019 Adam Veldhousen
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

@ -0,0 +1,39 @@
# rifraf
A browser omni search bar enhancer. Side effects may include enhanced productivity, happiness and less google search tracking.
## How to install
- Install it:
```
go get git.vdhsn.com/adam/riffraff
```
- Start it:
```
rifiraff [-p 80] [-accesslog]
```
- Point your browser at it:
- Customize it:
- add a shortcut: `add gitemoji https://www.webfx.com/tools/emoji-cheat-sheet`
- add a search *note the `%s`*: `add so https://stackoverflow.com/search?q=%s` or `add go https://godoc.org/?q=%s`
- Use it:
- use stackoverflow shortcut: `so what is the copy and swap idiom`
- go to a shortcut: `gitemoji`
## FAQ
- Why rifraf?
- It's Halloween, I finally watched Rocky Horror Picture Show, and I'm following the butler theme for search apps.
- How does this work?
- This serves a page over HTTP that implements [Opensearch spec](https://developer.mozilla.org/en-US/docs/Web/OpenSearch).
## License
GPL

@ -0,0 +1,5 @@
module github.com/adamveld12/riffraff
go 1.13
require github.com/gobuffalo/packr v1.30.1

@ -0,0 +1,80 @@
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/gobuffalo/envy v1.7.0 h1:GlXgaiBkmrYMHco6t4j7SacKO4XUjvh5pwXh0f4uxXU=
github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
github.com/gobuffalo/logger v1.0.0 h1:xw9Ko9EcC5iAFprrjJ6oZco9UpzS5MQ4jAwghsLHdy4=
github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs=
github.com/gobuffalo/packd v0.3.0 h1:eMwymTkA1uXsqxS0Tpoop3Lc0u3kTfiMBE6nKtQU4g4=
github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q=
github.com/gobuffalo/packr v1.30.1 h1:hu1fuVR3fXEZR7rXNW3h8rqSML8EVAf6KNm0NKO/wKg=
github.com/gobuffalo/packr v1.30.1/go.mod h1:ljMyFO2EcrnzsHsN99cvbq055Y9OhRrIaviy289eRuk=
github.com/gobuffalo/packr/v2 v2.5.1 h1:TFOeY2VoGamPjQLiNDT3mn//ytzk236VMO2j7iHxJR4=
github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/karrick/godirwalk v1.10.12 h1:BqUm+LuJcXjGv1d2mj3gBiQyrQ57a0rYoAmhvJQ7RDU=
github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
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/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/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-20190621222207-cc06ce4a13d4 h1:ydJNl0ENAG67pFbB+9tfhiL2pYqLhfoaZFw/cjLhY4A=
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/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-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190515120540-06a5c4944438 h1:khxRGsvPk4n2y8I/mLLjp7e5dMTJmH75wvqS6nMwUtY=
golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

@ -0,0 +1,51 @@
package internal
import (
"fmt"
"log"
"net/http"
"os"
"sync"
)
func NewServer(tp TemplateRenderer, accessLogging bool) http.Handler {
mux := http.NewServeMux()
ss := &CommandHandler{
Mutex: &sync.Mutex{},
Shortcuts: map[string]string{
"*": DefaultSearchProvider,
"help": "/",
},
}
mux.HandleFunc("/", tp.RenderHandler("index.html", ss, nil))
mux.HandleFunc("/index.html", tp.RenderHandler("index.html", ss, nil))
mux.HandleFunc("/search_plugin.xml", tp.RenderHandler("search_plugin.xml", ss, http.Header{
"Content-Type": []string{"application/opensearchdescription+xml"},
}))
handlerFunc := searchHandler(ss, accessLogging)
mux.HandleFunc("/search", handlerFunc)
mux.HandleFunc("/search_to_home", handlerFunc)
return mux
}
func searchHandler(scs *CommandHandler, logAccess bool) http.HandlerFunc {
accessLogger := log.New(os.Stdout, "[access] ", log.Ldate|log.Lmicroseconds|log.Lshortfile)
return func(res http.ResponseWriter, req *http.Request) {
v := req.URL.Query()
commandString := v.Get("q")
action, err := scs.Handle(commandString)
if err != nil {
accessLogger.Printf("'%s' -> got error: '%s'", commandString, err.Error())
http.Redirect(res, req, fmt.Sprintf("https://duckduckgo.com?q=%s", commandString), http.StatusFound)
return
}
accessLogger.Printf("'%s' %s -> 302 %s", commandString, action.Action, action.Location)
http.Redirect(res, req, action.Location, http.StatusFound)
}
}

@ -0,0 +1,109 @@
package internal
import (
"errors"
"fmt"
"strings"
"sync"
)
const (
DefaultSearchProvider = "https://duckduckgo.com/%s"
)
var (
ErrUnrecognizedCommand = errors.New("unrecognized command")
ErrNotEnoughArguments = errors.New("not enough arguments")
)
type CommandHandler struct {
*sync.Mutex
Shortcuts map[string]string
}
func (c *CommandHandler) Handle(input string) (Command, error) {
rawArgs := strings.Fields(input)
fragmentCount := len(rawArgs)
farg := "*"
parameters := input
var shortcut string
if fragmentCount > 0 {
farg = rawArgs[0]
if fragmentCount > 1 {
shortcut = rawArgs[1]
}
var updateShortcutParams string
if fragmentCount > 2 {
updateShortcutParams = strings.Join(rawArgs[2:], " ")
}
if cmd, err := c.updateShortcut(farg, shortcut, updateShortcutParams); err != ErrUnrecognizedCommand {
return cmd, err
}
}
return c.getShortcut(farg, parameters), nil
}
func (c *CommandHandler) updateShortcut(action, shortcut, location string) (Command, error) {
command := Command{
Action: action,
Name: shortcut,
Location: location,
}
switch action {
case "add":
if location == "" {
return Command{}, ErrNotEnoughArguments
}
c.Lock()
c.Shortcuts[shortcut] = command.Location
c.Unlock()
case "remove":
if shortcut == "" {
return Command{}, ErrNotEnoughArguments
}
command.Location = c.Shortcuts[shortcut]
c.Lock()
delete(c.Shortcuts, shortcut)
c.Unlock()
default:
return Command{}, ErrUnrecognizedCommand
}
return command, nil
}
func (c *CommandHandler) getShortcut(key string, parameter string) Command {
location, ok := c.Shortcuts[key]
if !ok {
location = DefaultSearchProvider
key = "*"
}
if strings.Contains(location, "%s") {
location = fmt.Sprintf(location, parameter)
}
return Command{
Action: "lookup",
Name: key,
Location: location,
}
}
type Command struct {
Action string
Name string
Location string
}

@ -0,0 +1,91 @@
package internal
import (
"fmt"
"reflect"
"testing"
)
func Test_Handle(t *testing.T) {
tests := []struct {
name string
input string
want Command
wantErr bool
}{
{
name: "empty input should send to default search provider",
input: "",
want: Command{
Action: "lookup",
Name: "*",
Location: fmt.Sprintf(DefaultSearchProvider, ""),
},
},
{
name: "add shortcut: 'add gh https://github.com'",
input: "add gh https://github.com",
want: Command{
Action: "add",
Name: "gh",
Location: "https://github.com",
},
},
{
name: "add shortcut without location: 'add gh'",
input: "add gh",
wantErr: true,
},
{
name: "remove shortcut: 'remove gh'",
input: "remove gh",
want: Command{
Action: "remove",
Name: "gh",
},
},
{
name: "remove command with incorrect number of args: 'remove'",
input: "remove",
wantErr: true,
},
{
name: "forward search to search provider: 'golang unit testing frameworks'",
input: "golang unit testing frameworks",
want: Command{
Action: "lookup",
Name: "*",
Location: fmt.Sprintf(DefaultSearchProvider, "golang unit testing frameworks"),
},
},
{
name: "visit a shortcut: 'fb'",
input: "fb",
want: Command{
Action: "lookup",
Name: "fb",
Location: "https://facebook.com",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cm := &CommandHandler{
Shortcuts: map[string]string{
"fb": "https://facebook.com",
},
}
got, err := cm.Handle(tt.input)
if tt.wantErr != (err != nil) {
t.Errorf("wantErr: %v got '%v'", tt.wantErr, err)
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("parseInput('%s') = %v, want %v", tt.input, got, tt.want)
}
})
}
}

@ -0,0 +1,85 @@
package internal
import (
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"html/template"
)
type TemplateRenderer struct {
FS http.FileSystem
}
type TemplateVariables struct {
Host string
Entries map[string]string
}
func ToTemplateVars(req *http.Request, shortcuts map[string]string) TemplateVariables {
scheme := req.URL.Scheme
host := req.URL.Host
if scheme == "" {
scheme = "http"
}
if host == "" {
if host = req.Header.Get("X-Forwarded-For"); host == "" {
host = req.Host
}
}
fqdn := fmt.Sprintf("%s://%s", scheme, host)
return TemplateVariables{
Host: fqdn,
Entries: shortcuts,
}
}
func (tr TemplateRenderer) Render(name string, templVars TemplateVariables, w io.Writer) error {
templateFileName := fmt.Sprintf("%s.tpl", name)
f, err := tr.FS.Open(templateFileName)
if err != nil {
return err
}
defer f.Close()
templateBytes, err := ioutil.ReadAll(f)
if err != nil {
return err
}
templateStr := string(templateBytes)
templateObj, parseTemplateErr := template.New(templateFileName).Parse(templateStr)
if parseTemplateErr != nil {
return fmt.Errorf("could not parse template for '%s': %w", templateFileName, parseTemplateErr)
}
log.Printf("%+v", templVars)
return templateObj.Execute(w, templVars)
}
func (tr TemplateRenderer) RenderHandler(filename string, ss *CommandHandler, headers http.Header) http.HandlerFunc {
return func(res http.ResponseWriter, req *http.Request) {
templVar := ToTemplateVars(req, ss.Shortcuts)
h := res.Header()
for k, v := range headers {
h[k] = v
}
h.Set("Cache-Control", "max-age 0; no-cache; private")
if err := tr.Render(filename, templVar, res); err != nil {
http.Error(res, err.Error(), http.StatusInternalServerError)
return
}
}
}

@ -0,0 +1,14 @@
{
"shortcuts": [
{
"name": "gh",
"location": "https://github.com"
}
],
"searches": [
{
"name": "so",
"location": "https://stackoverflow.com/search?q=%s"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 B

@ -0,0 +1,37 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link
rel="search"
type="application/opensearchdescription+xml"
title="riff-raff"
href="/search_plugin.xml"
/>
<Url type="application/opensearchdescription+xml"
rel="self"
template="/search_plugin.xml" />
</head>
<body style="display: flex; width: 100%; align-items: center; flex-direction: column;">
<div style="display: flex; align-content: center; flex-direction: column; min-width: 40%;">
<h1>Hello Internet from {{ .Host }}</h1>
<!-- Add search box form here for testing/adding shortcuts -->
<form action="/search" method="GET" style="display:flex; margin-bottom: 10px; width: 100%;">
<input type="text" name="q" value="" style="flex-grow: 1;"/>
<input type="submit" />
</form>
<div style="background: lightgray; padding: 10px 5px; margin-bottom: 10px;">
add &lt;shortcut&gt; &lt;url&gt;: adds a url as a shortcut<br/>
remove &lt;shortcut&gt; : removes a url shortcut<br/>
</div>
<ul style="list-style-type: none; padding: 0; margin-top: 15px;">
{{ range $key, $value := .Entries }}
<li>
- {{ $key }} → <a href="{{ $value }}">{{ $value }}</a>
</li>
{{ end }}
</ul>
</div>
</body>
</html>

@ -0,0 +1,11 @@
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/" xmlns:moz="http://www.mozilla.org/2006/browser/search/">
<ShortName>Riff Raff</ShortName>
<Description>slick omnibar search enhancer</Description>
<InputEncoding>UTF-8</InputEncoding>
<Image width="16" height="16" type="image/png">{{ .Host }}/favicon.png</Image>
<Url type="text/html" template="{{ .Host }}/search">
<Param name="q" value="{searchTerms}"/>
</Url>
<Url type="application/x-suggestions+json" template="{{ .Host }}/search"/>
<moz:SearchForm>{{ .Host }}/search</moz:SearchForm>
</OpenSearchDescription>

@ -0,0 +1,28 @@
package main
import (
"flag"
"fmt"
"log"
"net/http"
"github.com/adamveld12/riffraff/internal"
"github.com/gobuffalo/packr"
)
func main() {
port := flag.Int("port", 80, "port to listen on")
enableAccessLogging := flag.Bool("accesslog", true, "Enable access logging")
flag.Parse()
box := packr.NewBox("./internal/templates")
tp := internal.TemplateRenderer{FS: box}
server := internal.NewServer(tp, *enableAccessLogging)
log.SetPrefix("[INFO] ")
addr := fmt.Sprintf("0.0.0.0:%d", *port)
log.Printf("Listening @ %s", addr)
log.Fatal(http.ListenAndServe(addr, server))
}

@ -0,0 +1,32 @@
APP := riffraff
dev: clean .bin/$(APP)-dev
./.bin/$(APP)-dev -port 8080 -accesslog=true
package:
docker build --build-arg VERSION=$${VERSION:-dev} -t vdhsn/$(APP):$${VERSION:-dev} .
package-run:
docker run -it --rm --name riffraff -u 1000:1000 -p 8080:8080 vdhsn/$(APP):$${VERSION:-dev}
publish: package
docker push vdhsn/$(APP):$${VERSION:-dev}
build: .bin/$(APP)
.bin:
mkdir .bin
.bin/$(APP): packr .bin
packr build -o .bin/$(APP) -v .
.bin/$(APP)-dev: .bin
go build -o .bin/$(APP)-dev -v .
clean:
rm -rf .bin
packr:
go get -u github.com/gobuffalo/packr/packr
.PHONY: build clean dev package package-run publish packr
Loading…
Cancel
Save