Rebrand to Yukari's Gap

Signed-off-by: Izuru Yakumo <yakumo.izuru@chaotic.ninja>

git-svn-id: file:///srv/svn/repo/yukari/trunk@142 f3bd38d9-da89-464d-a02a-eb04e43141b5
This commit is contained in:
yakumo.izuru 2023-08-26 11:57:19 +00:00
parent 940bc84841
commit 0950c02269
11 changed files with 90 additions and 146 deletions

2
.gitignore vendored
View File

@ -1 +1 @@
morty
yukari

View File

@ -1,17 +0,0 @@
language: go
sudo: false
go:
- 1.12.x
script:
# run tests on a standard platform
- OUT="$(go get -a)"; test -z "$OUT" || (echo "$OUT" && return 1)
- OUT="$(gofmt -l -d ./)"; test -z "$OUT" || (echo "$OUT" && return 1)
- go vet -v ./...
- go test -v ./...
# build test for supported platforms
- GOOS=linux go build
- GOOS=darwin go build
- GOOS=freebsd go build
- GOOS=windows go build
- GOARCH=386 go build

View File

@ -1,3 +1,7 @@
# v0.2.1 - 2023.08.26
Applied some suggestions from the issue tracker, and
rebrand this fork.
# v0.2.0 - 2018.05.28
Man page added

View File

@ -1,30 +0,0 @@
# STEP 1 build executable binary
FROM golang:1.14-alpine as builder
WORKDIR $GOPATH/src/github.com/asciimoo/morty
RUN apk add --no-cache git
COPY . .
RUN go get -d -v
RUN gofmt -l ./
#RUN go vet -v ./...
#RUN go test -v ./...
RUN go build .
# STEP 2 build the image including only the binary
FROM alpine:3.12
EXPOSE 3000
RUN apk --no-cache add ca-certificates \
&& rm -f /var/cache/apk/* \
&& adduser -D -h /usr/local/morty -s /bin/false morty morty
COPY --from=builder /go/src/github.com/asciimoo/morty/morty /usr/local/morty/morty
USER morty
ENV DEBUG=true
ENTRYPOINT ["/usr/local/morty/morty"]

View File

@ -1,9 +1,10 @@
APP_NAME=morty
all: build
bench:
go test -benchmem -bench .
build:
docker rmi -f $(APP_NAME):latest
docker build -t $(APP_NAME) .
run:
@echo "\n /!\ DO NOT use in production\n"
docker run --rm -t -i --net=host --name="$(APP_NAME)" $(APP_NAME)
go build -o yukari
clean:
rm -f yukari
test:
go test

View File

@ -1,14 +1,10 @@
# Morty
# Yukari
[![Build Status](https://travis-ci.org/asciimoo/morty.svg)](https://travis-ci.org/asciimoo/morty)
[![License: AGPL v3](https://img.shields.io/badge/License-AGPL%20v3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0)
[![Docker Pulls](https://img.shields.io/docker/pulls/dalf/morty)](https://hub.docker.com/r/dalf/morty)
Web content sanitizer proxy as a service, fork of [MortyProxy](https://github.com/asciimoo/morty) with some suggestions from the issue tracker applied, named after [Yes, that Gap Youkai](https://en.touhouwiki.net/wiki/Yukari_Yakumo)
Web content sanitizer proxy as a service
Yukari rewrites web pages to exclude malicious HTML tags and attributes. It also replaces external resource references to prevent third party information leaks.
Morty rewrites web pages to exclude malicious HTML tags and attributes. It also replaces external resource references to prevent third party information leaks.
The main goal of morty is to provide a result proxy for [searx](https://asciimoo.github.com/searx/), but it can be used as a standalone sanitizer service too.
The main goal of yukari is to provide a result proxy for [searx](https://asciimoo.github.com/searx/), but it can be used as a standalone sanitizer service too.
Features:
@ -26,8 +22,8 @@ Features:
Requirement: Go version 1.10 or higher.
```
$ go install github.com/asciimoo/morty@latest
$ "$GOPATH/bin/morty" --help
$ go install marisa.chaotic.ninja/yukari@latest
$ "$GOPATH/bin/yukari" --help
```
### Usage
@ -38,7 +34,7 @@ $ "$GOPATH/bin/morty" --help
-followredirect
Follow HTTP GET redirect
-hashparam string
User-defined requesting string HASH parameter name (ie: '/?hash=...' or '/?h=...') (default "mortyhash")
User-defined requesting string HASH parameter name (ie: '/?hash=...' or '/?h=...') (default "yukarihash")
-ipv6
Allow IPv6 HTTP requests (default true)
-key string
@ -54,35 +50,24 @@ $ "$GOPATH/bin/morty" --help
-timeout uint
Request timeout (default 5)
-urlparam string
User-defined requesting string URL parameter name (ie: '/?url=...' or '/?u=...') (default "mortyurl")
User-defined requesting string URL parameter name (ie: '/?url=...' or '/?u=...') (default "yukariurl")
-version
Show version
```
### Environment variables
Morty can additionally be configured using the following environment variables:
- `MORTY_ADDRESS`: Listen address (default to `127.0.0.1:3000`)
- `MORTY_KEY`: HMAC url validation key (base64 encoded) to prevent direct URL opening. Leave blank to disable validation. Use `openssl rand -base64 33` to generate.
- `MORTY_URL_PARAM`: User-defined requesting string URL parameter name (ie: `/?url=...` or `/?u=...`) (default `mortyurl`)
- `MORTY_HASH_PARAM`: User-defined requesting string HASH parameter name (ie: `/?hash=...` or `/?h=...`) (default `mortyhash`)
Yukari can additionally be configured using the following environment variables:
- `YUKARI_ADDRESS`: Listen address (default to `127.0.0.1:3000`)
- `YUKARI_KEY`: HMAC url validation key (base64 encoded) to prevent direct URL opening. Leave blank to disable validation. Use `openssl rand -base64 33` to generate.
- `YUKARI_URL_PARAM`: User-defined requesting string URL parameter name (ie: `/?url=...` or `/?u=...`) (default `yukariurl`)
- `YUKARI_HASH_PARAM`: User-defined requesting string HASH parameter name (ie: `/?hash=...` or `/?h=...`) (default `yukarihash`)
- `DEBUG`: Enable/disable proxy and redirection logs (default to `true`). Set to `false` to disable.
### Docker
```
docker run -e DEBUG=false -e MORTY_ADDRESS=0.0.0.0:3000 dalf/morty
```
```
docker run -e DEBUG=false dalf/morty -listen 0.0.0.0:3000
```
### Test
```
$ cd "$GOPATH/src/github.com/asciimoo/morty"
$ cd "$GOPATH/src/marisa.chaotic.ninja/yukari"
$ go test
```
@ -90,11 +75,10 @@ $ go test
### Benchmark
```
$ cd "$GOPATH/src/github.com/asciimoo/morty"
$ cd "$GOPATH/src/marisa.chaotic.ninja/yukari"
$ go test -benchmem -bench .
```
## Bugs
Bugs or suggestions? Visit the [issue tracker](https://github.com/asciimoo/morty/issues).
Bugs or suggestions? Visit the [issue tracker](https://git.chaotic.ninja/yakumo.izuru/yukari/issues).

View File

@ -19,19 +19,19 @@ type Config struct {
var DefaultConfig *Config
func init() {
default_listen_addr := os.Getenv("MORTY_ADDRESS")
default_listen_addr := os.Getenv("YUKARI_ADDRESS")
if default_listen_addr == "" {
default_listen_addr = "127.0.0.1:3000"
}
default_url_parameter := os.Getenv("MORTY_URL_PARAM")
default_url_parameter := os.Getenv("YUKARI_URL_PARAM")
if default_url_parameter == "" {
default_url_parameter = "mortyurl"
default_url_parameter = "yukariurl"
}
default_hash_parameter := os.Getenv("MORTY_HASH_PARAM")
default_hash_parameter := os.Getenv("YUKARI_HASH_PARAM")
if default_hash_parameter == "" {
default_hash_parameter = "mortyhash"
default_hash_parameter = "yukarihash"
}
default_key := os.Getenv("MORTY_KEY")
default_key := os.Getenv("YUKARI_KEY")
DefaultConfig = &Config{
Debug: os.Getenv("DEBUG") != "false",
ListenAddress: default_listen_addr,

2
go.mod
View File

@ -1,4 +1,4 @@
module github.com/asciimoo/morty
module marisa.chaotic.ninja/yukari
go 1.14

View File

@ -1,16 +1,16 @@
.TH MORTY "1" "2018" "morty" "User Commands"
.TH MORTY "1" "2018" "yukari" "User Commands"
.SH NAME
morty \- Privacy aware web content sanitizer proxy as a service
yukari \- Privacy aware web content sanitizer proxy as a service
.SH SYNOPSIS
.B morty
.B yukari
.RI [ OPTIONS ]
.br
.SH DESCRIPTION
Morty rewrites web pages to exclude malicious HTML tags and attributes. It
Yukari rewrites web pages to exclude malicious HTML tags and attributes. It
also replaces external resource references to prevent third party
information leaks.
.sp
The main goal of morty is to provide a result proxy for searx, but it can be
The main goal of yukari is to provide a result proxy for searx, but it can be
used as a standalone sanitizer service too.
.SH OPTIONS
.HP
@ -35,10 +35,12 @@ Request timeout (default 2)
Show version
.SH BUGS
Bugs or suggestions? Visit the issue tracker at
https://github.com/asciimoo/morty/issues.
https://git.chaotic.ninja/yakumo.izuru/yukari/issues.
.SH SEE ALSO
.BR searx (1)
.SH LICENSE
Copyright 2023-present Izuru Yakumo <yakumo.izuru@chaotic.ninja>
.br
Copyright 2016-2018 Adam Tauber <asciimoo@gmail.com>
.br
Copyright 2016 Alexandre Flament <alex@al-f.net>

View File

@ -27,8 +27,8 @@ import (
"golang.org/x/net/html/charset"
"golang.org/x/text/encoding"
"github.com/asciimoo/morty/config"
"github.com/asciimoo/morty/contenttype"
"marisa.chaotic.ninja/yukari/config"
"marisa.chaotic.ninja/yukari/contenttype"
)
const (
@ -195,13 +195,13 @@ type RequestConfig struct {
type HTMLBodyExtParam struct {
BaseURL string
HasMortyKey bool
HasYukariKey bool
URLParamName string
}
type HTMLFormExtParam struct {
BaseURL string
MortyHash string
YukariHash string
URLParamName string
HashParamName string
}
@ -217,10 +217,10 @@ var HTML_HEAD_CONTENT_TYPE string = `<meta http-equiv="Content-Type" content="te
<meta name="referrer" content="no-referrer">
`
var MORTY_HTML_PAGE_START string = `<!doctype html>
var YUKARI_HTML_PAGE_START string = `<!doctype html>
<html>
<head>
<title>MortyProxy</title>
<title>YukariSukima</title>
<meta name="viewport" content="width=device-width, initial-scale=1 , maximum-scale=1.0, user-scalable=1" />
<style>
html { height: 100%; }
@ -237,14 +237,14 @@ h1 { font-size: 3em; }
</head>
<body>
<div class="container">
<h1>MortyProxy</h1>
<h1>YukariSukima</h1>
`
var MORTY_HTML_PAGE_END string = `
var YUKARI_HTML_PAGE_END string = `
</div>
<div class="footer">
<p>Morty rewrites web pages to exclude malicious HTML tags and CSS/HTML attributes. It also replaces external resource references to prevent third-party information leaks.<br />
<a href="https://github.com/asciimoo/morty">view on github</a>
<p>Yukari rewrites web pages to exclude malicious HTML tags and CSS/HTML attributes. It also replaces external resource references to prevent third-party information leaks.<br />
<a href="https://marisa.chaotic.ninja/yukari">view on github</a>
</p>
</div>
</body>
@ -258,31 +258,31 @@ func init() {
FAVICON_BYTES, _ = base64.StdEncoding.DecodeString(FaviconBase64)
var err error
HTML_FORM_EXTENSION, err = template.New("html_form_extension").Parse(
`<input type="hidden" name="mortyurl" value="{{.BaseURL}}" />{{if .MortyHash}}<input type="hidden" name="mortyhash" value="{{.MortyHash}}" />{{end}}`)
`<input type="hidden" name="yukariurl" value="{{.BaseURL}}" />{{if .YukariHash}}<input type="hidden" name="yukarihash" value="{{.YukariHash}}" />{{end}}`)
if err != nil {
panic(err)
}
HTML_BODY_EXTENSION, err = template.New("html_body_extension").Parse(`
<input type="checkbox" id="mortytoggle" autocomplete="off" />
<div id="mortyheader">
<input type="checkbox" id="yukaritoggle" autocomplete="off" />
<div id="yukariheader">
<form method="get">
<label for="mortytoggle">hide</label>
<span><a href="/">Morty Proxy</a></span>
<input type="url" value="{{.BaseURL}}" name="{{.URLParamName}}" {{if .HasMortyKey }}readonly="true"{{end}} />
This is a <a href="https://github.com/asciimoo/morty">proxified and sanitized</a> view of the page, visit <a href="{{.BaseURL}}" rel="noreferrer">original site</a>.
<label for="yukaritoggle">hide</label>
<span><a href="/">Yukari's Gap</a></span>
<input type="url" value="{{.BaseURL}}" name="{{.URLParamName}}" {{if .HasYukariKey }}readonly="true"{{end}} />
This is a <a href="https://marisa.chaotic.ninja/yukari">proxified and sanitized</a> view of the page, visit <a href="{{.BaseURL}}" rel="noreferrer">original site</a>.
</form>
</div>
<style>
body{ position: absolute !important; top: 42px !important; left: 0 !important; right: 0 !important; bottom: 0 !important; }
#mortyheader { position: fixed; margin: 0; box-sizing: border-box; -webkit-box-sizing: border-box; top: 0; left: 0; right: 0; z-index: 2147483647 !important; font-size: 12px; line-height: normal; border-width: 0px 0px 2px 0; border-style: solid; border-color: #AAAAAA; background: #FFF; padding: 4px; color: #444; height: 42px; }
#mortyheader * { padding: 0; margin: 0; }
#mortyheader p { padding: 0 0 0.7em 0; display: block; }
#mortyheader a { color: #3498db; font-weight: bold; display: inline; }
#mortyheader label { text-align: right; cursor: pointer; position: fixed; right: 4px; top: 4px; display: block; color: #444; }
#mortyheader > form > span { font-size: 24px; font-weight: bold; margin-right: 20px; margin-left: 20px; }
input[type=checkbox]#mortytoggle { display: none; }
input[type=checkbox]#mortytoggle:checked ~ div { display: none; visibility: hidden; }
#mortyheader input[type=url] { width: 50%; padding: 4px; font-size: 16px; }
#yukariheader { position: fixed; margin: 0; box-sizing: border-box; -webkit-box-sizing: border-box; top: 0; left: 0; right: 0; z-index: 2147483647 !important; font-size: 12px; line-height: normal; border-width: 0px 0px 2px 0; border-style: solid; border-color: #AAAAAA; background: #FFF; padding: 4px; color: #444; height: 42px; }
#yukariheader * { padding: 0; margin: 0; }
#yukariheader p { padding: 0 0 0.7em 0; display: block; }
#yukariheader a { color: #3498db; font-weight: bold; display: inline; }
#yukariheader label { text-align: right; cursor: pointer; position: fixed; right: 4px; top: 4px; display: block; color: #444; }
#yukariheader > form > span { font-size: 24px; font-weight: bold; margin-right: 20px; margin-left: 20px; }
input[type=checkbox]#yukaritoggle { display: none; }
input[type=checkbox]#yukaritoggle:checked ~ div { display: none; visibility: hidden; }
#yukariheader input[type=url] { width: 50%; padding: 4px; font-size: 16px; }
</style>
`)
if err != nil {
@ -355,7 +355,7 @@ func (p *Proxy) ProcessUri(ctx *fasthttp.RequestCtx, requestURIStr string, redir
// Serve an intermediate page for protocols other than HTTP(S)
if (parsedURI.Scheme != "http" && parsedURI.Scheme != "https") || strings.HasSuffix(parsedURI.Host, ".onion") {
p.serveExitMortyPage(ctx, parsedURI)
p.serveExitYukariPage(ctx, parsedURI)
return
}
@ -397,7 +397,7 @@ func (p *Proxy) ProcessUri(ctx *fasthttp.RequestCtx, requestURIStr string, redir
loc := resp.Header.Peek("Location")
if loc != nil {
if p.FollowRedirect && ctx.IsGet() {
// GET method: Morty follows the redirect
// GET method: Yukari follows the redirect
if redirectCount < MAX_REDIRECT_COUNT {
if cfg.Debug {
log.Println("follow redirect to", string(loc))
@ -408,7 +408,7 @@ func (p *Proxy) ProcessUri(ctx *fasthttp.RequestCtx, requestURIStr string, redir
}
return
} else {
// Other HTTP methods: Morty does NOT follow the redirect
// Other HTTP methods: Yukari does NOT follow the redirect
rc := &RequestConfig{Key: p.Key, BaseURL: parsedURI}
url, err := rc.ProxifyURI(loc)
if err == nil {
@ -506,7 +506,7 @@ func (p *Proxy) ProcessUri(ctx *fasthttp.RequestCtx, requestURIStr string, redir
if !rc.BodyInjected {
p := HTMLBodyExtParam{rc.BaseURL.String(), false, cfg.UrlParameter}
if len(rc.Key) > 0 {
p.HasMortyKey = true
p.HasYukariKey = true
}
err := HTML_BODY_EXTENSION.Execute(ctx, p)
if err != nil {
@ -730,7 +730,7 @@ func sanitizeHTML(rc *RequestConfig, out io.Writer, htmlDoc []byte) {
case "body":
p := HTMLBodyExtParam{rc.BaseURL.String(), false, cfg.UrlParameter}
if len(rc.Key) > 0 {
p.HasMortyKey = true
p.HasYukariKey = true
}
err := HTML_BODY_EXTENSION.Execute(out, p)
if err != nil {
@ -978,7 +978,7 @@ func (rc *RequestConfig) ProxifyURI(uri []byte) (string, error) {
fragment = "#" + u.Fragment
}
// reset the fragment: it is not included in the mortyurl
// reset the fragment: it is not included in the yukariurl
u.Fragment = ""
// merge the URI with the document URI
@ -996,12 +996,12 @@ func (rc *RequestConfig) ProxifyURI(uri []byte) (string, error) {
}
// return full URI and fragment (if not empty)
morty_uri := u.String()
yukari_uri := u.String()
if rc.Key == nil {
return fmt.Sprintf("./?%s=%s%s", cfg.UrlParameter, url.QueryEscape(morty_uri), fragment), nil
return fmt.Sprintf("./?%s=%s%s", cfg.UrlParameter, url.QueryEscape(yukari_uri), fragment), nil
}
return fmt.Sprintf("./?%s=%s&%s=%s%s", cfg.HashParameter, hash(morty_uri, rc.Key), cfg.UrlParameter, url.QueryEscape(morty_uri), fragment), nil
return fmt.Sprintf("./?%s=%s&%s=%s%s", cfg.HashParameter, hash(yukari_uri, rc.Key), cfg.UrlParameter, url.QueryEscape(yukari_uri), fragment), nil
}
func inArray(b []byte, a [][]byte) bool {
@ -1033,23 +1033,23 @@ func verifyRequestURI(uri, hashMsg, key []byte) bool {
return hmac.Equal(h, mac.Sum(nil))
}
func (p *Proxy) serveExitMortyPage(ctx *fasthttp.RequestCtx, uri *url.URL) {
func (p *Proxy) serveExitYukariPage(ctx *fasthttp.RequestCtx, uri *url.URL) {
ctx.SetContentType("text/html")
ctx.SetStatusCode(403)
ctx.Write([]byte(MORTY_HTML_PAGE_START))
ctx.Write([]byte("<h2>You are about to exit MortyProxy</h2>"))
ctx.Write([]byte(YUKARI_HTML_PAGE_START))
ctx.Write([]byte("<h2>You are about to exit YukariSukima</h2>"))
ctx.Write([]byte("<p>Following</p><p><a href=\""))
ctx.Write([]byte(html.EscapeString(uri.String())))
ctx.Write([]byte("\" rel=\"noreferrer\">"))
ctx.Write([]byte(html.EscapeString(uri.String())))
ctx.Write([]byte("</a></p><p>the content of this URL will be <b>NOT</b> sanitized.</p>"))
ctx.Write([]byte(MORTY_HTML_PAGE_END))
ctx.Write([]byte(YUKARI_HTML_PAGE_END))
}
func (p *Proxy) serveMainPage(ctx *fasthttp.RequestCtx, statusCode int, err error) {
ctx.SetContentType("text/html; charset=UTF-8")
ctx.SetStatusCode(statusCode)
ctx.Write([]byte(MORTY_HTML_PAGE_START))
ctx.Write([]byte(YUKARI_HTML_PAGE_START))
if err != nil {
if cfg.Debug {
log.Println("error:", err)
@ -1069,7 +1069,7 @@ func (p *Proxy) serveMainPage(ctx *fasthttp.RequestCtx, statusCode int, err erro
} else {
ctx.Write([]byte(`<h3>Warning! This instance does not support direct URL opening.</h3>`))
}
ctx.Write([]byte(MORTY_HTML_PAGE_END))
ctx.Write([]byte(YUKARI_HTML_PAGE_END))
}
func main() {

View File

@ -27,17 +27,17 @@ var attrTestData []*AttrTestCase = []*AttrTestCase{
&AttrTestCase{
[]byte("href"),
[]byte("./x"),
[]byte(` href="./?mortyurl=http%3A%2F%2F127.0.0.1%2Fx"`),
[]byte(` href="./?yukariurl=http%3A%2F%2F127.0.0.1%2Fx"`),
},
&AttrTestCase{
[]byte("src"),
[]byte("http://x.com/y"),
[]byte(` src="./?mortyurl=http%3A%2F%2Fx.com%2Fy"`),
[]byte(` src="./?yukariurl=http%3A%2F%2Fx.com%2Fy"`),
},
&AttrTestCase{
[]byte("action"),
[]byte("/z"),
[]byte(` action="./?mortyurl=http%3A%2F%2F127.0.0.1%2Fz"`),
[]byte(` action="./?yukariurl=http%3A%2F%2F127.0.0.1%2Fz"`),
},
&AttrTestCase{
[]byte("onclick"),
@ -107,11 +107,11 @@ var sanitizeUriTestData []*SanitizeURITestCase = []*SanitizeURITestCase{
var urlTestData []*StringTestCase = []*StringTestCase{
&StringTestCase{
"http://x.com/",
"./?mortyurl=http%3A%2F%2Fx.com%2F",
"./?yukariurl=http%3A%2F%2Fx.com%2F",
},
&StringTestCase{
"http://a@x.com/",
"./?mortyurl=http%3A%2F%2Fa%40x.com%2F",
"./?yukariurl=http%3A%2F%2Fa%40x.com%2F",
},
&StringTestCase{
"#a",