Compare commits

...

22 commits

Author SHA1 Message Date
d6ac9af1c3
chore: go 1.24 and regen go.mod 2025-02-24 16:03:51 -08:00
ddvk
1b0cb6d5c1 add dev cloud urls 2024-12-15 15:33:18 +01:00
ddvk
665318f08b
Update README.md
typo
2024-11-23 09:04:14 +01:00
ddvk
d41cf0b79f
Update README.md
add simple instructions for rmpro
2024-11-23 09:02:57 +01:00
ddvk
8fc87780f1
Merge pull request #15 from ddvk/revert-14-add-apphost-com
Revert "Add host local.apphost.com"
2024-11-15 18:06:50 +01:00
ddvk
01ed34dc5e
Revert "Add host local.apphost.com" 2024-11-15 18:06:01 +01:00
ddvk
ce61af629c
Merge pull request #14 from innerand/add-apphost-com 2024-11-14 08:27:29 +01:00
Andreas Innerlohninger
1edf5ea4a9 Add host local.apphost.com 2024-11-10 16:04:10 +01:00
ddvk
45f7f5eff6
Merge pull request #13 from Esras/feature/add_rmpro_build_and_installer
Add RM Paper Pro Support
2024-10-07 18:22:51 +02:00
ddvk
ad06c390bb fix build 2024-10-07 14:05:44 +02:00
Esras
e5dec23cd6 Add back in original INSTALLER target for backwards compatability. 2024-10-05 17:24:34 -07:00
Esras
eb3d963a87 Add a new target for the RMPro installer to the Makefile and rearrange / rename some of the other variables to reflect multiple outputs. 2024-10-05 17:14:57 -07:00
ddvk
743a38c344 rename binary to rmfakecloud-proxy 2024-09-26 20:54:33 +02:00
Dobrin von Känel
3ddeb5ae39
Merge pull request #9 from Eeems/patch-1 2023-11-29 10:21:35 +01:00
Nathaniel van Diepen
2f208b01d6
Don't run sed if no metadata files are found 2023-11-28 16:45:06 -07:00
ddvk
fbd6f6f16a add new localhost address 2022-10-28 23:41:02 +02:00
ddvk
fce8ddfeb2 add more hosts 2022-04-06 21:18:56 +02:00
Dobrin von Känel
b137c369b0
Update README.md 2021-12-14 11:13:49 +01:00
ddvk
3c2bac1b29 add doc for config 2021-09-27 00:26:42 +02:00
ddvk
a6a59b1c3a tidy installer script 2021-09-27 00:09:46 +02:00
ddvk
83feb65863
Merge pull request #2 from matteodelabre/rewrite-host-header
Rewrite the Host header in forwarded requests
2021-09-26 22:38:44 +02:00
Mattéo Delabre
9ef79c874c
Rewrite the Host header in forwarded requests
The default httputil.NewSingleHostReverseProxy implementation does not rewrite the Host header in forwarded requests. So, the upstream server receives requests with the Host header set as the original reMarkable domain. In where a reverse proxy is used in front of rmfakecloud (as suggested [here](https://github.com/ddvk/rmfakecloud/blob/master/docs/https.md)), this can make the HTTP server confused especially if it is configured to serve several websites (in which case the Host header is used to differentiate requests).

This PR replaces the call to NewSingleHostReverseProxy with an implementation that rewrites the Host header (by assigning `req.Host`). This is essentially a copy/paste of the [original implementation](https://cs.opensource.google/go/go/+/refs/tags/go1.17.1:src/net/http/httputil/reverseproxy.go;drc=b7a85e0003cedb1b48a1fd3ae5b746ec6330102e;l=143) but with a new line added that does the rewrite. I don’t know if there’s a cleaner way to do this, and this may introduce licensing issues since the original source is BSD-licensed.
2021-09-26 19:43:03 +02:00
8 changed files with 202 additions and 69 deletions

1
.gitignore vendored
View file

@ -1 +1,2 @@
version.go version.go
dist/

2
.mise.toml Normal file
View file

@ -0,0 +1,2 @@
[tools]
golang = "1.24.0"

View file

@ -1,16 +1,37 @@
BINARY=dist/rmake-proxy ARMV7_BINARY=dist/rmfakecloud-proxy-arm7
AARCH64_BINARY=dist/rmfakecloud-proxy-aarch64
WIN_BINARY=dist/rmfakecloud-proxy.exe
LINUX_BINARY=dist/rmfakecloud-proxy64
INSTALLER=dist/installer.sh INSTALLER=dist/installer.sh
RM12_INSTALLER=dist/installer-rm12.sh
RMPRO_INSTALLER=dist/installer-rmpro.sh
.PHONY: clean .PHONY: clean
all: $(INSTALLER) all: $(RMPRO_INSTALLER) $(RM12_INSTALLER) $(INSTALLER) $(WIN_BINARY) $(LINUX_BINARY)
$(LINUX_BINARY): version.go main.go
go build -ldflags="-w -s" -o $@
$(ARMV7_BINARY): version.go main.go
GOARCH=arm GOARM=7 go build -ldflags="-w -s" -o $@
$(AARCH64_BINARY): version.go main.go
GOARCH=arm64 go build -ldflags="-w -s" -o $@
$(WIN_BINARY): version.go main.go
GOOS=windows go build -ldflags="-w -s" -o $@
$(BINARY): version.go
GOARCH=arm GOARM=7 go build -ldflags="-w -s" -o $(BINARY)
version.go: version.go:
go generate go generate
$(INSTALLER): $(BINARY) scripts/installer.sh $(RMPRO_INSTALLER): $(AARCH64_BINARY) scripts/installer.sh
cp scripts/installer.sh $@ cp scripts/installer.sh $@
gzip -c $(BINARY) >> $@ gzip -c $(AARCH64_BINARY) >> $@
chmod +x $@ chmod +x $@
$(INSTALLER) $(RM12_INSTALLER): $(ARMV7_BINARY) scripts/installer.sh
cp scripts/installer.sh $@
gzip -c $(ARMV7_BINARY) >> $@
chmod +x $@
clean: clean:
rm -fr dist rm -fr dist

View file

@ -3,22 +3,54 @@ Single-minded HTTPS reverse proxy
(forked from https://github.com/yi-jiayu/secure) (forked from https://github.com/yi-jiayu/secure)
## Installation
### Manual
Download `installer-rm12.sh` for rm1/2 or `installer-rmpro.sh` on a pc.
Transfer to the tablet with `scp` / `WinSCP`
run installer on the tablet over ssh
```
chmod +x installer-xxx.sh
./installer-xxx.sh
```
### Use toltec if supported
`opkg install rmfakecloud-proxy`
### rmpro
To make it permanent, make root writable and unmount /etc first e.g.
```
mount -o remount,rw /
umount -R /etc
./installer-rmpro.sh
```
## Usage ## Usage
``` ```
usage: secure [-addr host:port] -cert certfile -key keyfile upstream usage: rmfakecloud-proxy [-addr host:port] -cert certfile -key keyfile upstream
-addr string -addr string
listen address (default ":443") listen address (default ":443")
-cert string -cert string
path to cert file path to cert file
-key string -key string
path to key file path to key file
-c configfile
upstream string upstream string
upstream url upstream url
``` ```
### Example ### Example
``` ```
secure -cert cert.pem -key key.pem http://localhost:6060 rmfakecloud-proxy -cert cert.pem -key key.pem http://localhost:6060
```
## Configfile
```yaml
cert: proxy.crt
key: proxy.key
upstream: https://somehost:123
#addr: :443
``` ```

4
go.mod
View file

@ -1,5 +1,5 @@
module github.com/yi-jiayu/secure module github.com/yi-jiayu/secure
go 1.15 go 1.24
require gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b require gopkg.in/yaml.v3 v3.0.1

5
go.sum
View file

@ -1,3 +1,4 @@
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

75
main.go
View file

@ -7,8 +7,6 @@ import (
"context" "context"
"flag" "flag"
"fmt" "fmt"
"gopkg.in/yaml.v3"
"io/ioutil"
"log" "log"
"net/http" "net/http"
"net/http/httputil" "net/http/httputil"
@ -16,12 +14,16 @@ import (
"os" "os"
"os/signal" "os/signal"
"path/filepath" "path/filepath"
"strconv"
"strings"
"syscall" "syscall"
"gopkg.in/yaml.v3"
) )
type Config struct { type Config struct {
CertFile string `yaml:"certfile"` CertFile string `yaml:"cert"`
KeyFile string `yaml:"keyfile"` KeyFile string `yaml:"key"`
Upstream string `yaml:"upstream"` Upstream string `yaml:"upstream"`
Addr string `yaml:"addr"` Addr string `yaml:"addr"`
} }
@ -55,7 +57,7 @@ func getConfig() (config *Config, err error) {
if configFile != "" { if configFile != "" {
var data []byte var data []byte
data, err = ioutil.ReadFile(configFile) data, err = os.ReadFile(configFile)
if err != nil { if err != nil {
return return
@ -64,6 +66,10 @@ func getConfig() (config *Config, err error) {
if err != nil { if err != nil {
return nil, fmt.Errorf("cant parse config, %v", err) return nil, fmt.Errorf("cant parse config, %v", err)
} }
if _, err := strconv.Atoi(cfg.Addr); err == nil {
cfg.Addr = ":" + cfg.Addr
}
return &cfg, nil return &cfg, nil
} }
@ -77,20 +83,71 @@ func getConfig() (config *Config, err error) {
return &cfg, nil return &cfg, nil
} }
func singleJoiningSlash(a, b string) string {
aslash := strings.HasSuffix(a, "/")
bslash := strings.HasPrefix(b, "/")
switch {
case aslash && bslash:
return a + b[1:]
case !aslash && !bslash:
return a + "/" + b
}
return a + b
}
func joinURLPath(a, b *url.URL) (path, rawpath string) {
if a.RawPath == "" && b.RawPath == "" {
return singleJoiningSlash(a.Path, b.Path), ""
}
// Same as singleJoiningSlash, but uses EscapedPath to determine
// whether a slash should be added
apath := a.EscapedPath()
bpath := b.EscapedPath()
aslash := strings.HasSuffix(apath, "/")
bslash := strings.HasPrefix(bpath, "/")
switch {
case aslash && bslash:
return a.Path + b.Path[1:], apath + bpath[1:]
case !aslash && !bslash:
return a.Path + "/" + b.Path, apath + "/" + bpath
}
return a.Path + b.Path, apath + bpath
}
func _main() error { func _main() error {
cfg, err := getConfig() cfg, err := getConfig()
if err != nil { if err != nil {
return err return err
} }
u, err := url.Parse(cfg.Upstream) upstream, err := url.Parse(cfg.Upstream)
if err != nil { if err != nil {
return fmt.Errorf("invalid upstream address: %v", err) return fmt.Errorf("invalid upstream address: %v", err)
} }
rp := httputil.NewSingleHostReverseProxy(u) upstreamQuery := upstream.RawQuery
director := func(req *http.Request) {
req.URL.Scheme = upstream.Scheme
req.Host = upstream.Host
req.URL.Host = upstream.Host
req.URL.Path, req.URL.RawPath = joinURLPath(upstream, req.URL)
if upstreamQuery == "" || req.URL.RawQuery == "" {
req.URL.RawQuery = upstreamQuery + req.URL.RawQuery
} else {
req.URL.RawQuery = upstreamQuery + "&" + req.URL.RawQuery
}
if _, ok := req.Header["User-Agent"]; !ok {
// explicitly disable User-Agent so it's not set to default value
req.Header.Set("User-Agent", "")
}
}
srv := http.Server{ srv := http.Server{
Handler: rp, Handler: &httputil.ReverseProxy{
Director: director,
},
Addr: cfg.Addr, Addr: cfg.Addr,
} }
@ -106,7 +163,7 @@ func _main() error {
close(done) close(done)
}() }()
log.Printf("cert-file=%s key-file=%s listen-addr=%s upstream-url=%s", cfg.CertFile, cfg.KeyFile, srv.Addr, u.String()) log.Printf("cert-file=%s key-file=%s listen-addr=%s upstream-url=%s", cfg.CertFile, cfg.KeyFile, srv.Addr, upstream.String())
if err := srv.ListenAndServeTLS(cfg.CertFile, cfg.KeyFile); err != http.ErrServerClosed { if err := srv.ListenAndServeTLS(cfg.CertFile, cfg.KeyFile); err != http.ErrServerClosed {
return fmt.Errorf("ListenAndServeTLS: %v", err) return fmt.Errorf("ListenAndServeTLS: %v", err)
} }

View file

@ -1,15 +1,10 @@
#!/bin/bash #!/bin/bash
set -e set -e
UNIT_NAME=proxy UNIT_NAME=rmfakecloud-proxy
BINARY=rmfake-proxy BINARY=rmfakecloud-proxy
DESTINATION="/home/root/rmfakecloud" DESTINATION="/home/root/rmfakecloud"
echo ""
echo "rmFakeCloud proxy installer"
echo ""
# Create destination folder # Create destination folder
@ -24,28 +19,24 @@ function unpack(){
# marks all as unsynced so that they are not deleted # marks all as unsynced so that they are not deleted
function fixsync(){ function fixsync(){
grep sync ~/.local/share/remarkable/xochitl/*.metadata -l | xargs sed -i 's/synced\": true/synced\": false/' grep sync ~/.local/share/remarkable/xochitl/*.metadata -l | xargs -r sed -i 's/synced\": true/synced\": false/'
} }
function install_proxyservice(){ function install_proxyservice(){
cloudurl=$1 cloudurl=$1
echo "Setting cloud sync to: ${cloudurl}" echo "Setting cloud sync to: ${cloudurl}"
workdir=$DESTINATION workdir=$DESTINATION
cat > $workdir/proxy.cfg <<EOF
URL=
EOF
cat > /etc/systemd/system/${UNIT_NAME}.service <<EOF cat > /etc/systemd/system/${UNIT_NAME}.service <<EOF
[Unit] [Unit]
Description=reverse proxy Description=rmfakecloud reverse proxy
#StartLimitIntervalSec=600 #StartLimitIntervalSec=600
#StartLimitBurst=4 #StartLimitBurst=4
After=home.mount After=home.mount
[Service] [Service]
Environment=HOME=/home/root Environment=HOME=/home/root
#EnvironmentFile=$workdir/proxy.cfg
WorkingDirectory=$workdir WorkingDirectory=$workdir
ExecStart=$workdir/${BINARY} -cert $workdir/proxy.crt -key $workdir/proxy.key ${cloudurl} ExecStart=$workdir/${BINARY} -cert $workdir/proxy.bundle.crt -key $workdir/proxy.key ${cloudurl}
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target
@ -61,17 +52,18 @@ function uninstall(){
#rm proxy.key proxy.crt ca.crt ca.srl ca.key proxy.pubkey proxy.csr csr.conf proxy.cfg #rm proxy.key proxy.crt ca.crt ca.srl ca.key proxy.pubkey proxy.csr csr.conf proxy.cfg
rm /usr/local/share/ca-certificates/ca.crt rm /usr/local/share/ca-certificates/ca.crt
update-ca-certificates --fresh update-ca-certificates --fresh
rm /etc/systemd/system/proxy.service rm /etc/systemd/system/${UNIT_NAME}.service
sed -i '/# rmfake_start/,/# rmfake_end/d' /etc/hosts sed -i '/# rmfake_start/,/# rmfake_end/d' /etc/hosts
echo "Marking files as not synced to prevent data loss" echo "Marking files as not synced to prevent data loss"
echo "Stopping xochitl..."
systemctl stop xochitl
fixsync fixsync
rm -fr $DESTINATION rm -fr $DESTINATION
echo "You can restart xochitl now" echo "Restart xochitl for the changes to take effect"
} }
function generate_certificates(){ function generate_certificates(){
# thanks to https://gist.github.com/Soarez/9688998 # thanks to https://gist.github.com/Soarez/9688998
pushd $DESTINATION
cat <<EOF > csr.conf cat <<EOF > csr.conf
[ req ] [ req ]
@ -103,54 +95,57 @@ subjectAltName=@san
[ san ] [ san ]
DNS.1 = *.appspot.com DNS.1 = *.appspot.com
DNS.2 = my.remarkable.com DNS.2 = *.remarkable.com
DNS.3 = internal.cloud.remarkable.com DNS.3 = *.cloud.remarkable.com
DNS.4 = ping.remarkable.com DNS.4 = *.cloud.remarkable.engineering
DNS.5 = *.remarkable.com DNS.5 = *.rmfakecloud.localhost
# DNS.3 = any additional hosts DNS.6 = *.internal.cloud.remarkable.com
DNS.7 = *.tectonic.remarkable.com
DNS.8 = *.ping.remarkable.com
EOF EOF
# ca # ca
if [ ! -f ca.crt ]; then if [ ! -f ca.crt ]; then
echo "Generating ca..." echo "Generating CA key and crt..."
openssl genrsa -out ca.key 2048 openssl genrsa -out ca.key 2048
openssl req -new -sha256 -x509 -key ca.key -out ca.crt -days 3650 -subj /CN=rmfakecloud openssl req -new -sha256 -x509 -key ca.key -out ca.crt -days 3650 -subj /CN=rmfakecloud
rm proxy.key || true rm -f proxy.key
rm proxy.pubkey || true rm -f proxy.pubkey
else else
echo "CA exists" echo "CA exists"
fi fi
if [ ! -f proxy.key ]; then if [ ! -f proxy.key ]; then
echo "Generating proxy keys..." echo "Generating private key..."
openssl genrsa -out proxy.key 2048 openssl genrsa -out proxy.key 2048
rm proxy.pubkey || true rm -f proxy.pubkey
else else
echo "Private key exists" echo "Private key exists"
fi fi
if [ ! -f proxy.pubkey ]; then if [ ! -f proxy.pubkey ]; then
echo "Generating pub key..."
openssl rsa -in proxy.key -pubout -out proxy.pubkey openssl rsa -in proxy.key -pubout -out proxy.pubkey
rm proxy.crt || true rm -f proxy.crt
else else
echo "Pub key exists" echo "Pub key exists"
fi fi
if [ ! -f proxy.crt ]; then if [ ! -f proxy.crt ]; then
echo "Generating csr and crt..."
openssl req -new -config ./csr.conf -key proxy.key -out proxy.csr openssl req -new -config ./csr.conf -key proxy.key -out proxy.csr
# Signing # Signing
openssl x509 -req -in proxy.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out proxy.crt -days 3650 -extfile csr.conf -extensions caext openssl x509 -req -in proxy.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out proxy.crt -days 3650 -extfile csr.conf -extensions caext
#cat proxy.crt ca.crt > proxy.bundle.crt cat proxy.crt ca.crt > proxy.bundle.crt
echo "showing result" #echo "showing result"
#openssl x509 -in proxy.bundle.crt -text -noout #openssl x509 -in proxy.bundle.crt -text -noout
echo "Generation complete" echo "Generation complete!"
else else
echo "crt exists" echo "crt exists"
fi fi
popd
} }
function install_certificates(){ function install_certificates(){
@ -174,8 +169,12 @@ function patch_hosts(){
127.0.0.1 service-manager-production-dot-remarkable-production.appspot.com 127.0.0.1 service-manager-production-dot-remarkable-production.appspot.com
127.0.0.1 local.appspot.com 127.0.0.1 local.appspot.com
127.0.0.1 my.remarkable.com 127.0.0.1 my.remarkable.com
127.0.0.1 internal.cloud.remarkable.com
127.0.0.1 ping.remarkable.com 127.0.0.1 ping.remarkable.com
127.0.0.1 internal.cloud.remarkable.com
127.0.0.1 backtrace-proxy.cloud.remarkable.engineering
127.0.0.1 dev.ping.remarkable.com
127.0.0.1 dev.tectonic.remarkable.com
127.0.0.1 dev.internal.cloud.remarkable.com
# rmfake_end # rmfake_end
EOF EOF
fi fi
@ -183,21 +182,31 @@ EOF
} }
function getproxy(){ function getproxy(){
read -p "Enter your own cloud url: " url read -p "Enter your own cloud url [http(s)://somehost:port] >" url
echo $url echo $url
} }
function doinstall(){ function doinstall(){
echo "Extracting embedded binary..."
unpack unpack
pushd "${DESTINATION}"
generate_certificates generate_certificates
install_certificates install_certificates
# install proxy # install proxy
url=$1
if [ -z $url ]; then
url=$(getproxy) url=$(getproxy)
fi
install_proxyservice $url install_proxyservice $url
echo "Patching /etc/hosts"
patch_hosts patch_hosts
echo "Stoping xochitl.."
systemctl stop xochitl systemctl stop xochitl
echo "Fixing sync status..."
fixsync fixsync
echo "Starting xochitl..."
systemctl start xochitl systemctl start xochitl
popd
} }
@ -207,10 +216,15 @@ case $1 in
;; ;;
"install" ) "install" )
doinstall shift 1
doinstall $1
;; ;;
"setproxy" ) "gencert" )
generate_certificates
;;
"setcloud" )
shift 1 shift 1
url=$1 url=$1
if [ $# -lt 1 ]; then if [ $# -lt 1 ]; then
@ -220,16 +234,22 @@ case $1 in
;; ;;
* ) * )
cat <<EOF cat <<EOF
rmFakeCloud reverse proxy installer
Usage: Usage:
install install [cloudurl]
installs installs and asks for cloud url
uninstall uninstall
uninstall uninstall, removes everything
setproxy [cloudurl] gencert
generate certificates
setcloud [cloudurl]
changes the cloud address to changes the cloud address to
EOF EOF
@ -237,7 +257,6 @@ EOF
esac esac
# Exit from the script with success (0)
exit 0 exit 0
__ARCHIVE__ __ARCHIVE__