git.sophuwu.com > manweb
finished up version 1.5.0 i think
sophuwu sophie@sophuwu.com
Mon, 28 Jul 2025 19:33:57 +0200
commit

1cfe53609702cd4a465fb330dc7f07dfa92f34f1

parent

a67a042a896aed44d07e6fe7f69109da2d3a04ab

M MakefileMakefile

@@ -6,12 +6,6 @@

clean: rm -rf build -build_deb: - cd extra && nfpm pkg --packager deb --config nfpm.yaml --target ../build/manweb.deb - -install_deb: ./build/manweb.deb - sudo apt-get install -y ./build/manweb.deb - install_bin: ./build/manweb sudo apt-get install -y mandoc sudo sh ./extras/preinst.sh
M README.mdREADME.md

@@ -17,19 +17,15 @@ - Filter by page function or section: 1=commands, 3=C/C++ Refs, 5,7=config/format, 8=sudo commands, etc.

- Able to correctly interpret and display incorrectly formatted man pages, to a degree. - Auto updates man pages when new packages are installed or removed using standard installation methods. -## Extra Information -### Performance: -A query for all user or sudo commands that list or organise information, shows 119 commands in 53ms. -Searching for all C libraries for parsing, shows 38 libraries in 48ms. +## Pictures -If I wish to find a command that configures a service, I would use: -network interfaces, # Installation Using Apt Simply run the following commands to add my repository and install the package. This will install the latest release and automatically update the server when new versions are released. -This will also make the server available as a systemd service, and start it automatically. You may still want to configure a user for the service as some manuals may be in user home directories. -This isn't common on most systems, so the default configuration should work out of the box in most cases. +This will also make the server available as a systemd service, and start it automatically. + +You can read [addrepo.sh.txt](https://cdn.sophuwu.com/deb/addrepo.sh.txt) in your browser. ```bash curl https://cdn.sophuwu.com/deb/addrepo.sh | sudo sh

@@ -39,11 +35,18 @@

# Compiling From Source ## Dependencies -If you are not installing from apt, you will need to install the mandoc package. -* Ubuntu/Debian dependency installation: `sudo apt-get install mandoc -y` +To compile the binary, the `go` compiler is required [go.dev](https://go.dev/doc/install), `make` +is recommended for compilation. -If you wish to compile from source, you will need Go installed.\ -* Golang installation instructions at [go.dev](https://go.dev/doc/install). +The following packages are required +* `mandoc` +* `make` +* `git` - Optional, for tldr support +```bash +sudo apt install mandoc make git +``` +The go compiler is required to compile +* [go.dev](https://go.dev/doc/install). ## Compiling The Binary

@@ -55,75 +58,65 @@

# build binary make build make install_bin - -# build a debian package and install it -make build_deb -make install_deb ``` # Using As Systemd Service: -The provided service file should work on most systems, but you may need to edit it to fit your needs.\ -It will open a http server on port 8082 available through all network interfaces.\ -You should change the `ListenAddr` variable to `127.0.0.1` and use a secure reverse proxy if you are on a public network.\ -TLS and authentication are not implemented in this server. - -### Variables in the service file: - -Environment Variables:\ -`HOSTNAME`: Used for displaying the hostname on the webpage.\ -`ListenPort`: If unset, the server will default to 8082.\ -`ListenAddr`: This should be changed if you are on a public network.\ - -### System Variables: - -`User`: Reccomended to use your login user so the service can access your ~/.local man pages. But not required.\ -`ExecStart`: The path to the manweb binary. If you installed it to /usr/local/bin, you can leave it as is.\ -`WorkingDirectory`: This should be /tmp since the server doesn't need to write to disk.\ - -```sh -# to edit paths, users, and environment variables if needed -nano manweb.service - -# install the service file to systemd and load it -sudo install manweb.service /etc/systemd/system/manweb.service +If you used the installer script, the service will be automatically installed. You just need to enable it. +```bash sudo systemctl daemon-reload +sudo systemctl enable manweb +sudo systemctl start manweb +``` -# start the service and check its status -sudo systemctl start manweb.service -sudo systemctl status manweb.service - -# to keep the service running after a reboot -sudo systemctl enable manweb.service +# Configuring The Server +The server can be configured by editing the `/etc/manweb/manweb.conf` file. +Simply set the options how you like, and restart the service. +```bash +sudo nano /etc/manweb/manweb.conf +sudo systemctl restart manweb +``` -# to stop the service and disable it from restarting -sudo systemctl stop manweb.service -sudo systemctl disable manweb.service +# Setting A Password +To set a password for the web interface, you must enable the `require_auth` option in `/etc/manweb/manweb.conf`. +Generally, there is no need to change the `auth_file` option. -# to edit the server configuration after installation -sudo systemctl edit manweb.service -sudo systemctl daemon-reload -sudo systemctl reload-or-restart manweb.service -sudo systemctl status manweb.service +Once you have enabled `require_auth`, you can set a password `manweb-passwd` while the service is not running. +```bash +sudo systemctl stop manweb +sudo manweb-passwd username +sudo systemctl start manweb ``` +The `manweb-passwd` command will prompt you for a password. +If you enter a password, it will be set for the specified user. +If you leave the password blank, it will remove the user from the authentication database. + +If you set the `require_auth` option to `no`, the server will ignore the authentication database and allow access to the web interface without a password. +This is the default behavior. +' # Accessing the Web Interface -Open your web browser and navigate to `http://localhost:8082` if you are running the server locally or the remote server's IP address or hostname.\ -To search with regex, you can use the search bar at the top of the page with `-r` at the beginning of the search term.\ -To look into a specific section, you can add `-sN` to the search term where N is the section number.\ -If no section is specified, the server will display with the same priority as the defualt `man` command.\ -Glob patterns are also supported in the search bar if regex not enabled.\ +If you have installled the service and are running with default settings, you should be able to access +the web interface on [http://localhost:8082](http://localhost:8082). +By default, the web interface binds to `0.0.0.0:8082`. -## Example Usage: +### Accessibility Options +* For the best reading experience, the web interface has 3 themes: light, dark, and yellow filter. +* The text contrast can be adjusted to make it easier to read. +* The settings tab has an adjustable font scale, allowing easier uniform scaling on any device. + +### Searching +Regex and wildcards are supported in the search bar. +You can also filter by section, or page function. -- `ls*`: List all pages that begin with `ls`, including `ls`, `lsblk`, `lsmod`, etc. -- `-r ^ls`: Same as above but with regex. Usually more useful for with multiple queries and logical operators. Like finding any C++ reference to `std::string` and `std::vector`. -- `ls` or `ls.1`: Open the page for the `ls` user command. This is orignal man behavior. -- `-r ^ls -s1`: List all pages that begin with `ls` in section 1 (user/bin commands). Useful for finding commands that list any information without requiring sudo. -- `*config* -s8`: List pages for sudo commands containing keyword `config`. this can will show you commands that edit critical system files. -- `vsftpd.5`: Open the manual page for vsftpd confuguration file if vsftpd is installed. This will show you how to configure the ftp server. -- `vsftpd.8`: Open the manual page for vsftpd executable if vsftpd is installed. This will show how to call the ftp server from the command line. +* `ls*`: List all pages that begin with `ls`, including `ls`, `lsblk`, `lsmod`, etc. +* `-r ^ls`: Same as above but with regex. +* `ls` or `ls.1`: Open the page for the `ls` user command. This is orignal man behavior. +* `-r ^ls -s1`: List all pages that begin with `ls` in section 1 (user/bin commands). Useful for finding commands that list any information without requiring sudo. +* `*config* -s8`: List pages for sudo commands containing keyword `config`. this can will show you commands that edit critical system files. +* `vsftpd.5`: Open the manual page for vsftpd confuguration file if vsftpd is installed. This will show you how to configure the ftp server. +* `vsftpd.8`: Open the manual page for vsftpd executable if vsftpd is installed. This will show how to call the ftp server from the command line. ## License
M embeds/template/index.htmlembeds/template/index.html

@@ -5,9 +5,9 @@ <head>

<meta charset="utf-8"> <title>{{ .Title }}@{{ .Hostname }}</title> <meta name="viewport" content="width=device-width, initial-scale=1"> - <link rel="stylesheet" href="?static=css" type="text/css"> - <script src="?static=js"></script> - <link rel="icon" href="?static=ico" type="image/x-icon"> + <link rel="stylesheet" href="css.css?static=css" type="text/css"> + <script src="js.js?static=js"></script> + <link rel="icon" href="ico.ico?static=ico" type="image/x-icon"> <style id="styleCss"></style> </head> <body>
A extra/mkdeb.sh

@@ -0,0 +1,56 @@

+#!/bin/bash + +dir="$PWD" + +goarch() { + [[ -n "GOARCH" ]] && go build -ldflags="-w -s" -trimpath -o "$dir/build/manweb_$GOARCH" "$dir/main.go" ; +} +gobuild() { + case "$1" in + "amd"|"amd64"|"x86"|"x86_64") + export GOARCH="amd64" ; + echo building "build/manweb_$GOARCH" ; + goarch ;; + "arm"|"arm64") + export GOARCH="arm64" ; + echo building "build/manweb_$GOARCH" ; + goarch ;; + *) + echo "invalid arch: $i" ; + echo "valid values: amd64, arm64" ; + return 1;; + esac + return 0 +} + +setVersion() { + if [[ -z "$1" ]]; then + echo "invalid version: $1" ; + return 1 ; + fi; + local uwu="$1" ; + uwu=$(printf "%d.%d.%d\n" ${uwu//./ } 2> /dev/null) + if [[ $? -ne 0 ]]; then + echo "invalid version: $1" ; + return 1 ; + fi + for i in {amd64,arm64}; do + sed --in-place "s/^version:.*\$/version: \"$uwu\"/g" "$dir/extra/nfpm_$i.yaml" ; + done + return 0 ; +} + +mkDeb() { + cd "$dir/extra"; + vers=$(grep 'version:' nfpm_amd64.yaml) + vers=${vers:10:-1} + for i in {amd64,arm64}; do + gobuild "$i" && \ + nfpm pkg --packager deb --config "nfpm_$i.yaml" --target "$dir/build/manweb_${vers}_${i}.deb" && \ + echo "manweb_${vers}_${i}.deb created" || \ + echo "failed to build deb for $i" ; + done +} + + +setVersion "$1" && mkDeb
M extra/nfpm.yamlextra/nfpm_amd64.yaml

@@ -1,11 +1,7 @@

-# nfpm example configuration file -# -# check https://nfpm.goreleaser.com/configuration for detailed usage -# +version: "1.5.0" name: "manweb" arch: "amd64" platform: "linux" -version: "1.4.0" section: "default" priority: "extra" replaces:

@@ -31,7 +27,7 @@ homepage: "https://git.sophuwu.com/manweb"

license: "MIT" changelog: "" contents: -- src: ../build/manweb +- src: ../build/manweb_amd64 dst: /usr/bin/manweb - src: ./manweb-passwd dst: /usr/bin/manweb-passwd
A extra/nfpm_arm64.yaml

@@ -0,0 +1,44 @@

+version: "1.5.0" +name: "manweb" +arch: "arm64" +platform: "linux" +section: "default" +priority: "extra" +replaces: +provides: +depends: +- mandoc +- git +recommends: +suggests: +conflicts: +maintainer: "sophuwu <sophie@sophuwu.com>" +description: | + manweb is a frontend for the linux man pages. + Offering a functional, minimalistic interface for viewing and finding pages. + - Search directly by page name + - Search by keyword/wildcard + - Search by section number + - Full regex name and description search + It is useful for serving manpages over a network, or for browsing them + in a web browser. +vendor: "sophuwu.com" +homepage: "https://git.sophuwu.com/manweb" +license: "MIT" +changelog: "" +contents: +- src: ../build/manweb_arm64 + dst: /usr/bin/manweb +- src: ./manweb-passwd + dst: /usr/bin/manweb-passwd +- src: ./manweb.service + dst: /etc/manweb/manweb.service + type: config +- src: ./manweb.conf + dst: /etc/manweb/manweb.conf + type: config +overrides: + deb: + scripts: + postinstall: ./postinstall.sh + preinstall: ./preinst.sh
M go.modgo.mod

@@ -4,13 +4,11 @@ go 1.24.4

require ( git.sophuwu.com/authuwu v0.0.0-20250727204702-f3a53ad3d5bf - git.sophuwu.com/gophuwu v0.0.0-20250716231858-26e29b0c923a + git.sophuwu.com/gophuwu v0.0.0-20250728114940-b336dded4177 + github.com/asdine/storm/v3 v3.2.1 + go.etcd.io/bbolt v1.4.2 golang.org/x/sys v0.34.0 golang.org/x/term v0.33.0 ) -require ( - github.com/asdine/storm/v3 v3.2.1 // indirect - go.etcd.io/bbolt v1.4.2 // indirect - golang.org/x/net v0.39.0 // indirect -) +require golang.org/x/net v0.39.0 // indirect
M go.sumgo.sum

@@ -1,7 +1,7 @@

git.sophuwu.com/authuwu v0.0.0-20250727204702-f3a53ad3d5bf h1:dynoakGl6r7KDIimBIrQBFpn1Wj/oxylZ1qAqgRyuWE= git.sophuwu.com/authuwu v0.0.0-20250727204702-f3a53ad3d5bf/go.mod h1:8Iwgnydo+Zud59xPW1HZKflqjVfXslLr0isASGRhj+M= -git.sophuwu.com/gophuwu v0.0.0-20250716231858-26e29b0c923a h1:eh4yOMWfnwuv7sJ35tZD/fNzeSfs0v2gHnYqiHtpm2M= -git.sophuwu.com/gophuwu v0.0.0-20250716231858-26e29b0c923a/go.mod h1:2j1SAWD5STcFV5oKUm4vChACQ1peXCKpfJLbgE/sD00= +git.sophuwu.com/gophuwu v0.0.0-20250728114940-b336dded4177 h1:FiGpg3/ceTwB5WNOuVACi2YlPB2nRLJlJNlQgi/xNxA= +git.sophuwu.com/gophuwu v0.0.0-20250728114940-b336dded4177/go.mod h1:2j1SAWD5STcFV5oKUm4vChACQ1peXCKpfJLbgE/sD00= github.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM= github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/Sereal/Sereal v0.0.0-20190618215532-0b8ac451a863 h1:BRrxwOZBolJN4gIwvZMJY1tzqBvQgpaZiQRuIDD40jM=
M logs/logs.gologs/logs.go

@@ -5,6 +5,19 @@ "fmt"

"os" ) +var OnExit = make([]func(), 0) + +func AddOnExit(fn func()) { + OnExit = append(OnExit, fn) +} + +func Exit(n int) { + for _, fn := range OnExit { + fn() + } + os.Exit(n) +} + func Log(a ...any) { fmt.Println(a...) }

@@ -19,12 +32,12 @@ }

func Fatalf(format string, a ...any) { fmt.Println("Fatal Error: ", fmt.Sprintf(format, a...)) - os.Exit(1) + Exit(1) } func Fatal(msg string, err error) { fmt.Println("Fatal Error:", msg, ": ", err) - os.Exit(1) + Exit(1) } func CheckFatal(msg string, err error) {
M main.gomain.go

@@ -100,13 +100,14 @@ err = authuwu.OpenDB(CFG.PasswdFile)

logs.CheckFatal("opening password database", err) _ = cookies.PurgeExpiredCookies() PageHandler = authuwu.NewAuthuwuHandler(PageHandler, time.Hour*24*3, embeds.LoginPage) - defer authuwu.CloseDB() + logs.AddOnExit(func() { authuwu.CloseDB() }) } if CFG.EnableStats { stats.OpenDB() - defer stats.CloseDB() + logs.AddOnExit(func() { stats.CloseDB() }) } CFG.ListenAndServe(Handler) + logs.Exit(0) } var RxWords = regexp.MustCompile(`("[^"]+")|([^ ]+)`).FindAllString

@@ -131,7 +132,7 @@ embeds.WriteError(w, r, neterr.Err404, q)

return } var output string - for _, line := range RxWhatIs(string(b), -1) { // strings.Split(string(b), "\n") { + for _, line := range RxWhatIs(string(b), -1) { if len(line) == 4 { output += fmt.Sprintf(`<p><a href="?%s.%s">%s (%s)</a> - %s</p>%c`, line[1], line[2], line[1], line[2], line[3], 10) }

@@ -146,7 +147,9 @@ name = strings.TrimSpace(name)

if r.Method == "POST" { n := r.PostFormValue("q") n = strings.TrimSpace(n) - if n != "" { + if n == "" { + name = "" + } else if n != "" { name = n if strings.ContainsAny(name, `"*?^|`) { SearchHandler(w, r, name)
M manpage/manpage.gomanpage/manpage.go

@@ -46,7 +46,12 @@ func (m *ManPage) Find(q string) bool {

if !ManDotName.MatchString(q) { return false } - b, err := exec.Command(CFG.ManCmd, "--where", q).Output() + args := []string{"--where", q} + if strings.Contains(q, ".") { + m.Name, m.Section = ext(q) + args = []string{"-s" + m.Section, "--where", m.Name} + } + b, err := exec.Command(CFG.ManCmd, args...).Output() if err != nil { return false }

@@ -82,7 +87,7 @@ html, err := m.Html()

if embeds.ChkWriteError(w, r, err, q) { return true } - embeds.WriteHtml(w, r, m.Title(), html, q, m.Url()) + embeds.WriteHtml(w, r, m.Title(), html, m.Url(), m.Url()) stats.Count(m.Url()) return true }