Merge pull request #6 from grufwub/development

Bump to 0.2-alpha
master
Kim 4 years ago committed by GitHub
commit 5ad8a97721
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -9,9 +9,9 @@ Linux only _for now_. Cross-compiled to way too many architectures. Don't
judge my build script, it's not easy on the eyes, I'll fix it when I can be
bothered...
I'm unemployed (not due to lack of effort...) and work on open-source projects
like this and many others for free. If you would like to help support my work
that would be hugely appreciated 💕 https://liberapay.com/grufwub/
I'm unemployed and work on open-source projects like this and many others for
free. If you would like to help support my work that would be hugely
appreciated 💕 https://liberapay.com/grufwub/
WARNING: the development branch is filled with lava, fear and capitalism.
@ -35,7 +35,7 @@ gophor [args]
files from showing in directory listing.
-description Change server description in auto generated caps.txt.
-admin-email Change admin email in auto generated caps.txt.
-geloc Change geolocation in auto generated caps.txt.
-geoloc Change geolocation in auto generated caps.txt.
```
# Features
@ -211,6 +211,8 @@ Shortterm:
- Improve autogenerated policy file sending -- need to rethink the worker +
response logic.
- Add to file extesion --> item type map
Longterm:
- TLS support -- requires a rethink of how we're passing port functions

@ -0,0 +1,6 @@
#!/bin/sh
echo "Building for current platform..."
CGO_ENABLED=1 go build -trimpath -o 'gophor' -buildmode 'pie' -a -tags 'netgo' -ldflags '-s -w -extldflags "-static"'
upx --best --color 'gophor'
echo ""

@ -2,7 +2,7 @@ package main
const (
/* Gophor */
GophorVersion = "0.1-alpha"
GophorVersion = "0.2-alpha"
/* Parsing */
DOSLineEnd = "\r\n"
@ -43,48 +43,47 @@ const (
type ItemType byte
const (
/* RFC 1436 Standard */
TypeFile = ItemType('0') /* Regular file [TEXT] */
TypeDirectory = ItemType('1') /* Directory [MENU] */
TypePhonebook = ItemType('2') /* CSO phone-book server */
TypeError = ItemType('3') /* Error [ERROR] */
TypeMacBinHex = ItemType('4') /* Binhexed macintosh file */
TypeDosBinArchive = ItemType('5') /* DOS bin archive, CLIENT MUST READ UNTIL TCP CLOSE [GZIP] */
TypeUnixFile = ItemType('6') /* Unix uuencoded file */
TypeIndexSearch = ItemType('7') /* Index-search server [QUERY] */
TypeTelnet = ItemType('8') /* Text-based telnet session */
TypeBin = ItemType('9') /* Binary file, CLIENT MUST READ UNTIL TCP CLOSE [BINARY] */
TypeTn3270 = ItemType('T') /* Text-based tn3270 session */
TypeGif = ItemType('g') /* Gif format graphics file [GIF] */
TypeImage = ItemType('I') /* Some kind of image file (client decides how to display) [IMAGE] */
TypeRedundant = ItemType('+') /* Redundant server */
TypeEnd = ItemType('.') /* Indicates LastLine if only this + CrLf */
/* Non-standard - as used by https://github.com/prologic/go-gopher
* (also seen on Wikipedia: https://en.wikipedia.org/wiki/Gopher_%28protocol%29#Item_types)
*/
TypeInfo = ItemType('i') /* Informational message [INFO] */
TypeHtml = ItemType('h') /* HTML document [HTML] */
TypeAudio = ItemType('s') /* Audio file */
TypePng = ItemType('p') /* PNG image */
TypeDoc = ItemType('d') /* Document [DOC] */
/* Non-standard - as used by Gopernicus https://github.com/gophernicus/gophernicus */
TypeMime = ItemType('M') /* [MIME] */
TypeVideo = ItemType(';') /* [VIDEO] */
TypeCalendar = ItemType('c') /* [CALENDAR] */
TypeTitle = ItemType('!') /* [TITLE] */
TypeComment = ItemType('#') /* [COMMENT] */
TypeHiddenFile = ItemType('-') /* [HIDDEN] Hides file from directory listing */
TypeSubGophermap = ItemType('=') /* [EXECUTE] read this file in here */
TypeEndBeginList = ItemType('*') /* If only this + CrLf, indicates last line but then followed by directory list */
TypeFile = ItemType('0') /* Regular file (text) */
TypeDirectory = ItemType('1') /* Directory (menu) */
TypeDatabase = ItemType('2') /* CCSO flat db; other db */
TypeError = ItemType('3') /* Error message */
TypeMacBinHex = ItemType('4') /* Macintosh BinHex file */
TypeBinArchive = ItemType('5') /* Binary archive (zip, rar, 7zip, tar, gzip, etc), CLIENT MUST READ UNTIL TCP CLOSE */
TypeUUEncoded = ItemType('6') /* UUEncoded archive */
TypeSearch = ItemType('7') /* Query search engine or CGI script */
TypeTelnet = ItemType('8') /* Telnet to: VT100 series server */
TypeBin = ItemType('9') /* Binary file (see also, 5), CLIENT MUST READ UNTIL TCP CLOSE */
TypeTn3270 = ItemType('T') /* Telnet to: tn3270 series server */
TypeGif = ItemType('g') /* GIF format image file (just use I) */
TypeImage = ItemType('I') /* Any format image file */
TypeRedundant = ItemType('+') /* Redundant (indicates mirror of previous item) */
/* GopherII Standard */
TypeCalendar = ItemType('c') /* Calendar file */
TypeDoc = ItemType('d') /* Word-processing document; PDF document */
TypeHtml = ItemType('h') /* HTML document */
TypeInfo = ItemType('i') /* Informational text (not selectable) */
TypeMarkup = ItemType('p') /* Page layout or markup document (plain text w/ ASCII tags) */
TypeMail = ItemType('M') /* Email repository (MBOX) */
TypeAudio = ItemType('s') /* Audio recordings */
TypeXml = ItemType('x') /* eXtensible Markup Language document */
TypeVideo = ItemType(';') /* Video files */
/* Commonly Used */
TypeTitle = ItemType('!') /* [SERVER ONLY] Menu title (set title ONCE per gophermap) */
TypeComment = ItemType('#') /* [SERVER ONLY] Comment, rest of line is ignored */
TypeHiddenFile = ItemType('-') /* [SERVER ONLY] Hide file/directory from directory listing */
TypeEnd = ItemType('.') /* [SERVER ONLY] Last line -- stop processing gophermap default */
TypeSubGophermap = ItemType('=') /* [SERVER ONLY] Include subgophermap / regular file here. */
TypeEndBeginList = ItemType('*') /* [SERVER ONLY] Last line + directory listing -- stop processing gophermap and end on a directory listing */
/* Planned To Be Supported */
TypeExec = ItemType('$') /* [SERVER ONLY] Execute shell command and print stdout here */
/* Default type */
TypeDefault = TypeBin
/* Gophor specific types */
TypeExec = ItemType('$') /* Execute command and insert stdout here */
TypeInfoNotStated = ItemType('z') /* INTERNAL USE. We use this in a switch case, a line never starts with this */
TypeUnknown = ItemType('?') /* INTERNAL USE. We use this in a switch case, a line never starts with this */
TypeInfoNotStated = ItemType('z') /* [INTERNAL USE] */
TypeUnknown = ItemType('?') /* [INTERNAL USE] */
)

@ -1,25 +0,0 @@
package main
/* RegularFileContents:
* Very simple implementation of FileContents that just
* buffered reads from the stored file path, stores the
* read bytes in a slice and returns when requested.
*/
type RegularFileContents struct {
path string
contents []byte
}
func (fc *RegularFileContents) Render() []byte {
return fc.contents
}
func (fc *RegularFileContents) Load() *GophorError {
var gophorErr *GophorError
fc.contents, gophorErr = bufferedRead(fc.path)
return gophorErr
}
func (fc *RegularFileContents) Clear() {
fc.contents = nil
}

@ -6,6 +6,30 @@ import (
"strings"
)
/* RegularFileContents:
* Very simple implementation of FileContents that just
* buffered reads from the stored file path, stores the
* read bytes in a slice and returns when requested.
*/
type RegularFileContents struct {
path string
contents []byte
}
func (fc *RegularFileContents) Render() []byte {
return fc.contents
}
func (fc *RegularFileContents) Load() *GophorError {
var gophorErr *GophorError
fc.contents, gophorErr = bufferedRead(fc.path)
return gophorErr
}
func (fc *RegularFileContents) Clear() {
fc.contents = nil
}
/* GophermapContents:
* Implementation of FileContents that reads and
* parses a gophermap file into a slice of gophermap

@ -5,53 +5,64 @@ import (
"strings"
)
var SingleFileExtMap = map[string]ItemType{
".out": TypeBin,
".a": TypeBin,
".o": TypeBin,
".ko": TypeBin, /* ... Though tbh, kernel extensions?!!! */
".msi": TypeBin,
".exe": TypeBin,
".txt": TypeFile,
".md": TypeFile,
".json": TypeFile,
".xml": TypeFile,
".yaml": TypeFile,
".ocaml": TypeFile,
".s": TypeFile,
".c": TypeFile,
".py": TypeFile,
".h": TypeFile,
".go": TypeFile,
".fs": TypeFile,
".doc": TypeDoc,
".docx": TypeDoc,
".gif": TypeGif,
".jpg": TypeImage,
".jpeg": TypeImage,
".png": TypeImage,
".html": TypeHtml,
".ogg": TypeAudio,
".mp3": TypeAudio,
".wav": TypeAudio,
".mod": TypeAudio,
".it": TypeAudio,
".xm": TypeAudio,
".mid": TypeAudio,
".vgm": TypeAudio,
".mp4": TypeVideo,
".mkv": TypeVideo,
}
var DoubleFileExtMap = map[string]ItemType{
".tar.gz": TypeBin,
var FileExtMap = map[string]ItemType{
".out": TypeBin,
".a": TypeBin,
".o": TypeBin,
".ko": TypeBin, /* ... Though tbh, kernel extensions?!!! */
".msi": TypeBin,
".exe": TypeBin,
".lz": TypeBinArchive,
".gz": TypeBinArchive,
".bz2": TypeBinArchive,
".7z": TypeBinArchive,
".zip": TypeBinArchive,
".gitignore": TypeFile,
".txt": TypeFile,
".json": TypeFile,
".yaml": TypeFile,
".ocaml": TypeFile,
".s": TypeFile,
".c": TypeFile,
".py": TypeFile,
".h": TypeFile,
".go": TypeFile,
".fs": TypeFile,
".odin": TypeFile,
".md": TypeMarkup,
".xml": TypeXml,
".doc": TypeDoc,
".docx": TypeDoc,
".pdf": TypeDoc,
".jpg": TypeImage,
".jpeg": TypeImage,
".png": TypeImage,
".gif": TypeImage,
".html": TypeHtml,
".htm": TypeHtml,
".ogg": TypeAudio,
".mp3": TypeAudio,
".wav": TypeAudio,
".mod": TypeAudio,
".it": TypeAudio,
".xm": TypeAudio,
".mid": TypeAudio,
".vgm": TypeAudio,
".opus": TypeAudio,
".m4a": TypeAudio,
".aac": TypeAudio,
".mp4": TypeVideo,
".mkv": TypeVideo,
".webm": TypeVideo,
}
func buildError(selector string) []byte {
@ -95,39 +106,19 @@ func buildInfoLine(content string) []byte {
* single call.
*/
func getItemType(name string) ItemType {
/* Name MUST be lower */
nameLower := strings.ToLower(name)
/* Split, name MUST be lower */
split := strings.Split(strings.ToLower(name), ".")
/* First we look at how many '.' in name string */
switch strings.Count(nameLower, ".") {
splitLen := len(split)
switch splitLen {
case 0:
/* Always return TypeDefault. We can never tell */
return TypeDefault
case 1:
/* Get index of ".", try look in SingleFileExtMap */
i := strings.IndexByte(nameLower, '.')
fileType, ok := SingleFileExtMap[nameLower[i:]]
if ok {
return fileType
} else {
return TypeDefault
}
default:
/* Get index of penultimate ".", try look in DoubleFileExtMap */
i, j := len(nameLower)-1, 0
for i >= 0 {
if nameLower[i] == '.' {
if j == 1 {
break
} else {
j += 1
}
}
i -= 1
}
fileType, ok := DoubleFileExtMap[nameLower[i:]]
/* Get index of str after last ".", look in FileExtMap */
fileType, ok := FileExtMap["."+split[splitLen-1]]
if ok {
return fileType
} else {

107
fs.go

@ -197,61 +197,62 @@ func unixLineEndSplitter(data []byte, atEOF bool) (advance int, token []byte, er
* single call.
*/
var listDir func(dirPath string, hidden map[string]bool) ([]byte, *GophorError)
func _listDir(dirPath string, hidden map[string]bool) ([]byte, *GophorError) {
/* Open directory file descriptor */
fd, err := os.Open(dirPath)
if err != nil {
logSystemError("failed to open %s: %s\n", dirPath, err.Error())
return nil, &GophorError{ FileOpenErr, err }
}
/* Read files in directory */
files, err := fd.Readdir(-1)
if err != nil {
logSystemError("failed to enumerate dir %s: %s\n", dirPath, err.Error())
return nil, &GophorError{ DirListErr, err }
}
func _listDir(dirPath string, hidden map[string]bool) ([]byte, *GophorError) {
return _listDirBase(dirPath, func(dirContents *[]byte, file os.FileInfo) {
/* If requested hidden */
if _, ok := hidden[file.Name()]; ok {
return
}
/* Sort the files by name */
sort.Sort(byName(files))
/* Handle file, directory or ignore others */
switch {
case file.Mode() & os.ModeDir != 0:
/* Directory -- create directory listing */
itemPath := path.Join(dirPath, file.Name())
*dirContents = append(*dirContents, buildLine(TypeDirectory, file.Name(), itemPath, *ServerHostname, *ServerPort)...)
/* Create directory content slice, ready */
dirContents := make([]byte, 0)
case file.Mode() & os.ModeType == 0:
/* Regular file -- find item type and creating listing */
itemPath := path.Join(dirPath, file.Name())
itemType := getItemType(itemPath)
*dirContents = append(*dirContents, buildLine(itemType, file.Name(), itemPath, *ServerHostname, *ServerPort)...)
/* First add a 'back' entry. GoLang Readdir() seems to miss this */
line := buildLine(TypeDirectory, "..", path.Join(fd.Name(), ".."), *ServerHostname, *ServerPort)
dirContents = append(dirContents, line...)
default:
/* Ignore */
}
})
}
/* Walk through files :D */
for _, file := range files {
/* If requested hidden */
if _, ok := hidden[file.Name()]; ok {
continue
func _listDirRegexMatch(dirPath string, hidden map[string]bool) ([]byte, *GophorError) {
return _listDirBase(dirPath, func(dirContents *[]byte, file os.FileInfo) {
/* If regex match in restricted files || requested hidden */
if isRestrictedFile(file.Name()) {
return
} else if _, ok := hidden[file.Name()]; ok {
return
}
/* Handle file, directory or ignore others */
switch {
case file.Mode() & os.ModeDir != 0:
/* Directory -- create directory listing */
itemPath := path.Join(fd.Name(), file.Name())
line = buildLine(TypeDirectory, file.Name(), itemPath, *ServerHostname, *ServerPort)
dirContents = append(dirContents, line...)
itemPath := path.Join(dirPath, file.Name())
*dirContents = append(*dirContents, buildLine(TypeDirectory, file.Name(), itemPath, *ServerHostname, *ServerPort)...)
case file.Mode() & os.ModeType == 0:
/* Regular file -- find item type and creating listing */
itemPath := path.Join(fd.Name(), file.Name())
itemPath := path.Join(dirPath, file.Name())
itemType := getItemType(itemPath)
line = buildLine(itemType, file.Name(), itemPath, *ServerHostname, *ServerPort)
dirContents = append(dirContents, line...)
*dirContents = append(*dirContents, buildLine(itemType, file.Name(), itemPath, *ServerHostname, *ServerPort)...)
default:
/* Ignore */
}
}
return dirContents, nil
})
}
func _listDirRegexMatch(dirPath string, hidden map[string]bool) ([]byte, *GophorError) {
func _listDirBase(dirPath string, iterFunc func(dirContents *[]byte, file os.FileInfo)) ([]byte, *GophorError) {
/* Open directory file descriptor */
fd, err := os.Open(dirPath)
if err != nil {
@ -272,38 +273,14 @@ func _listDirRegexMatch(dirPath string, hidden map[string]bool) ([]byte, *Gophor
/* Create directory content slice, ready */
dirContents := make([]byte, 0)
/* First add a 'back' entry. GoLang Readdir() seems to miss this */
line := buildLine(TypeDirectory, "..", path.Join(fd.Name(), ".."), *ServerHostname, *ServerPort)
dirContents = append(dirContents, line...)
/* First add a title */
dirContents = append(dirContents, buildLine(TypeInfo, "[ "+*ServerHostname+dirPath+" ]", "TITLE", NullHost, NullPort)...)
/* Walk through files :D */
for _, file := range files {
/* If regex match in restricted files || requested hidden */
if isRestrictedFile(file.Name()) {
continue
} else if _, ok := hidden[file.Name()]; ok {
continue
}
/* Handle file, directory or ignore others */
switch {
case file.Mode() & os.ModeDir != 0:
/* Directory -- create directory listing */
itemPath := path.Join(fd.Name(), file.Name())
line = buildLine(TypeDirectory, file.Name(), itemPath, *ServerHostname, *ServerPort)
dirContents = append(dirContents, line...)
/* Add a 'back' entry. GoLang Readdir() seems to miss this */
dirContents = append(dirContents, buildLine(TypeDirectory, "..", path.Join(fd.Name(), ".."), *ServerHostname, *ServerPort)...)
case file.Mode() & os.ModeType == 0:
/* Regular file -- find item type and creating listing */
itemPath := path.Join(fd.Name(), file.Name())
itemType := getItemType(itemPath)
line = buildLine(itemType, file.Name(), itemPath, *ServerHostname, *ServerPort)
dirContents = append(dirContents, line...)
default:
/* Ignore */
}
}
/* Walk through files :D */
for _, file := range files { iterFunc(&dirContents, file) }
return dirContents, nil
}

@ -244,7 +244,9 @@ func sanitizePath(dataStr string) string {
/* Clean path and trim '/' prefix if still exists */
requestPath := strings.TrimPrefix(path.Clean(dataStr), "/")
if !strings.HasPrefix(requestPath, "/") {
if requestPath == "." {
requestPath = "/"
} else if !strings.HasPrefix(requestPath, "/") {
requestPath = "/" + requestPath
}

Loading…
Cancel
Save