Compare commits

...

28 commits

Author SHA1 Message Date
Zack
04ad1997a6
Create FUNDING.yml 2020-05-13 15:36:38 -07:00
Zack
caaed23f57
Merge pull request #14 from 0x333333/master
Fix a typo.
2019-07-20 09:07:42 -07:00
0x333
bdd0536998 Fix a typo. 2019-07-16 22:51:04 -07:00
Zack Scholl
47ef115491 fix handling of relative path 2019-07-15 08:58:40 -07:00
Zack Scholl
e98f05e6dc check it webkitRelativePath exists 2019-07-15 08:50:23 -07:00
Zack Scholl
ab215af53e fix dockerfile 2019-07-14 17:12:39 -06:00
Zack Scholl
3a62f092f1 add docker fixes #10 2019-07-14 17:02:32 -06:00
Zack Scholl
d34a5bca3f add Dockerfile 2019-07-14 16:58:44 -06:00
Zack
e96dfb99e7
Merge pull request #8 from dmuth/master
Added Homebrew installation instructions
2019-07-14 05:42:59 -07:00
Douglas Muth
b458bac63f Added Homebrew installation instructions 2019-07-13 14:28:46 -04:00
Zack Scholl
d74ce01023 bump 2019-07-12 21:38:01 -06:00
Zack Scholl
2804887a56 only request all files when index.html is not found at root 2019-07-12 16:37:55 -07:00
Zack Scholl
ef28306e6d more logging 2019-07-12 16:29:49 -07:00
Zack Scholl
d709d471be client servers file list
Fixes #7
2019-07-12 16:25:44 -07:00
Zack Scholl
479838af2a add file listing if nothing is found 2019-07-12 15:20:26 -07:00
Zack Scholl
78f06e76ca add file listing if nothing is found 2019-07-12 15:15:51 -07:00
Zack Scholl
3520f36f72 use fullpath if no webkitRelativePath 2019-07-12 14:33:10 -07:00
Zack Scholl
2670c964d1 bump 2019-07-12 09:51:18 -06:00
Zack Scholl
bd01535efa make the host run forever 2019-07-12 08:50:37 -07:00
Zack Scholl
8ff76da85e bug fix: browser reconnect after disconnect 2019-07-12 08:43:41 -07:00
Zack Scholl
66d39b9503 bug fix: attempt to get files with no extension 2019-07-12 08:52:07 -06:00
Zack Scholl
ef0758e07a bump 2019-07-12 08:15:06 -06:00
Zack Scholl
329667f3b6 Merge branch 'master' of github.com:schollz/hostyoself 2019-07-12 13:54:23 +00:00
Zack Scholl
6f31c5793f debug -> debugf 2019-07-12 13:54:19 +00:00
Zack
ec1ef5b442
Merge pull request #2 from DavidePastore/patch-1
Fix typos
2019-07-12 05:25:54 -07:00
Zack Scholl
ae6121a085 return nil from websocket error so no superfluos writes 2019-07-12 12:18:40 +00:00
Zack Scholl
79bf4213e4 fix superflous response 2019-07-12 12:11:07 +00:00
Davide Pastore
c0c267f5a1 "What's" instead of "Whats" 2019-07-12 12:55:22 +02:00
9 changed files with 261 additions and 24 deletions

3
.github/FUNDING.yml vendored Normal file
View file

@ -0,0 +1,3 @@
# These are supported funding model platforms
github: schollz

20
Dockerfile Normal file
View file

@ -0,0 +1,20 @@
###################################
# 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"]

View file

@ -4,7 +4,7 @@
<br>
<a
href="https://github.com/schollz/hostyoself/releases/latest"><img
src="https://img.shields.io/badge/version-0.0.2-brightgreen.svg?style=flat-square"
src="https://img.shields.io/badge/version-0.0.6-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,6 +32,18 @@ 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
@ -56,12 +68,14 @@ 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.
**Whats the largest file I can host using this?** `¯\_(ツ)_/¯`
**What's 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
View file

@ -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 a impromptu website"
app.UsageText = "use to transfer files or host an impromptu website"
app.Commands = []cli.Command{
{
Name: "relay",
@ -92,7 +92,15 @@ func host(c *cli.Context) (err error) {
if err != nil {
return
}
return cl.Run()
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)
}
}
func relay(c *cli.Context) (err error) {

View file

@ -1,6 +1,7 @@
package client
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
@ -10,6 +11,7 @@ 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"
@ -134,6 +136,31 @@ 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)
@ -195,6 +222,7 @@ 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()

View file

@ -1,6 +1,7 @@
package server
import (
"encoding/json"
"fmt"
"html/template"
"math/rand"
@ -79,7 +80,7 @@ Disallow:`))
var b []byte
b, err = Asset(r.URL.Path[1:])
if err != nil {
http.Error(w, "file not found", 404)
err = fmt.Errorf("resource '%s' not found", r.URL.Path[1:])
return
}
var contentType string
@ -168,6 +169,7 @@ 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
@ -176,11 +178,46 @@ Disallow:`))
pathToFile += "/"
}
pathToFile += "index.html"
log.Debugf("trying 2nd try to get: %s", pathToFile)
data, err = s.get(domain, pathToFile, ipAddress)
}
if err != nil {
log.Debug("problem getting: %s", err.Error())
return
// 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
}
}
}
}
@ -232,7 +269,8 @@ 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 {
return errUpgrade
log.Error(errUpgrade)
return nil
}
ws := wsconn.New(c)
@ -250,7 +288,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
return nil
}
domain := strings.Replace(strings.ToLower(strings.TrimSpace(p.Message)), " ", "-", -1)
@ -276,7 +314,10 @@ func (s *server) handleWebsocket(w http.ResponseWriter, r *http.Request) (err er
Message: domain,
Success: true,
})
return
if err != nil {
log.Error(err)
}
return nil
}
func (s *server) isdomain(domain string) bool {
@ -286,6 +327,69 @@ 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
View file

@ -48,13 +48,24 @@ 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 (files.length == 1) {
relativeDirectory = file.webkitRelativePath.split("/")[0];
} else if (file.webkitRelativePath.split("/")[0] != relativeDirectory) {
relativeDirectory = "";
if ("webkitRelativePath" in file) {
if (files.length == 1 && file.webkitRelativePath != "") {
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;
@ -121,12 +132,35 @@ const socketMessageListener = (event) => {
}
console.log(data)
consoleLog(`[debug] ${data.message}`)
if (data.type == "get") {
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") {
var foundFile = false
var iToSend = 0
for (i = 0; i < files.length; i++) {
if (files[i].webkitRelativePath == data.message || files[i].name == data.message || files[i]
.webkitRelativePath == relativeDirectory + "/" + data.message) {
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) {
iToSend = i;
var reader = new FileReader();
reader.onload = function(theFile) {
@ -164,6 +198,14 @@ 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 Normal file
View file

@ -0,0 +1,20 @@
<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
View file

@ -60,12 +60,10 @@
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>Whats the largest file I can host using this?</strong> <code>¯\_(ツ)_/¯</code></p>
<p><strong>What's 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 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>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>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>
@ -242,4 +240,4 @@
<script src="/static/main.js"></script>
</body>
</html>
</html>