Compare commits

..

3 Commits

Author SHA1 Message Date
vxclutch
d18838dfee feat: share link 2026-05-28 08:25:59 -04:00
vxclutch
363c3b6c96 maint: comment source code 2026-05-28 07:55:10 -04:00
vxclutch
b436415980 feat: port flag 2026-05-28 07:44:33 -04:00
8 changed files with 56 additions and 9 deletions

5
TODO
View File

@@ -1,9 +1,6 @@
maint: clean up source code maint: clean up source code
maint: comment source code
maint: document more maint: document more
maint: make the colors more cross platform
feat: improve flags feat: improve flags
-p for port
feat: replace uuid dep with custom id generator feat: replace uuid dep with custom id generator
feat: multiple files feat: multiple files
feat: share link
maint: make the colors more cross platform

View File

@@ -7,11 +7,14 @@ import (
"lash" "lash"
"lash/internal/app" "lash/internal/app"
"lash/internal/errx" "lash/internal/errx"
share "lash/internal/shareLink"
"net/http" "net/http"
) )
var versionFlag = flag.Bool("version", false, "Print out version and exit.") var versionFlag = flag.Bool("version", false, "Print out version and exit.")
var port = flag.Int("p", 1337, "Set the port for LASH exchanges.")
func main() { func main() {
flag.Parse() flag.Parse()
@@ -22,10 +25,12 @@ func main() {
srv := app.New() srv := app.New()
// TODO(vxc): Make this more portable
errx.Log("Your share link is %s", share.GenerateShareLink(*port))
errx.Log("Your token is \033[1;92m%s\033[0m", lash.Token) errx.Log("Your token is \033[1;92m%s\033[0m", lash.Token)
errx.Log("starting server at http://0.0.0.0:1337") errx.Log("starting server at http://0.0.0.0:%d", *port)
if err := http.ListenAndServe(":1337", srv); err != nil { if err := http.ListenAndServe(fmt.Sprintf(":%d", *port), srv); err != nil {
errx.FatalPerror(err) errx.FatalPerror(err)
} }
} }

View File

@@ -2,14 +2,14 @@ package app
import ( import (
"errors" "errors"
"os" "flag"
"strings" "strings"
) )
func GetFilePath() (string, error) { func GetFilePath() (string, error) {
fp := "" fp := ""
for _, v := range os.Args[1:] { for _, v := range flag.Args() {
if !strings.HasPrefix(v, "-") { if !strings.HasPrefix(v, "-") {
fp = v fp = v
return fp, nil return fp, nil

View File

@@ -22,7 +22,7 @@ func New() http.Handler {
} }
share := handlers.ShareData{ share := handlers.ShareData{
Version: lash.Version, Version: lash.Version,
} }
file := handlers.FileData{ file := handlers.FileData{
@@ -32,6 +32,7 @@ func New() http.Handler {
mux.HandleFunc("/", share.Handler) mux.HandleFunc("/", share.Handler)
mux.HandleFunc("/api/receive-token", file.APIHandler) mux.HandleFunc("/api/receive-token", file.APIHandler)
mux.HandleFunc("/"+lash.ShareLinkToken, file.FileHandler)
return mux return mux
} }

View File

@@ -32,6 +32,17 @@ func (h FileData) APIHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
// Send the file over as a stream of bytes
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s", h.FileName))
w.Header().Set("Content-Type", "application/octet-stream")
w.Header().Set("Content-Length", strconv.Itoa(len(h.Contents)))
w.WriteHeader(http.StatusOK)
w.Write(h.Contents)
}
func (h FileData) FileHandler(w http.ResponseWriter, r *http.Request) {
// Send the file over as a stream of bytes
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s", h.FileName)) w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s", h.FileName))
w.Header().Set("Content-Type", "application/octet-stream") w.Header().Set("Content-Type", "application/octet-stream")
w.Header().Set("Content-Length", strconv.Itoa(len(h.Contents))) w.Header().Set("Content-Length", strconv.Itoa(len(h.Contents)))

View File

@@ -13,6 +13,7 @@ type ShareData struct {
} }
func (h *ShareData) Handler(w http.ResponseWriter, r *http.Request) { func (h *ShareData) Handler(w http.ResponseWriter, r *http.Request) {
// Although `Must` can fail since `Templates` is embeded these files will always exist.
tmpl := template.Must(template.ParseFS(lash.Templates, "templates/share.html")) tmpl := template.Must(template.ParseFS(lash.Templates, "templates/share.html"))
if err := tmpl.ExecuteTemplate(w, "share.html", h); err != nil { if err := tmpl.ExecuteTemplate(w, "share.html", h); err != nil {

View File

@@ -0,0 +1,29 @@
package sharelink
import (
"fmt"
"lash"
"lash/internal/errx"
"net"
)
func GenerateShareLink(port int) string {
link := "http://"
link += getLocalIP()
link += fmt.Sprintf(":%d", port)
link += "/"
link += lash.ShareLinkToken
return link
}
func getLocalIP() string {
conn, err := net.Dial("udp", "8.8.8.8:80")
if err != nil {
errx.FatalPerror(err)
}
defer conn.Close()
localAddress := conn.LocalAddr().(*net.UDPAddr)
return localAddress.IP.String()
}

View File

@@ -12,4 +12,7 @@ var Templates embed.FS
//go:embed version //go:embed version
var Version string var Version string
// TODO(vxc): Replace this with custom token generator
var Token string = uuid.New().String() var Token string = uuid.New().String()
var ShareLinkToken string = uuid.New().String()