mirror of
https://github.com/schollz/hostyoself.git
synced 2026-01-23 18:35:09 +00:00
Compare commits
No commits in common. "master" and "v0.0.3" have entirely different histories.
9 changed files with 24 additions and 261 deletions
3
.github/FUNDING.yml
vendored
3
.github/FUNDING.yml
vendored
|
|
@ -1,3 +0,0 @@
|
|||
# These are supported funding model platforms
|
||||
|
||||
github: schollz
|
||||
20
Dockerfile
20
Dockerfile
|
|
@ -1,20 +0,0 @@
|
|||
###################################
|
||||
# 1. Build in a Go-based image #
|
||||
###################################
|
||||
FROM golang:1.12-alpine as builder
|
||||
RUN apk add --no-cache git ca-certificates # add deps here (like make) if needed
|
||||
WORKDIR /go/hostyoself
|
||||
COPY . .
|
||||
# any pre-requisities to building should be added here
|
||||
RUN go generate -v
|
||||
RUN go build -v
|
||||
|
||||
###################################
|
||||
# 2. Copy into a clean image #
|
||||
###################################
|
||||
FROM alpine:latest
|
||||
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
|
||||
COPY --from=builder /go/hostyoself/hostyoself /hostyoself
|
||||
VOLUME /data
|
||||
CMD ["sh","-c","/hostyoself host --folder /data"]
|
||||
|
||||
18
README.md
18
README.md
|
|
@ -4,7 +4,7 @@
|
|||
<br>
|
||||
<a
|
||||
href="https://github.com/schollz/hostyoself/releases/latest"><img
|
||||
src="https://img.shields.io/badge/version-0.0.6-brightgreen.svg?style=flat-square"
|
||||
src="https://img.shields.io/badge/version-0.0.2-brightgreen.svg?style=flat-square"
|
||||
alt="Version"></a> </p>
|
||||
|
||||
<p align="center">A hosting service from the browser, because why not. Try it at <a href="https://hostyoself.com">hostyoself.com</a>.</p>
|
||||
|
|
@ -32,18 +32,6 @@ https://hostyoself.com/confidentcat/
|
|||
|
||||
Now if you have a file in your folder `README.md` you can access it with the public URL `https://hostyoself.com/confidentcat/README.md`, directly from your computer!
|
||||
|
||||
If you're on a Mac, you can install with Homebrew:
|
||||
|
||||
```
|
||||
brew tap schollz/homebrew https://github.com/schollz/homebrew-tap.git
|
||||
brew install hostyoself
|
||||
```
|
||||
|
||||
Or you can host your current directory using Docker:
|
||||
|
||||
```
|
||||
$ docker run -v `pwd`:/data schollz/hostyoself
|
||||
```
|
||||
|
||||
## Run your own relay
|
||||
|
||||
|
|
@ -68,14 +56,12 @@ Just *kidding*! You don't need any of that crap. Just goto [hostyoself.com](http
|
|||
|
||||
**Won't I have to reload my browser if I change a file?** Yep! Welcome to the joys of Javascript.
|
||||
|
||||
**What's the largest file I can host using this?** `¯\_(ツ)_/¯`
|
||||
**Whats the largest file I can host using this?** `¯\_(ツ)_/¯`
|
||||
|
||||
**Should I use this to host a website?** Dear god yes.
|
||||
|
||||
**Does this use AI or blockchain?** Sure, why not.
|
||||
|
||||
**Does it scale?** Horizontally, or vertically? Probably neither!
|
||||
|
||||
**What inspired this?** [beaker browser](https://beakerbrowser.com/), [ngrok](https://ngrok.com/), [localhost.run](http://localhost.run/), [inlets.dev](https://github.com/alexellis/inlets), Parks and Recreation.
|
||||
|
||||
**What's the point of this?** You can host a website! You can share a file! Anything you want, directly from your browser!
|
||||
|
|
|
|||
12
main.go
12
main.go
|
|
@ -34,7 +34,7 @@ func main() {
|
|||
app.Version = Version
|
||||
app.Compiled = time.Now()
|
||||
app.Usage = "host your files using websockets from the command line or a browser"
|
||||
app.UsageText = "use to transfer files or host an impromptu website"
|
||||
app.UsageText = "use to transfer files or host a impromptu website"
|
||||
app.Commands = []cli.Command{
|
||||
{
|
||||
Name: "relay",
|
||||
|
|
@ -92,15 +92,7 @@ func host(c *cli.Context) (err error) {
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
for {
|
||||
log.Info("serving forever")
|
||||
err = cl.Run()
|
||||
if err != nil {
|
||||
log.Debug(err)
|
||||
}
|
||||
log.Infof("server disconnected, retrying in 10 seconds")
|
||||
time.Sleep(10 * time.Second)
|
||||
}
|
||||
return cl.Run()
|
||||
}
|
||||
|
||||
func relay(c *cli.Context) (err error) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
|
@ -11,7 +10,6 @@ import (
|
|||
"sync"
|
||||
|
||||
"github.com/schollz/hostyoself/pkg/namesgenerator"
|
||||
"github.com/schollz/hostyoself/pkg/server"
|
||||
"github.com/schollz/hostyoself/pkg/utils"
|
||||
"github.com/schollz/hostyoself/pkg/wsconn"
|
||||
|
||||
|
|
@ -136,31 +134,6 @@ func (c *client) Run() (err error) {
|
|||
})
|
||||
log.Infof("%s /%s 200", p.IPAddress, p.Message)
|
||||
}
|
||||
} else if p.Type == "files" {
|
||||
c.Lock()
|
||||
fs := make([]server.File, len(c.fileList))
|
||||
i := 0
|
||||
for n := range c.fileList {
|
||||
fs[i] = server.File{
|
||||
FullPath: n,
|
||||
Upload: server.Upload{
|
||||
UUID: "",
|
||||
Total: 0,
|
||||
Filename: "",
|
||||
},
|
||||
}
|
||||
i++
|
||||
}
|
||||
c.Unlock()
|
||||
|
||||
b, _ := json.Marshal(fs)
|
||||
log.Infof("%s sitemap", p.IPAddress)
|
||||
err = ws.Send(wsconn.Payload{
|
||||
Type: "files",
|
||||
Success: true,
|
||||
Message: string(b),
|
||||
Key: c.Key,
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
log.Debug(err)
|
||||
|
|
@ -222,7 +195,6 @@ func (c *client) watchFileSystem() (err error) {
|
|||
} else {
|
||||
ppath, _ = filepath.Abs(ppath)
|
||||
ppath = strings.TrimPrefix(filepath.ToSlash(ppath), c.Folder+"/")
|
||||
log.Debugf("%s", ppath)
|
||||
c.Lock()
|
||||
c.fileList[ppath] = struct{}{}
|
||||
c.Unlock()
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"math/rand"
|
||||
|
|
@ -80,7 +79,7 @@ Disallow:`))
|
|||
var b []byte
|
||||
b, err = Asset(r.URL.Path[1:])
|
||||
if err != nil {
|
||||
err = fmt.Errorf("resource '%s' not found", r.URL.Path[1:])
|
||||
http.Error(w, "file not found", 404)
|
||||
return
|
||||
}
|
||||
var contentType string
|
||||
|
|
@ -169,7 +168,6 @@ Disallow:`))
|
|||
|
||||
// send GET request to websockets
|
||||
var data string
|
||||
var fs []File
|
||||
data, err = s.get(domain, pathToFile, ipAddress)
|
||||
if err != nil {
|
||||
// try index.html if it doesn't exist
|
||||
|
|
@ -178,46 +176,11 @@ Disallow:`))
|
|||
pathToFile += "/"
|
||||
}
|
||||
pathToFile += "index.html"
|
||||
log.Debugf("trying 2nd try to get: %s", pathToFile)
|
||||
data, err = s.get(domain, pathToFile, ipAddress)
|
||||
}
|
||||
if err != nil {
|
||||
// try one more time
|
||||
if strings.HasSuffix(pathToFile, "/index.html") {
|
||||
pathToFile = strings.TrimSuffix(pathToFile, "/index.html")
|
||||
log.Debugf("trying 3rd try to get: %s", pathToFile)
|
||||
data, err = s.get(domain, pathToFile, ipAddress)
|
||||
}
|
||||
if err != nil {
|
||||
if pathToFile == "index.html" {
|
||||
// just serve files
|
||||
fs, err = s.getFiles(domain, ipAddress)
|
||||
log.Debugf("fs: %+v", fs)
|
||||
if err != nil {
|
||||
log.Debug(err)
|
||||
return
|
||||
}
|
||||
|
||||
b, _ := Asset("templates/files.html")
|
||||
var t *template.Template
|
||||
t, err = template.New("files").Parse(string(b))
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
return t.Execute(w, struct {
|
||||
Files []File
|
||||
Domain string
|
||||
}{
|
||||
Domain: domain,
|
||||
Files: fs,
|
||||
})
|
||||
} else {
|
||||
log.Debugf("problem getting: %s", err.Error())
|
||||
err = fmt.Errorf("not found")
|
||||
return
|
||||
}
|
||||
}
|
||||
log.Debug("problem getting: %s", err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -269,8 +232,7 @@ func (s *server) handleWebsocket(w http.ResponseWriter, r *http.Request) (err er
|
|||
// handle websockets on this page
|
||||
c, errUpgrade := wsupgrader.Upgrade(w, r, nil)
|
||||
if errUpgrade != nil {
|
||||
log.Error(errUpgrade)
|
||||
return nil
|
||||
return errUpgrade
|
||||
}
|
||||
ws := wsconn.New(c)
|
||||
|
||||
|
|
@ -288,7 +250,7 @@ func (s *server) handleWebsocket(w http.ResponseWriter, r *http.Request) (err er
|
|||
err = fmt.Errorf("got wrong type/domain: %s/%s", p.Type, p.Message)
|
||||
log.Debug(err)
|
||||
ws.Close()
|
||||
return nil
|
||||
return
|
||||
}
|
||||
|
||||
domain := strings.Replace(strings.ToLower(strings.TrimSpace(p.Message)), " ", "-", -1)
|
||||
|
|
@ -314,10 +276,7 @@ func (s *server) handleWebsocket(w http.ResponseWriter, r *http.Request) (err er
|
|||
Message: domain,
|
||||
Success: true,
|
||||
})
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
return nil
|
||||
return
|
||||
}
|
||||
|
||||
func (s *server) isdomain(domain string) bool {
|
||||
|
|
@ -327,69 +286,6 @@ func (s *server) isdomain(domain string) bool {
|
|||
return ok
|
||||
}
|
||||
|
||||
type File struct {
|
||||
FullPath string `json:"fullPath"`
|
||||
Upload Upload `json:"upload"`
|
||||
}
|
||||
type Upload struct {
|
||||
UUID string `json:"uuid"`
|
||||
Total int `json:"total"`
|
||||
Filename string `json:"filename"`
|
||||
}
|
||||
|
||||
func (s *server) getFiles(domain, ipAddress string) (fs []File, err error) {
|
||||
var connections []*connection
|
||||
s.Lock()
|
||||
if _, ok := s.conn[domain]; ok {
|
||||
connections = s.conn[domain]
|
||||
}
|
||||
s.Unlock()
|
||||
if connections == nil || len(connections) == 0 {
|
||||
err = fmt.Errorf("no connections available for domain %s", domain)
|
||||
log.Debug(err)
|
||||
return
|
||||
}
|
||||
log.Debugf("requesting files of %s from %d connections", domain, len(connections))
|
||||
|
||||
// any connection that initated with this key is viable
|
||||
key := connections[0].Key
|
||||
|
||||
// loop through connections randomly and try to get one to serve the file
|
||||
for _, i := range rand.Perm(len(connections)) {
|
||||
var p wsconn.Payload
|
||||
p, err = func() (p wsconn.Payload, err error) {
|
||||
err = connections[i].ws.Send(wsconn.Payload{
|
||||
Type: "files",
|
||||
Message: "all",
|
||||
IPAddress: ipAddress,
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
p, err = connections[i].ws.Receive()
|
||||
return
|
||||
}()
|
||||
if err != nil {
|
||||
log.Debug(err)
|
||||
s.dumpConnection(domain, connections[i].ID)
|
||||
continue
|
||||
}
|
||||
log.Tracef("recv: %+v", p)
|
||||
if p.Type == "files" && p.Key == key {
|
||||
if !p.Success {
|
||||
err = fmt.Errorf(p.Message)
|
||||
return
|
||||
}
|
||||
|
||||
err = json.Unmarshal([]byte(p.Message), &fs)
|
||||
return
|
||||
}
|
||||
log.Debugf("no good data from %d", i)
|
||||
}
|
||||
err = fmt.Errorf("invalid response")
|
||||
return
|
||||
}
|
||||
|
||||
func (s *server) get(domain, filePath, ipAddress string) (payload string, err error) {
|
||||
var connections []*connection
|
||||
s.Lock()
|
||||
|
|
|
|||
58
static/main.js
vendored
58
static/main.js
vendored
|
|
@ -48,24 +48,13 @@ var filesize = 0;
|
|||
|
||||
drop.on('addedfile', function(file) {
|
||||
// console.log(file);
|
||||
var domain = document.getElementById("inputDomain").value;
|
||||
var domain = document.getElementById("inputDomain").value
|
||||
files.push(file);
|
||||
if ("webkitRelativePath" in file) {
|
||||
if (files.length == 1 && file.webkitRelativePath != "") {
|
||||
relativeDirectory = file.webkitRelativePath.split("/")[0];
|
||||
} else if (file.webkitRelativePath.split("/")[0] != relativeDirectory) {
|
||||
relativeDirectory = "";
|
||||
}
|
||||
if (files.length == 1) {
|
||||
relativeDirectory = file.webkitRelativePath.split("/")[0];
|
||||
} else if (file.webkitRelativePath.split("/")[0] != relativeDirectory) {
|
||||
relativeDirectory = "";
|
||||
}
|
||||
if ("fullPath" in file) {
|
||||
if (files.length == 1 && file.fullPath != "") {
|
||||
relativeDirectory = file.fullPath.split("/")[0];
|
||||
} else if (file.fullPath.split("/")[0] != relativeDirectory) {
|
||||
relativeDirectory = "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (!(isConnected)) {
|
||||
isConnected = true;
|
||||
|
|
@ -132,35 +121,12 @@ const socketMessageListener = (event) => {
|
|||
}
|
||||
console.log(data)
|
||||
consoleLog(`[debug] ${data.message}`)
|
||||
if (data.type == "files") {
|
||||
if (files.length > 0) {
|
||||
socketSend({
|
||||
type: "files",
|
||||
message: JSON.stringify(files),
|
||||
success: true,
|
||||
key: document.getElementById("inputKey").value,
|
||||
});
|
||||
consoleLog(
|
||||
`${data.ip} [${(new Date()).toUTCString()}] sitemap 200`
|
||||
);
|
||||
} else {
|
||||
socketSend({
|
||||
type: "files",
|
||||
message: "none found",
|
||||
success: false,
|
||||
key: document.getElementById("inputKey").value,
|
||||
});
|
||||
consoleLog(
|
||||
`${data.ip} [${(new Date()).toUTCString()}] sitemap 404`
|
||||
);
|
||||
}
|
||||
} else if (data.type == "get") {
|
||||
if (data.type == "get") {
|
||||
var foundFile = false
|
||||
var iToSend = 0
|
||||
for (i = 0; i < files.length; i++) {
|
||||
if (files[i].webkitRelativePath == data.message || files[i].fullPath == data.message || files[i].name == data.message || files[i]
|
||||
.webkitRelativePath == relativeDirectory + "/" + data.message || files[i]
|
||||
.fullPath == relativeDirectory + "/" + data.message) {
|
||||
if (files[i].webkitRelativePath == data.message || files[i].name == data.message || files[i]
|
||||
.webkitRelativePath == relativeDirectory + "/" + data.message) {
|
||||
iToSend = i;
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(theFile) {
|
||||
|
|
@ -198,14 +164,6 @@ const socketMessageListener = (event) => {
|
|||
};
|
||||
const socketOpenListener = (event) => {
|
||||
consoleLog('[info] connected');
|
||||
if (isConnected == true) {
|
||||
// reconnect if was connected and got disconnected
|
||||
socketSend({
|
||||
type: "domain",
|
||||
message: document.getElementById("inputDomain").value,
|
||||
key: document.getElementById("inputKey").value,
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
const socketCloseListener = (event) => {
|
||||
|
|
|
|||
20
templates/files.html
vendored
20
templates/files.html
vendored
|
|
@ -1,20 +0,0 @@
|
|||
<html>
|
||||
|
||||
<head>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<ul>
|
||||
{{range .Files}}
|
||||
<li>
|
||||
{{ if .FullPath }}
|
||||
<a href="/{{$.Domain}}/{{.FullPath}}">{{.FullPath}}</a>
|
||||
{{else}}
|
||||
<a href="/{{$.Domain}}/{{.Upload.Filename}}">{{.Upload.Filename}}</a>
|
||||
{{end}}
|
||||
</li>
|
||||
{{end}}
|
||||
</ul>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
10
templates/view.html
vendored
10
templates/view.html
vendored
|
|
@ -60,10 +60,12 @@
|
|||
computer turns off then your site is down. Welcome to the joys of hosting a site on the internet.</p>
|
||||
<p><strong>Won't I have to reload my browser if I change a file?</strong> Yep! Welcome to the joys of
|
||||
Javascript.</p>
|
||||
<p><strong>What's the largest file I can host using this?</strong> <code>¯\_(ツ)_/¯</code></p>
|
||||
<p><strong>Whats the largest file I can host using this?</strong> <code>¯\_(ツ)_/¯</code></p>
|
||||
<p><strong>Should I use this to host a website?</strong> Dear god yes.</p>
|
||||
<p><strong>Does it scale?</strong> Horizontally, or vertically? Probably neither!</p>
|
||||
<p><strong>What inspired this?</strong> <a href="https://beakerbrowser.com/">beaker browser</a>, <a href="https://ngrok.com/">ngrok</a>, <a href="http://localhost.run/">localhost.run</a>, <a href="https://github.com/alexellis/inlets">inlets.dev</a>, Parks and Recreation.</p>
|
||||
<p><strong>Does this use AI or blockchain?</strong> Sure, why not. </p>
|
||||
<p><strong>What inspired this?</strong> <a href="https://github.com/joewalnes/websocketd">websocketd</a>
|
||||
which shows the magic of websockets and <a href="https://beakerbrowser.com/">beaker browser</a> which
|
||||
shows the magic of browser hosting.</p>
|
||||
<p><strong>What's the point of this?</strong> You can host a website! You can share a file! Anything you
|
||||
want, directly from your browser!</p>
|
||||
<p>
|
||||
|
|
@ -240,4 +242,4 @@
|
|||
<script src="/static/main.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
Loading…
Add table
Add a link
Reference in a new issue