Copy disabled (too large)
Download .txt
Showing preview only (105,314K chars total). Download the full file to get everything.
Repository: umputun/secrets
Branch: master
Commit: 9e7db2599b91
Files: 2102
Total size: 230.4 MB
Directory structure:
gitextract__fg68ugu/
├── .dockerignore
├── .github/
│ ├── dependabot.yml
│ └── workflows/
│ ├── ci.yml
│ ├── e2e.yml
│ └── release.yml
├── .gitignore
├── .golangci.yml
├── .goreleaser.yml
├── .zed/
│ └── tasks.json
├── CHANGELOG.md
├── CLAUDE.md
├── Dockerfile
├── LICENSE
├── Makefile
├── README.md
├── app/
│ ├── email/
│ │ ├── email.go
│ │ ├── email.tmpl.html
│ │ ├── email_test.go
│ │ └── mocks/
│ │ └── notifier_mock.go
│ ├── main.go
│ ├── messager/
│ │ ├── crypt.go
│ │ ├── crypt_mock.go
│ │ ├── crypt_test.go
│ │ ├── engine_mock.go
│ │ ├── messager.go
│ │ └── messager_test.go
│ ├── server/
│ │ ├── assets/
│ │ │ ├── efs.go
│ │ │ ├── html/
│ │ │ │ ├── index.tmpl.html
│ │ │ │ ├── pages/
│ │ │ │ │ ├── 404.tmpl.html
│ │ │ │ │ ├── about.tmpl.html
│ │ │ │ │ ├── home.tmpl.html
│ │ │ │ │ ├── message-error.tmpl.html
│ │ │ │ │ └── show-message.tmpl.html
│ │ │ │ └── partials/
│ │ │ │ ├── copy-button.tmpl.html
│ │ │ │ ├── decoded-message.tmpl.html
│ │ │ │ ├── email-popup.tmpl.html
│ │ │ │ ├── email-sent.tmpl.html
│ │ │ │ ├── error.tmpl.html
│ │ │ │ ├── login-popup.tmpl.html
│ │ │ │ ├── no-pin-modal.tmpl.html
│ │ │ │ ├── popup.tmpl.html
│ │ │ │ └── secure-link.tmpl.html
│ │ │ └── static/
│ │ │ ├── css/
│ │ │ │ └── main.css
│ │ │ └── js/
│ │ │ ├── app.js
│ │ │ ├── crypto.js
│ │ │ └── htmx-response-targets.js
│ │ ├── auth.go
│ │ ├── auth_test.go
│ │ ├── middleware.go
│ │ ├── middleware_test.go
│ │ ├── mocks/
│ │ │ └── email_sender_mock.go
│ │ ├── server.go
│ │ ├── server_test.go
│ │ ├── validator/
│ │ │ ├── validator.go
│ │ │ └── validator_test.go
│ │ ├── web.go
│ │ └── web_test.go
│ └── store/
│ ├── sqlite.go
│ ├── sqlite_test.go
│ ├── store.go
│ └── store_test.go
├── completions/
│ ├── secrets.bash
│ ├── secrets.fish
│ └── secrets.zsh
├── docker-compose-dev.yml
├── docker-compose-reproxy.yml
├── docker-compose.yml
├── docs/
│ └── plans/
│ └── completed/
│ ├── 2025-12-26-paranoid-mode-sqlite.md
│ ├── 2025-12-27-hybrid-encryption.md
│ ├── 2025-12-29-optional-pin.md
│ └── 2026-01-15-csp-inline-scripts-elimination.md
├── e2e/
│ ├── auth_test.go
│ ├── crypto_test.go
│ ├── e2e_test.go
│ ├── email_test.go
│ ├── file_test.go
│ ├── hybrid_test.go
│ └── no_pin_test.go
├── go.mod
├── go.sum
├── secrets-nginx.conf
├── secrets.rest
└── vendor/
├── github.com/
│ ├── aymerick/
│ │ └── douceur/
│ │ ├── LICENSE
│ │ ├── css/
│ │ │ ├── declaration.go
│ │ │ ├── rule.go
│ │ │ └── stylesheet.go
│ │ └── parser/
│ │ └── parser.go
│ ├── davecgh/
│ │ └── go-spew/
│ │ ├── LICENSE
│ │ └── spew/
│ │ ├── bypass.go
│ │ ├── bypasssafe.go
│ │ ├── common.go
│ │ ├── config.go
│ │ ├── doc.go
│ │ ├── dump.go
│ │ ├── format.go
│ │ └── spew.go
│ ├── deckarep/
│ │ └── golang-set/
│ │ └── v2/
│ │ ├── .gitignore
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── iterator.go
│ │ ├── set.go
│ │ ├── sorted.go
│ │ ├── threadsafe.go
│ │ └── threadunsafe.go
│ ├── didip/
│ │ └── tollbooth/
│ │ └── v8/
│ │ ├── .gitignore
│ │ ├── .golangci.yml
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── errors/
│ │ │ └── errors.go
│ │ ├── internal/
│ │ │ └── time/
│ │ │ ├── AUTHORS
│ │ │ ├── CONTRIBUTORS
│ │ │ ├── LICENSE
│ │ │ ├── PATENTS
│ │ │ └── rate/
│ │ │ └── rate.go
│ │ ├── libstring/
│ │ │ └── libstring.go
│ │ ├── limiter/
│ │ │ ├── limiter.go
│ │ │ └── limiter_options.go
│ │ └── tollbooth.go
│ ├── dustin/
│ │ └── go-humanize/
│ │ ├── .travis.yml
│ │ ├── LICENSE
│ │ ├── README.markdown
│ │ ├── big.go
│ │ ├── bigbytes.go
│ │ ├── bytes.go
│ │ ├── comma.go
│ │ ├── commaf.go
│ │ ├── ftoa.go
│ │ ├── humanize.go
│ │ ├── number.go
│ │ ├── ordinals.go
│ │ ├── si.go
│ │ └── times.go
│ ├── go-jose/
│ │ └── go-jose/
│ │ └── v3/
│ │ ├── LICENSE
│ │ └── json/
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── decode.go
│ │ ├── encode.go
│ │ ├── indent.go
│ │ ├── scanner.go
│ │ ├── stream.go
│ │ └── tags.go
│ ├── go-pkgz/
│ │ ├── email/
│ │ │ ├── .gitignore
│ │ │ ├── .golangci.yml
│ │ │ ├── LICENSE
│ │ │ ├── README.md
│ │ │ ├── auth.go
│ │ │ ├── email.go
│ │ │ └── options.go
│ │ ├── expirable-cache/
│ │ │ └── v3/
│ │ │ ├── LICENSE
│ │ │ ├── cache.go
│ │ │ └── options.go
│ │ ├── notify/
│ │ │ ├── .golangci.yml
│ │ │ ├── LICENSE
│ │ │ ├── README.md
│ │ │ ├── email.go
│ │ │ ├── interface.go
│ │ │ ├── slack.go
│ │ │ ├── telegram.go
│ │ │ └── webhook.go
│ │ ├── repeater/
│ │ │ ├── .gitignore
│ │ │ ├── .golangci.yml
│ │ │ ├── LICENSE
│ │ │ ├── README.md
│ │ │ ├── repeater.go
│ │ │ └── strategy/
│ │ │ ├── backoff.go
│ │ │ ├── fixed.go
│ │ │ └── strategy.go
│ │ └── routegroup/
│ │ ├── .gitignore
│ │ ├── .golangci.yml
│ │ ├── LICENSE
│ │ ├── README.md
│ │ └── group.go
│ ├── go-stack/
│ │ └── stack/
│ │ ├── LICENSE.md
│ │ ├── README.md
│ │ └── stack.go
│ ├── google/
│ │ └── uuid/
│ │ ├── CHANGELOG.md
│ │ ├── CONTRIBUTING.md
│ │ ├── CONTRIBUTORS
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── dce.go
│ │ ├── doc.go
│ │ ├── hash.go
│ │ ├── marshal.go
│ │ ├── node.go
│ │ ├── node_js.go
│ │ ├── node_net.go
│ │ ├── null.go
│ │ ├── sql.go
│ │ ├── time.go
│ │ ├── util.go
│ │ ├── uuid.go
│ │ ├── version1.go
│ │ ├── version4.go
│ │ ├── version6.go
│ │ └── version7.go
│ ├── gorilla/
│ │ ├── css/
│ │ │ ├── LICENSE
│ │ │ └── scanner/
│ │ │ ├── doc.go
│ │ │ └── scanner.go
│ │ └── websocket/
│ │ ├── .gitignore
│ │ ├── AUTHORS
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── client.go
│ │ ├── compression.go
│ │ ├── conn.go
│ │ ├── doc.go
│ │ ├── join.go
│ │ ├── json.go
│ │ ├── mask.go
│ │ ├── mask_safe.go
│ │ ├── prepared.go
│ │ ├── proxy.go
│ │ ├── server.go
│ │ ├── tls_handshake.go
│ │ ├── tls_handshake_116.go
│ │ ├── util.go
│ │ └── x_net_proxy.go
│ ├── mattn/
│ │ └── go-isatty/
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── doc.go
│ │ ├── go.test.sh
│ │ ├── isatty_bsd.go
│ │ ├── isatty_others.go
│ │ ├── isatty_plan9.go
│ │ ├── isatty_solaris.go
│ │ ├── isatty_tcgets.go
│ │ └── isatty_windows.go
│ ├── microcosm-cc/
│ │ └── bluemonday/
│ │ ├── CONTRIBUTING.md
│ │ ├── CREDITS.md
│ │ ├── LICENSE.md
│ │ ├── README.md
│ │ ├── SECURITY.md
│ │ ├── css/
│ │ │ └── handlers.go
│ │ ├── doc.go
│ │ ├── helpers.go
│ │ ├── policies.go
│ │ ├── policy.go
│ │ └── sanitize.go
│ ├── ncruces/
│ │ └── go-strftime/
│ │ ├── .gitignore
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── parser.go
│ │ ├── pkg.go
│ │ ├── specifiers.go
│ │ └── strftime.go
│ ├── pmezard/
│ │ └── go-difflib/
│ │ ├── LICENSE
│ │ └── difflib/
│ │ └── difflib.go
│ ├── remyoudompheng/
│ │ └── bigfft/
│ │ ├── LICENSE
│ │ ├── README
│ │ ├── arith_decl.go
│ │ ├── fermat.go
│ │ ├── fft.go
│ │ └── scan.go
│ ├── stretchr/
│ │ └── testify/
│ │ ├── LICENSE
│ │ ├── assert/
│ │ │ ├── assertion_compare.go
│ │ │ ├── assertion_format.go
│ │ │ ├── assertion_format.go.tmpl
│ │ │ ├── assertion_forward.go
│ │ │ ├── assertion_forward.go.tmpl
│ │ │ ├── assertion_order.go
│ │ │ ├── assertions.go
│ │ │ ├── doc.go
│ │ │ ├── errors.go
│ │ │ ├── forward_assertions.go
│ │ │ ├── http_assertions.go
│ │ │ └── yaml/
│ │ │ ├── yaml_custom.go
│ │ │ ├── yaml_default.go
│ │ │ └── yaml_fail.go
│ │ └── require/
│ │ ├── doc.go
│ │ ├── forward_requirements.go
│ │ ├── require.go
│ │ ├── require.go.tmpl
│ │ ├── require_forward.go
│ │ ├── require_forward.go.tmpl
│ │ └── requirements.go
│ └── umputun/
│ └── go-flags/
│ ├── .travis.yml
│ ├── LICENSE
│ ├── README.md
│ ├── arg.go
│ ├── check_crosscompile.sh
│ ├── closest.go
│ ├── command.go
│ ├── completion.go
│ ├── convert.go
│ ├── error.go
│ ├── flags.go
│ ├── group.go
│ ├── help.go
│ ├── ini.go
│ ├── man.go
│ ├── multitag.go
│ ├── option.go
│ ├── optstyle_other.go
│ ├── optstyle_windows.go
│ ├── parser.go
│ ├── termsize.go
│ ├── termsize_nosysioctl.go
│ ├── termsize_windows.go
│ ├── tiocgwinsz_bsdish.go
│ ├── tiocgwinsz_linux.go
│ └── tiocgwinsz_other.go
├── golang.org/
│ └── x/
│ ├── crypto/
│ │ ├── LICENSE
│ │ ├── PATENTS
│ │ ├── argon2/
│ │ │ ├── argon2.go
│ │ │ ├── blake2b.go
│ │ │ ├── blamka_amd64.go
│ │ │ ├── blamka_amd64.s
│ │ │ ├── blamka_generic.go
│ │ │ └── blamka_ref.go
│ │ ├── bcrypt/
│ │ │ ├── base64.go
│ │ │ └── bcrypt.go
│ │ ├── blake2b/
│ │ │ ├── blake2b.go
│ │ │ ├── blake2bAVX2_amd64.go
│ │ │ ├── blake2bAVX2_amd64.s
│ │ │ ├── blake2b_amd64.s
│ │ │ ├── blake2b_generic.go
│ │ │ ├── blake2b_ref.go
│ │ │ ├── blake2x.go
│ │ │ ├── go125.go
│ │ │ └── register.go
│ │ ├── blowfish/
│ │ │ ├── block.go
│ │ │ ├── cipher.go
│ │ │ └── const.go
│ │ ├── internal/
│ │ │ ├── alias/
│ │ │ │ ├── alias.go
│ │ │ │ └── alias_purego.go
│ │ │ └── poly1305/
│ │ │ ├── mac_noasm.go
│ │ │ ├── poly1305.go
│ │ │ ├── sum_amd64.s
│ │ │ ├── sum_asm.go
│ │ │ ├── sum_generic.go
│ │ │ ├── sum_loong64.s
│ │ │ ├── sum_ppc64x.s
│ │ │ ├── sum_s390x.go
│ │ │ └── sum_s390x.s
│ │ ├── nacl/
│ │ │ └── secretbox/
│ │ │ └── secretbox.go
│ │ └── salsa20/
│ │ └── salsa/
│ │ ├── hsalsa20.go
│ │ ├── salsa208.go
│ │ ├── salsa20_amd64.go
│ │ ├── salsa20_amd64.s
│ │ ├── salsa20_noasm.go
│ │ └── salsa20_ref.go
│ ├── net/
│ │ ├── LICENSE
│ │ ├── PATENTS
│ │ └── html/
│ │ ├── atom/
│ │ │ ├── atom.go
│ │ │ └── table.go
│ │ ├── const.go
│ │ ├── doc.go
│ │ ├── doctype.go
│ │ ├── entity.go
│ │ ├── escape.go
│ │ ├── foreign.go
│ │ ├── iter.go
│ │ ├── node.go
│ │ ├── nodetype_string.go
│ │ ├── parse.go
│ │ ├── render.go
│ │ └── token.go
│ └── sys/
│ ├── LICENSE
│ ├── PATENTS
│ ├── cpu/
│ │ ├── asm_aix_ppc64.s
│ │ ├── asm_darwin_arm64_gc.s
│ │ ├── asm_darwin_x86_gc.s
│ │ ├── byteorder.go
│ │ ├── cpu.go
│ │ ├── cpu_aix.go
│ │ ├── cpu_arm.go
│ │ ├── cpu_arm64.go
│ │ ├── cpu_arm64.s
│ │ ├── cpu_darwin_arm64.go
│ │ ├── cpu_darwin_arm64_other.go
│ │ ├── cpu_darwin_x86.go
│ │ ├── cpu_gc_arm64.go
│ │ ├── cpu_gc_s390x.go
│ │ ├── cpu_gc_x86.go
│ │ ├── cpu_gc_x86.s
│ │ ├── cpu_gccgo_arm64.go
│ │ ├── cpu_gccgo_s390x.go
│ │ ├── cpu_gccgo_x86.c
│ │ ├── cpu_gccgo_x86.go
│ │ ├── cpu_linux.go
│ │ ├── cpu_linux_arm.go
│ │ ├── cpu_linux_arm64.go
│ │ ├── cpu_linux_loong64.go
│ │ ├── cpu_linux_mips64x.go
│ │ ├── cpu_linux_noinit.go
│ │ ├── cpu_linux_ppc64x.go
│ │ ├── cpu_linux_riscv64.go
│ │ ├── cpu_linux_s390x.go
│ │ ├── cpu_loong64.go
│ │ ├── cpu_loong64.s
│ │ ├── cpu_mips64x.go
│ │ ├── cpu_mipsx.go
│ │ ├── cpu_netbsd_arm64.go
│ │ ├── cpu_openbsd_arm64.go
│ │ ├── cpu_openbsd_arm64.s
│ │ ├── cpu_other_arm.go
│ │ ├── cpu_other_arm64.go
│ │ ├── cpu_other_mips64x.go
│ │ ├── cpu_other_ppc64x.go
│ │ ├── cpu_other_riscv64.go
│ │ ├── cpu_other_x86.go
│ │ ├── cpu_ppc64x.go
│ │ ├── cpu_riscv64.go
│ │ ├── cpu_s390x.go
│ │ ├── cpu_s390x.s
│ │ ├── cpu_wasm.go
│ │ ├── cpu_windows_arm64.go
│ │ ├── cpu_x86.go
│ │ ├── cpu_zos.go
│ │ ├── cpu_zos_s390x.go
│ │ ├── endian_big.go
│ │ ├── endian_little.go
│ │ ├── hwcap_linux.go
│ │ ├── parse.go
│ │ ├── proc_cpuinfo_linux.go
│ │ ├── runtime_auxv.go
│ │ ├── runtime_auxv_go121.go
│ │ ├── syscall_aix_gccgo.go
│ │ ├── syscall_aix_ppc64_gc.go
│ │ ├── syscall_darwin_arm64_gc.go
│ │ └── syscall_darwin_x86_gc.go
│ ├── unix/
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── affinity_linux.go
│ │ ├── aliases.go
│ │ ├── asm_aix_ppc64.s
│ │ ├── asm_bsd_386.s
│ │ ├── asm_bsd_amd64.s
│ │ ├── asm_bsd_arm.s
│ │ ├── asm_bsd_arm64.s
│ │ ├── asm_bsd_ppc64.s
│ │ ├── asm_bsd_riscv64.s
│ │ ├── asm_linux_386.s
│ │ ├── asm_linux_amd64.s
│ │ ├── asm_linux_arm.s
│ │ ├── asm_linux_arm64.s
│ │ ├── asm_linux_loong64.s
│ │ ├── asm_linux_mips64x.s
│ │ ├── asm_linux_mipsx.s
│ │ ├── asm_linux_ppc64x.s
│ │ ├── asm_linux_riscv64.s
│ │ ├── asm_linux_s390x.s
│ │ ├── asm_openbsd_mips64.s
│ │ ├── asm_solaris_amd64.s
│ │ ├── asm_zos_s390x.s
│ │ ├── auxv.go
│ │ ├── auxv_unsupported.go
│ │ ├── bluetooth_linux.go
│ │ ├── bpxsvc_zos.go
│ │ ├── bpxsvc_zos.s
│ │ ├── cap_freebsd.go
│ │ ├── constants.go
│ │ ├── dev_aix_ppc.go
│ │ ├── dev_aix_ppc64.go
│ │ ├── dev_darwin.go
│ │ ├── dev_dragonfly.go
│ │ ├── dev_freebsd.go
│ │ ├── dev_linux.go
│ │ ├── dev_netbsd.go
│ │ ├── dev_openbsd.go
│ │ ├── dev_zos.go
│ │ ├── dirent.go
│ │ ├── endian_big.go
│ │ ├── endian_little.go
│ │ ├── env_unix.go
│ │ ├── fcntl.go
│ │ ├── fcntl_darwin.go
│ │ ├── fcntl_linux_32bit.go
│ │ ├── fdset.go
│ │ ├── gccgo.go
│ │ ├── gccgo_c.c
│ │ ├── gccgo_linux_amd64.go
│ │ ├── ifreq_linux.go
│ │ ├── ioctl_linux.go
│ │ ├── ioctl_signed.go
│ │ ├── ioctl_unsigned.go
│ │ ├── ioctl_zos.go
│ │ ├── mkall.sh
│ │ ├── mkerrors.sh
│ │ ├── mmap_nomremap.go
│ │ ├── mremap.go
│ │ ├── pagesize_unix.go
│ │ ├── pledge_openbsd.go
│ │ ├── ptrace_darwin.go
│ │ ├── ptrace_ios.go
│ │ ├── race.go
│ │ ├── race0.go
│ │ ├── readdirent_getdents.go
│ │ ├── readdirent_getdirentries.go
│ │ ├── sockcmsg_dragonfly.go
│ │ ├── sockcmsg_linux.go
│ │ ├── sockcmsg_unix.go
│ │ ├── sockcmsg_unix_other.go
│ │ ├── sockcmsg_zos.go
│ │ ├── symaddr_zos_s390x.s
│ │ ├── syscall.go
│ │ ├── syscall_aix.go
│ │ ├── syscall_aix_ppc.go
│ │ ├── syscall_aix_ppc64.go
│ │ ├── syscall_bsd.go
│ │ ├── syscall_darwin.go
│ │ ├── syscall_darwin_amd64.go
│ │ ├── syscall_darwin_arm64.go
│ │ ├── syscall_darwin_libSystem.go
│ │ ├── syscall_dragonfly.go
│ │ ├── syscall_dragonfly_amd64.go
│ │ ├── syscall_freebsd.go
│ │ ├── syscall_freebsd_386.go
│ │ ├── syscall_freebsd_amd64.go
│ │ ├── syscall_freebsd_arm.go
│ │ ├── syscall_freebsd_arm64.go
│ │ ├── syscall_freebsd_riscv64.go
│ │ ├── syscall_hurd.go
│ │ ├── syscall_hurd_386.go
│ │ ├── syscall_illumos.go
│ │ ├── syscall_linux.go
│ │ ├── syscall_linux_386.go
│ │ ├── syscall_linux_alarm.go
│ │ ├── syscall_linux_amd64.go
│ │ ├── syscall_linux_amd64_gc.go
│ │ ├── syscall_linux_arm.go
│ │ ├── syscall_linux_arm64.go
│ │ ├── syscall_linux_gc.go
│ │ ├── syscall_linux_gc_386.go
│ │ ├── syscall_linux_gc_arm.go
│ │ ├── syscall_linux_gccgo_386.go
│ │ ├── syscall_linux_gccgo_arm.go
│ │ ├── syscall_linux_loong64.go
│ │ ├── syscall_linux_mips64x.go
│ │ ├── syscall_linux_mipsx.go
│ │ ├── syscall_linux_ppc.go
│ │ ├── syscall_linux_ppc64x.go
│ │ ├── syscall_linux_riscv64.go
│ │ ├── syscall_linux_s390x.go
│ │ ├── syscall_linux_sparc64.go
│ │ ├── syscall_netbsd.go
│ │ ├── syscall_netbsd_386.go
│ │ ├── syscall_netbsd_amd64.go
│ │ ├── syscall_netbsd_arm.go
│ │ ├── syscall_netbsd_arm64.go
│ │ ├── syscall_openbsd.go
│ │ ├── syscall_openbsd_386.go
│ │ ├── syscall_openbsd_amd64.go
│ │ ├── syscall_openbsd_arm.go
│ │ ├── syscall_openbsd_arm64.go
│ │ ├── syscall_openbsd_libc.go
│ │ ├── syscall_openbsd_mips64.go
│ │ ├── syscall_openbsd_ppc64.go
│ │ ├── syscall_openbsd_riscv64.go
│ │ ├── syscall_solaris.go
│ │ ├── syscall_solaris_amd64.go
│ │ ├── syscall_unix.go
│ │ ├── syscall_unix_gc.go
│ │ ├── syscall_unix_gc_ppc64x.go
│ │ ├── syscall_zos_s390x.go
│ │ ├── sysvshm_linux.go
│ │ ├── sysvshm_unix.go
│ │ ├── sysvshm_unix_other.go
│ │ ├── timestruct.go
│ │ ├── unveil_openbsd.go
│ │ ├── vgetrandom_linux.go
│ │ ├── vgetrandom_unsupported.go
│ │ ├── xattr_bsd.go
│ │ ├── zerrors_aix_ppc.go
│ │ ├── zerrors_aix_ppc64.go
│ │ ├── zerrors_darwin_amd64.go
│ │ ├── zerrors_darwin_arm64.go
│ │ ├── zerrors_dragonfly_amd64.go
│ │ ├── zerrors_freebsd_386.go
│ │ ├── zerrors_freebsd_amd64.go
│ │ ├── zerrors_freebsd_arm.go
│ │ ├── zerrors_freebsd_arm64.go
│ │ ├── zerrors_freebsd_riscv64.go
│ │ ├── zerrors_linux.go
│ │ ├── zerrors_linux_386.go
│ │ ├── zerrors_linux_amd64.go
│ │ ├── zerrors_linux_arm.go
│ │ ├── zerrors_linux_arm64.go
│ │ ├── zerrors_linux_loong64.go
│ │ ├── zerrors_linux_mips.go
│ │ ├── zerrors_linux_mips64.go
│ │ ├── zerrors_linux_mips64le.go
│ │ ├── zerrors_linux_mipsle.go
│ │ ├── zerrors_linux_ppc.go
│ │ ├── zerrors_linux_ppc64.go
│ │ ├── zerrors_linux_ppc64le.go
│ │ ├── zerrors_linux_riscv64.go
│ │ ├── zerrors_linux_s390x.go
│ │ ├── zerrors_linux_sparc64.go
│ │ ├── zerrors_netbsd_386.go
│ │ ├── zerrors_netbsd_amd64.go
│ │ ├── zerrors_netbsd_arm.go
│ │ ├── zerrors_netbsd_arm64.go
│ │ ├── zerrors_openbsd_386.go
│ │ ├── zerrors_openbsd_amd64.go
│ │ ├── zerrors_openbsd_arm.go
│ │ ├── zerrors_openbsd_arm64.go
│ │ ├── zerrors_openbsd_mips64.go
│ │ ├── zerrors_openbsd_ppc64.go
│ │ ├── zerrors_openbsd_riscv64.go
│ │ ├── zerrors_solaris_amd64.go
│ │ ├── zerrors_zos_s390x.go
│ │ ├── zptrace_armnn_linux.go
│ │ ├── zptrace_linux_arm64.go
│ │ ├── zptrace_mipsnn_linux.go
│ │ ├── zptrace_mipsnnle_linux.go
│ │ ├── zptrace_x86_linux.go
│ │ ├── zsymaddr_zos_s390x.s
│ │ ├── zsyscall_aix_ppc.go
│ │ ├── zsyscall_aix_ppc64.go
│ │ ├── zsyscall_aix_ppc64_gc.go
│ │ ├── zsyscall_aix_ppc64_gccgo.go
│ │ ├── zsyscall_darwin_amd64.go
│ │ ├── zsyscall_darwin_amd64.s
│ │ ├── zsyscall_darwin_arm64.go
│ │ ├── zsyscall_darwin_arm64.s
│ │ ├── zsyscall_dragonfly_amd64.go
│ │ ├── zsyscall_freebsd_386.go
│ │ ├── zsyscall_freebsd_amd64.go
│ │ ├── zsyscall_freebsd_arm.go
│ │ ├── zsyscall_freebsd_arm64.go
│ │ ├── zsyscall_freebsd_riscv64.go
│ │ ├── zsyscall_illumos_amd64.go
│ │ ├── zsyscall_linux.go
│ │ ├── zsyscall_linux_386.go
│ │ ├── zsyscall_linux_amd64.go
│ │ ├── zsyscall_linux_arm.go
│ │ ├── zsyscall_linux_arm64.go
│ │ ├── zsyscall_linux_loong64.go
│ │ ├── zsyscall_linux_mips.go
│ │ ├── zsyscall_linux_mips64.go
│ │ ├── zsyscall_linux_mips64le.go
│ │ ├── zsyscall_linux_mipsle.go
│ │ ├── zsyscall_linux_ppc.go
│ │ ├── zsyscall_linux_ppc64.go
│ │ ├── zsyscall_linux_ppc64le.go
│ │ ├── zsyscall_linux_riscv64.go
│ │ ├── zsyscall_linux_s390x.go
│ │ ├── zsyscall_linux_sparc64.go
│ │ ├── zsyscall_netbsd_386.go
│ │ ├── zsyscall_netbsd_amd64.go
│ │ ├── zsyscall_netbsd_arm.go
│ │ ├── zsyscall_netbsd_arm64.go
│ │ ├── zsyscall_openbsd_386.go
│ │ ├── zsyscall_openbsd_386.s
│ │ ├── zsyscall_openbsd_amd64.go
│ │ ├── zsyscall_openbsd_amd64.s
│ │ ├── zsyscall_openbsd_arm.go
│ │ ├── zsyscall_openbsd_arm.s
│ │ ├── zsyscall_openbsd_arm64.go
│ │ ├── zsyscall_openbsd_arm64.s
│ │ ├── zsyscall_openbsd_mips64.go
│ │ ├── zsyscall_openbsd_mips64.s
│ │ ├── zsyscall_openbsd_ppc64.go
│ │ ├── zsyscall_openbsd_ppc64.s
│ │ ├── zsyscall_openbsd_riscv64.go
│ │ ├── zsyscall_openbsd_riscv64.s
│ │ ├── zsyscall_solaris_amd64.go
│ │ ├── zsyscall_zos_s390x.go
│ │ ├── zsysctl_openbsd_386.go
│ │ ├── zsysctl_openbsd_amd64.go
│ │ ├── zsysctl_openbsd_arm.go
│ │ ├── zsysctl_openbsd_arm64.go
│ │ ├── zsysctl_openbsd_mips64.go
│ │ ├── zsysctl_openbsd_ppc64.go
│ │ ├── zsysctl_openbsd_riscv64.go
│ │ ├── zsysnum_darwin_amd64.go
│ │ ├── zsysnum_darwin_arm64.go
│ │ ├── zsysnum_dragonfly_amd64.go
│ │ ├── zsysnum_freebsd_386.go
│ │ ├── zsysnum_freebsd_amd64.go
│ │ ├── zsysnum_freebsd_arm.go
│ │ ├── zsysnum_freebsd_arm64.go
│ │ ├── zsysnum_freebsd_riscv64.go
│ │ ├── zsysnum_linux_386.go
│ │ ├── zsysnum_linux_amd64.go
│ │ ├── zsysnum_linux_arm.go
│ │ ├── zsysnum_linux_arm64.go
│ │ ├── zsysnum_linux_loong64.go
│ │ ├── zsysnum_linux_mips.go
│ │ ├── zsysnum_linux_mips64.go
│ │ ├── zsysnum_linux_mips64le.go
│ │ ├── zsysnum_linux_mipsle.go
│ │ ├── zsysnum_linux_ppc.go
│ │ ├── zsysnum_linux_ppc64.go
│ │ ├── zsysnum_linux_ppc64le.go
│ │ ├── zsysnum_linux_riscv64.go
│ │ ├── zsysnum_linux_s390x.go
│ │ ├── zsysnum_linux_sparc64.go
│ │ ├── zsysnum_netbsd_386.go
│ │ ├── zsysnum_netbsd_amd64.go
│ │ ├── zsysnum_netbsd_arm.go
│ │ ├── zsysnum_netbsd_arm64.go
│ │ ├── zsysnum_openbsd_386.go
│ │ ├── zsysnum_openbsd_amd64.go
│ │ ├── zsysnum_openbsd_arm.go
│ │ ├── zsysnum_openbsd_arm64.go
│ │ ├── zsysnum_openbsd_mips64.go
│ │ ├── zsysnum_openbsd_ppc64.go
│ │ ├── zsysnum_openbsd_riscv64.go
│ │ ├── zsysnum_zos_s390x.go
│ │ ├── ztypes_aix_ppc.go
│ │ ├── ztypes_aix_ppc64.go
│ │ ├── ztypes_darwin_amd64.go
│ │ ├── ztypes_darwin_arm64.go
│ │ ├── ztypes_dragonfly_amd64.go
│ │ ├── ztypes_freebsd_386.go
│ │ ├── ztypes_freebsd_amd64.go
│ │ ├── ztypes_freebsd_arm.go
│ │ ├── ztypes_freebsd_arm64.go
│ │ ├── ztypes_freebsd_riscv64.go
│ │ ├── ztypes_linux.go
│ │ ├── ztypes_linux_386.go
│ │ ├── ztypes_linux_amd64.go
│ │ ├── ztypes_linux_arm.go
│ │ ├── ztypes_linux_arm64.go
│ │ ├── ztypes_linux_loong64.go
│ │ ├── ztypes_linux_mips.go
│ │ ├── ztypes_linux_mips64.go
│ │ ├── ztypes_linux_mips64le.go
│ │ ├── ztypes_linux_mipsle.go
│ │ ├── ztypes_linux_ppc.go
│ │ ├── ztypes_linux_ppc64.go
│ │ ├── ztypes_linux_ppc64le.go
│ │ ├── ztypes_linux_riscv64.go
│ │ ├── ztypes_linux_s390x.go
│ │ ├── ztypes_linux_sparc64.go
│ │ ├── ztypes_netbsd_386.go
│ │ ├── ztypes_netbsd_amd64.go
│ │ ├── ztypes_netbsd_arm.go
│ │ ├── ztypes_netbsd_arm64.go
│ │ ├── ztypes_openbsd_386.go
│ │ ├── ztypes_openbsd_amd64.go
│ │ ├── ztypes_openbsd_arm.go
│ │ ├── ztypes_openbsd_arm64.go
│ │ ├── ztypes_openbsd_mips64.go
│ │ ├── ztypes_openbsd_ppc64.go
│ │ ├── ztypes_openbsd_riscv64.go
│ │ ├── ztypes_solaris_amd64.go
│ │ └── ztypes_zos_s390x.go
│ └── windows/
│ ├── aliases.go
│ ├── dll_windows.go
│ ├── env_windows.go
│ ├── eventlog.go
│ ├── exec_windows.go
│ ├── memory_windows.go
│ ├── mkerrors.bash
│ ├── mkknownfolderids.bash
│ ├── mksyscall.go
│ ├── race.go
│ ├── race0.go
│ ├── security_windows.go
│ ├── service.go
│ ├── setupapi_windows.go
│ ├── str.go
│ ├── syscall.go
│ ├── syscall_windows.go
│ ├── types_windows.go
│ ├── types_windows_386.go
│ ├── types_windows_amd64.go
│ ├── types_windows_arm.go
│ ├── types_windows_arm64.go
│ ├── zerrors_windows.go
│ ├── zknownfolderids_windows.go
│ └── zsyscall_windows.go
├── gopkg.in/
│ └── yaml.v3/
│ ├── LICENSE
│ ├── NOTICE
│ ├── README.md
│ ├── apic.go
│ ├── decode.go
│ ├── emitterc.go
│ ├── encode.go
│ ├── parserc.go
│ ├── readerc.go
│ ├── resolve.go
│ ├── scannerc.go
│ ├── sorter.go
│ ├── writerc.go
│ ├── yaml.go
│ ├── yamlh.go
│ └── yamlprivateh.go
├── modernc.org/
│ ├── libc/
│ │ ├── .gitignore
│ │ ├── AUTHORS
│ │ ├── CONTRIBUTING.md
│ │ ├── CONTRIBUTORS
│ │ ├── LICENSE
│ │ ├── LICENSE-3RD-PARTY.md
│ │ ├── Makefile
│ │ ├── README.md
│ │ ├── abi0_linux_amd64.go
│ │ ├── abi0_linux_amd64.s
│ │ ├── aliases.go
│ │ ├── asm_386.s
│ │ ├── atomic.go
│ │ ├── atomic32.go
│ │ ├── atomic64.go
│ │ ├── build_all_targets.sh
│ │ ├── builder.json
│ │ ├── builtin.go
│ │ ├── builtin32.go
│ │ ├── builtin64.go
│ │ ├── builtin_all.go
│ │ ├── capi_darwin_amd64.go
│ │ ├── capi_darwin_arm64.go
│ │ ├── capi_freebsd_386.go
│ │ ├── capi_freebsd_amd64.go
│ │ ├── capi_freebsd_arm.go
│ │ ├── capi_freebsd_arm64.go
│ │ ├── capi_illumos_amd64.go
│ │ ├── capi_linux_386.go
│ │ ├── capi_linux_amd64.go
│ │ ├── capi_linux_arm.go
│ │ ├── capi_linux_arm64.go
│ │ ├── capi_linux_loong64.go
│ │ ├── capi_linux_mips64le.go
│ │ ├── capi_linux_ppc64le.go
│ │ ├── capi_linux_riscv64.go
│ │ ├── capi_linux_s390x.go
│ │ ├── capi_netbsd_amd64.go
│ │ ├── capi_netbsd_arm.go
│ │ ├── capi_openbsd_386.go
│ │ ├── capi_openbsd_amd64.go
│ │ ├── capi_openbsd_arm64.go
│ │ ├── capi_windows_386.go
│ │ ├── capi_windows_amd64.go
│ │ ├── capi_windows_arm64.go
│ │ ├── ccgo.go
│ │ ├── ccgo_linux_386.go
│ │ ├── ccgo_linux_amd64.go
│ │ ├── ccgo_linux_arm.go
│ │ ├── ccgo_linux_arm64.go
│ │ ├── ccgo_linux_loong64.go
│ │ ├── ccgo_linux_ppc64le.go
│ │ ├── ccgo_linux_riscv64.go
│ │ ├── ccgo_linux_s390x.go
│ │ ├── dmesg.go
│ │ ├── errno/
│ │ │ ├── capi_darwin_amd64.go
│ │ │ ├── capi_darwin_arm64.go
│ │ │ ├── capi_freebsd_386.go
│ │ │ ├── capi_freebsd_amd64.go
│ │ │ ├── capi_freebsd_arm.go
│ │ │ ├── capi_freebsd_arm64.go
│ │ │ ├── capi_illumos_amd64.go
│ │ │ ├── capi_linux_386.go
│ │ │ ├── capi_linux_amd64.go
│ │ │ ├── capi_linux_arm.go
│ │ │ ├── capi_linux_arm64.go
│ │ │ ├── capi_linux_loong64.go
│ │ │ ├── capi_linux_mips64le.go
│ │ │ ├── capi_linux_ppc64le.go
│ │ │ ├── capi_linux_riscv64.go
│ │ │ ├── capi_linux_s390x.go
│ │ │ ├── capi_netbsd_amd64.go
│ │ │ ├── capi_netbsd_arm.go
│ │ │ ├── capi_openbsd_386.go
│ │ │ ├── capi_openbsd_amd64.go
│ │ │ ├── capi_openbsd_arm64.go
│ │ │ ├── capi_windows_386.go
│ │ │ ├── capi_windows_amd64.go
│ │ │ ├── capi_windows_arm64.go
│ │ │ ├── errno_darwin_amd64.go
│ │ │ ├── errno_darwin_arm64.go
│ │ │ ├── errno_freebsd_386.go
│ │ │ ├── errno_freebsd_amd64.go
│ │ │ ├── errno_freebsd_arm.go
│ │ │ ├── errno_freebsd_arm64.go
│ │ │ ├── errno_illumos_amd64.go
│ │ │ ├── errno_linux_386.go
│ │ │ ├── errno_linux_amd64.go
│ │ │ ├── errno_linux_arm.go
│ │ │ ├── errno_linux_arm64.go
│ │ │ ├── errno_linux_loong64.go
│ │ │ ├── errno_linux_mips64le.go
│ │ │ ├── errno_linux_ppc64le.go
│ │ │ ├── errno_linux_riscv64.go
│ │ │ ├── errno_linux_s390x.go
│ │ │ ├── errno_netbsd_amd64.go
│ │ │ ├── errno_netbsd_arm.go
│ │ │ ├── errno_openbsd_386.go
│ │ │ ├── errno_openbsd_amd64.go
│ │ │ ├── errno_openbsd_arm64.go
│ │ │ ├── errno_windows_386.go
│ │ │ ├── errno_windows_amd64.go
│ │ │ └── errno_windows_arm64.go
│ │ ├── etc.go
│ │ ├── etc_musl.go
│ │ ├── fcntl/
│ │ │ ├── capi_darwin_amd64.go
│ │ │ ├── capi_darwin_arm64.go
│ │ │ ├── capi_freebsd_386.go
│ │ │ ├── capi_freebsd_amd64.go
│ │ │ ├── capi_freebsd_arm.go
│ │ │ ├── capi_freebsd_arm64.go
│ │ │ ├── capi_illumos_amd64.go
│ │ │ ├── capi_linux_386.go
│ │ │ ├── capi_linux_amd64.go
│ │ │ ├── capi_linux_arm.go
│ │ │ ├── capi_linux_arm64.go
│ │ │ ├── capi_linux_loong64.go
│ │ │ ├── capi_linux_mips64le.go
│ │ │ ├── capi_linux_ppc64le.go
│ │ │ ├── capi_linux_riscv64.go
│ │ │ ├── capi_linux_s390x.go
│ │ │ ├── capi_netbsd_amd64.go
│ │ │ ├── capi_netbsd_arm.go
│ │ │ ├── capi_openbsd_386.go
│ │ │ ├── capi_openbsd_amd64.go
│ │ │ ├── capi_openbsd_arm64.go
│ │ │ ├── capi_windows_386.go
│ │ │ ├── capi_windows_amd64.go
│ │ │ ├── capi_windows_arm64.go
│ │ │ ├── fcntl_darwin_amd64.go
│ │ │ ├── fcntl_darwin_arm64.go
│ │ │ ├── fcntl_freebsd_386.go
│ │ │ ├── fcntl_freebsd_amd64.go
│ │ │ ├── fcntl_freebsd_arm.go
│ │ │ ├── fcntl_freebsd_arm64.go
│ │ │ ├── fcntl_illumos_amd64.go
│ │ │ ├── fcntl_linux_386.go
│ │ │ ├── fcntl_linux_amd64.go
│ │ │ ├── fcntl_linux_arm.go
│ │ │ ├── fcntl_linux_arm64.go
│ │ │ ├── fcntl_linux_loong64.go
│ │ │ ├── fcntl_linux_mips64le.go
│ │ │ ├── fcntl_linux_ppc64le.go
│ │ │ ├── fcntl_linux_riscv64.go
│ │ │ ├── fcntl_linux_s390x.go
│ │ │ ├── fcntl_netbsd_amd64.go
│ │ │ ├── fcntl_netbsd_arm.go
│ │ │ ├── fcntl_openbsd_386.go
│ │ │ ├── fcntl_openbsd_amd64.go
│ │ │ ├── fcntl_openbsd_arm64.go
│ │ │ ├── fcntl_windows_386.go
│ │ │ ├── fcntl_windows_amd64.go
│ │ │ └── fcntl_windows_arm64.go
│ │ ├── fsync.go
│ │ ├── fts/
│ │ │ ├── capi_darwin_amd64.go
│ │ │ ├── capi_darwin_arm64.go
│ │ │ ├── capi_freebsd_386.go
│ │ │ ├── capi_freebsd_amd64.go
│ │ │ ├── capi_freebsd_arm.go
│ │ │ ├── capi_freebsd_arm64.go
│ │ │ ├── capi_illumos_amd64.go
│ │ │ ├── capi_linux_386.go
│ │ │ ├── capi_linux_amd64.go
│ │ │ ├── capi_linux_arm.go
│ │ │ ├── capi_linux_arm64.go
│ │ │ ├── capi_linux_loong64.go
│ │ │ ├── capi_linux_mips64le.go
│ │ │ ├── capi_linux_ppc64le.go
│ │ │ ├── capi_linux_riscv64.go
│ │ │ ├── capi_linux_s390x.go
│ │ │ ├── capi_netbsd_amd64.go
│ │ │ ├── capi_netbsd_arm.go
│ │ │ ├── capi_openbsd_386.go
│ │ │ ├── capi_openbsd_amd64.go
│ │ │ ├── capi_openbsd_arm64.go
│ │ │ ├── fts_darwin_amd64.go
│ │ │ ├── fts_darwin_arm64.go
│ │ │ ├── fts_freebsd_386.go
│ │ │ ├── fts_freebsd_amd64.go
│ │ │ ├── fts_freebsd_arm.go
│ │ │ ├── fts_freebsd_arm64.go
│ │ │ ├── fts_illumos_amd64.go
│ │ │ ├── fts_linux_386.go
│ │ │ ├── fts_linux_amd64.go
│ │ │ ├── fts_linux_arm.go
│ │ │ ├── fts_linux_arm64.go
│ │ │ ├── fts_linux_loong64.go
│ │ │ ├── fts_linux_mips64le.go
│ │ │ ├── fts_linux_ppc64le.go
│ │ │ ├── fts_linux_riscv64.go
│ │ │ ├── fts_linux_s390x.go
│ │ │ ├── fts_netbsd_amd64.go
│ │ │ ├── fts_netbsd_arm.go
│ │ │ ├── fts_openbsd_386.go
│ │ │ ├── fts_openbsd_amd64.go
│ │ │ └── fts_openbsd_arm64.go
│ │ ├── grp/
│ │ │ ├── capi_darwin_amd64.go
│ │ │ ├── capi_darwin_arm64.go
│ │ │ ├── capi_freebsd_386.go
│ │ │ ├── capi_freebsd_amd64.go
│ │ │ ├── capi_freebsd_arm.go
│ │ │ ├── capi_freebsd_arm64.go
│ │ │ ├── capi_illumos_amd64.go
│ │ │ ├── capi_linux_386.go
│ │ │ ├── capi_linux_amd64.go
│ │ │ ├── capi_linux_arm.go
│ │ │ ├── capi_linux_arm64.go
│ │ │ ├── capi_linux_loong64.go
│ │ │ ├── capi_linux_mips64le.go
│ │ │ ├── capi_linux_ppc64le.go
│ │ │ ├── capi_linux_riscv64.go
│ │ │ ├── capi_linux_s390x.go
│ │ │ ├── capi_netbsd_amd64.go
│ │ │ ├── capi_netbsd_arm.go
│ │ │ ├── capi_openbsd_386.go
│ │ │ ├── capi_openbsd_amd64.go
│ │ │ ├── capi_openbsd_arm64.go
│ │ │ ├── grp_darwin_amd64.go
│ │ │ ├── grp_darwin_arm64.go
│ │ │ ├── grp_freebsd_386.go
│ │ │ ├── grp_freebsd_amd64.go
│ │ │ ├── grp_freebsd_arm.go
│ │ │ ├── grp_freebsd_arm64.go
│ │ │ ├── grp_illumos_amd64.go
│ │ │ ├── grp_linux_386.go
│ │ │ ├── grp_linux_amd64.go
│ │ │ ├── grp_linux_arm.go
│ │ │ ├── grp_linux_arm64.go
│ │ │ ├── grp_linux_loong64.go
│ │ │ ├── grp_linux_mips64le.go
│ │ │ ├── grp_linux_ppc64le.go
│ │ │ ├── grp_linux_riscv64.go
│ │ │ ├── grp_linux_s390x.go
│ │ │ ├── grp_netbsd_amd64.go
│ │ │ ├── grp_netbsd_arm.go
│ │ │ ├── grp_openbsd_386.go
│ │ │ ├── grp_openbsd_amd64.go
│ │ │ └── grp_openbsd_arm64.go
│ │ ├── honnef.co/
│ │ │ └── go/
│ │ │ └── netdb/
│ │ │ ├── README.md
│ │ │ └── netdb.go
│ │ ├── int128.go
│ │ ├── ioutil_darwin.go
│ │ ├── ioutil_freebsd.go
│ │ ├── ioutil_illumos.go
│ │ ├── ioutil_linux.go
│ │ ├── ioutil_netbsd.go
│ │ ├── ioutil_openbsd.go
│ │ ├── langinfo/
│ │ │ ├── capi_darwin_amd64.go
│ │ │ ├── capi_darwin_arm64.go
│ │ │ ├── capi_freebsd_386.go
│ │ │ ├── capi_freebsd_amd64.go
│ │ │ ├── capi_freebsd_arm.go
│ │ │ ├── capi_freebsd_arm64.go
│ │ │ ├── capi_illumos_amd64.go
│ │ │ ├── capi_linux_386.go
│ │ │ ├── capi_linux_amd64.go
│ │ │ ├── capi_linux_arm.go
│ │ │ ├── capi_linux_arm64.go
│ │ │ ├── capi_linux_loong64.go
│ │ │ ├── capi_linux_mips64le.go
│ │ │ ├── capi_linux_ppc64le.go
│ │ │ ├── capi_linux_riscv64.go
│ │ │ ├── capi_linux_s390x.go
│ │ │ ├── capi_netbsd_amd64.go
│ │ │ ├── capi_netbsd_arm.go
│ │ │ ├── capi_openbsd_386.go
│ │ │ ├── capi_openbsd_amd64.go
│ │ │ ├── capi_openbsd_arm64.go
│ │ │ ├── langinfo_darwin_amd64.go
│ │ │ ├── langinfo_darwin_arm64.go
│ │ │ ├── langinfo_freebsd_386.go
│ │ │ ├── langinfo_freebsd_amd64.go
│ │ │ ├── langinfo_freebsd_arm.go
│ │ │ ├── langinfo_freebsd_arm64.go
│ │ │ ├── langinfo_illumos_amd64.go
│ │ │ ├── langinfo_linux_386.go
│ │ │ ├── langinfo_linux_amd64.go
│ │ │ ├── langinfo_linux_arm.go
│ │ │ ├── langinfo_linux_arm64.go
│ │ │ ├── langinfo_linux_loong64.go
│ │ │ ├── langinfo_linux_mips64le.go
│ │ │ ├── langinfo_linux_ppc64le.go
│ │ │ ├── langinfo_linux_riscv64.go
│ │ │ ├── langinfo_linux_s390x.go
│ │ │ ├── langinfo_netbsd_amd64.go
│ │ │ ├── langinfo_netbsd_arm.go
│ │ │ ├── langinfo_openbsd_386.go
│ │ │ ├── langinfo_openbsd_amd64.go
│ │ │ └── langinfo_openbsd_arm64.go
│ │ ├── libc.go
│ │ ├── libc32.go
│ │ ├── libc64.go
│ │ ├── libc_386.go
│ │ ├── libc_all.go
│ │ ├── libc_amd64.go
│ │ ├── libc_arm.go
│ │ ├── libc_arm64.go
│ │ ├── libc_darwin.go
│ │ ├── libc_darwin_amd64.go
│ │ ├── libc_darwin_arm64.go
│ │ ├── libc_freebsd.go
│ │ ├── libc_freebsd_386.go
│ │ ├── libc_freebsd_amd64.go
│ │ ├── libc_freebsd_arm.go
│ │ ├── libc_freebsd_arm64.go
│ │ ├── libc_illumos.go
│ │ ├── libc_illumos_amd64.go
│ │ ├── libc_linux.go
│ │ ├── libc_linux_amd64.go
│ │ ├── libc_linux_mips64le.go
│ │ ├── libc_mips64le.go
│ │ ├── libc_musl.go
│ │ ├── libc_musl_linux_386.go
│ │ ├── libc_musl_linux_amd64.go
│ │ ├── libc_musl_linux_arm.go
│ │ ├── libc_musl_linux_arm64.go
│ │ ├── libc_musl_linux_loong64.go
│ │ ├── libc_musl_linux_ppc64le.go
│ │ ├── libc_musl_linux_riscv64.go
│ │ ├── libc_musl_linux_s390x.go
│ │ ├── libc_netbsd.go
│ │ ├── libc_netbsd_amd64.go
│ │ ├── libc_netbsd_arm.go
│ │ ├── libc_openbsd.go
│ │ ├── libc_openbsd_386.go
│ │ ├── libc_openbsd_amd64.go
│ │ ├── libc_openbsd_arm64.go
│ │ ├── libc_unix.go
│ │ ├── libc_unix1.go
│ │ ├── libc_unix2.go
│ │ ├── libc_unix3.go
│ │ ├── libc_windows.go
│ │ ├── libc_windows_386.go
│ │ ├── libc_windows_386.s
│ │ ├── libc_windows_amd64.go
│ │ ├── libc_windows_arm64.go
│ │ ├── libc_windows_arm64.s
│ │ ├── limits/
│ │ │ ├── capi_darwin_amd64.go
│ │ │ ├── capi_darwin_arm64.go
│ │ │ ├── capi_freebsd_386.go
│ │ │ ├── capi_freebsd_amd64.go
│ │ │ ├── capi_freebsd_arm.go
│ │ │ ├── capi_freebsd_arm64.go
│ │ │ ├── capi_illumos_amd64.go
│ │ │ ├── capi_linux_386.go
│ │ │ ├── capi_linux_amd64.go
│ │ │ ├── capi_linux_arm.go
│ │ │ ├── capi_linux_arm64.go
│ │ │ ├── capi_linux_loong64.go
│ │ │ ├── capi_linux_mips64le.go
│ │ │ ├── capi_linux_ppc64le.go
│ │ │ ├── capi_linux_riscv64.go
│ │ │ ├── capi_linux_s390x.go
│ │ │ ├── capi_netbsd_amd64.go
│ │ │ ├── capi_netbsd_arm.go
│ │ │ ├── capi_openbsd_386.go
│ │ │ ├── capi_openbsd_amd64.go
│ │ │ ├── capi_openbsd_arm64.go
│ │ │ ├── capi_windows_386.go
│ │ │ ├── capi_windows_amd64.go
│ │ │ ├── capi_windows_arm64.go
│ │ │ ├── limits_darwin_amd64.go
│ │ │ ├── limits_darwin_arm64.go
│ │ │ ├── limits_freebsd_386.go
│ │ │ ├── limits_freebsd_amd64.go
│ │ │ ├── limits_freebsd_arm.go
│ │ │ ├── limits_freebsd_arm64.go
│ │ │ ├── limits_illumos_amd64.go
│ │ │ ├── limits_linux_386.go
│ │ │ ├── limits_linux_amd64.go
│ │ │ ├── limits_linux_arm.go
│ │ │ ├── limits_linux_arm64.go
│ │ │ ├── limits_linux_loong64.go
│ │ │ ├── limits_linux_mips64le.go
│ │ │ ├── limits_linux_ppc64le.go
│ │ │ ├── limits_linux_riscv64.go
│ │ │ ├── limits_linux_s390x.go
│ │ │ ├── limits_netbsd_amd64.go
│ │ │ ├── limits_netbsd_arm.go
│ │ │ ├── limits_openbsd_386.go
│ │ │ ├── limits_openbsd_amd64.go
│ │ │ ├── limits_openbsd_arm64.go
│ │ │ ├── limits_windows_386.go
│ │ │ ├── limits_windows_amd64.go
│ │ │ └── limits_windows_arm64.go
│ │ ├── mem.go
│ │ ├── mem_brk.go
│ │ ├── mem_brk_musl.go
│ │ ├── mem_expvar.go
│ │ ├── mem_musl.go
│ │ ├── memgrind.go
│ │ ├── memgrind_musl.go
│ │ ├── musl_darwin_amd64.go
│ │ ├── musl_darwin_arm64.go
│ │ ├── musl_freebsd_386.go
│ │ ├── musl_freebsd_amd64.go
│ │ ├── musl_freebsd_arm.go
│ │ ├── musl_freebsd_arm64.go
│ │ ├── musl_illumos_amd64.go
│ │ ├── musl_linux_mips64le.go
│ │ ├── musl_netbsd_amd64.go
│ │ ├── musl_netbsd_arm.go
│ │ ├── musl_openbsd_386.go
│ │ ├── musl_openbsd_amd64.go
│ │ ├── musl_openbsd_arm64.go
│ │ ├── musl_windows_386.go
│ │ ├── musl_windows_amd64.go
│ │ ├── musl_windows_arm64.go
│ │ ├── netdb/
│ │ │ ├── capi_darwin_amd64.go
│ │ │ ├── capi_darwin_arm64.go
│ │ │ ├── capi_freebsd_386.go
│ │ │ ├── capi_freebsd_amd64.go
│ │ │ ├── capi_freebsd_arm.go
│ │ │ ├── capi_freebsd_arm64.go
│ │ │ ├── capi_illumos_amd64.go
│ │ │ ├── capi_linux_386.go
│ │ │ ├── capi_linux_amd64.go
│ │ │ ├── capi_linux_arm.go
│ │ │ ├── capi_linux_arm64.go
│ │ │ ├── capi_linux_loong64.go
│ │ │ ├── capi_linux_mips64le.go
│ │ │ ├── capi_linux_ppc64le.go
│ │ │ ├── capi_linux_riscv64.go
│ │ │ ├── capi_linux_s390x.go
│ │ │ ├── capi_netbsd_amd64.go
│ │ │ ├── capi_netbsd_arm.go
│ │ │ ├── capi_openbsd_386.go
│ │ │ ├── capi_openbsd_amd64.go
│ │ │ ├── capi_openbsd_arm64.go
│ │ │ ├── netdb_darwin_amd64.go
│ │ │ ├── netdb_darwin_arm64.go
│ │ │ ├── netdb_freebsd_386.go
│ │ │ ├── netdb_freebsd_amd64.go
│ │ │ ├── netdb_freebsd_arm.go
│ │ │ ├── netdb_freebsd_arm64.go
│ │ │ ├── netdb_illumos_amd64.go
│ │ │ ├── netdb_linux_386.go
│ │ │ ├── netdb_linux_amd64.go
│ │ │ ├── netdb_linux_arm.go
│ │ │ ├── netdb_linux_arm64.go
│ │ │ ├── netdb_linux_loong64.go
│ │ │ ├── netdb_linux_mips64le.go
│ │ │ ├── netdb_linux_ppc64le.go
│ │ │ ├── netdb_linux_riscv64.go
│ │ │ ├── netdb_linux_s390x.go
│ │ │ ├── netdb_netbsd_amd64.go
│ │ │ ├── netdb_netbsd_arm.go
│ │ │ ├── netdb_openbsd_386.go
│ │ │ ├── netdb_openbsd_amd64.go
│ │ │ └── netdb_openbsd_arm64.go
│ │ ├── netinet/
│ │ │ └── in/
│ │ │ ├── capi_darwin_amd64.go
│ │ │ ├── capi_darwin_arm64.go
│ │ │ ├── capi_freebsd_386.go
│ │ │ ├── capi_freebsd_amd64.go
│ │ │ ├── capi_freebsd_arm.go
│ │ │ ├── capi_freebsd_arm64.go
│ │ │ ├── capi_illumos_amd64.go
│ │ │ ├── capi_linux_386.go
│ │ │ ├── capi_linux_amd64.go
│ │ │ ├── capi_linux_arm.go
│ │ │ ├── capi_linux_arm64.go
│ │ │ ├── capi_linux_loong64.go
│ │ │ ├── capi_linux_mips64le.go
│ │ │ ├── capi_linux_ppc64le.go
│ │ │ ├── capi_linux_riscv64.go
│ │ │ ├── capi_linux_s390x.go
│ │ │ ├── capi_netbsd_amd64.go
│ │ │ ├── capi_netbsd_arm.go
│ │ │ ├── capi_openbsd_386.go
│ │ │ ├── capi_openbsd_amd64.go
│ │ │ ├── capi_openbsd_arm64.go
│ │ │ ├── in_darwin_amd64.go
│ │ │ ├── in_darwin_arm64.go
│ │ │ ├── in_freebsd_386.go
│ │ │ ├── in_freebsd_amd64.go
│ │ │ ├── in_freebsd_arm.go
│ │ │ ├── in_freebsd_arm64.go
│ │ │ ├── in_illumos_amd64.go
│ │ │ ├── in_linux_386.go
│ │ │ ├── in_linux_amd64.go
│ │ │ ├── in_linux_arm.go
│ │ │ ├── in_linux_arm64.go
│ │ │ ├── in_linux_loong64.go
│ │ │ ├── in_linux_mips64le.go
│ │ │ ├── in_linux_ppc64le.go
│ │ │ ├── in_linux_riscv64.go
│ │ │ ├── in_linux_s390x.go
│ │ │ ├── in_netbsd_amd64.go
│ │ │ ├── in_netbsd_arm.go
│ │ │ ├── in_openbsd_386.go
│ │ │ ├── in_openbsd_amd64.go
│ │ │ └── in_openbsd_arm64.go
│ │ ├── nodmesg.go
│ │ ├── nofsync.go
│ │ ├── poll/
│ │ │ ├── capi_darwin_amd64.go
│ │ │ ├── capi_darwin_arm64.go
│ │ │ ├── capi_freebsd_386.go
│ │ │ ├── capi_freebsd_amd64.go
│ │ │ ├── capi_freebsd_arm.go
│ │ │ ├── capi_freebsd_arm64.go
│ │ │ ├── capi_illumos_amd64.go
│ │ │ ├── capi_linux_386.go
│ │ │ ├── capi_linux_amd64.go
│ │ │ ├── capi_linux_arm.go
│ │ │ ├── capi_linux_arm64.go
│ │ │ ├── capi_linux_loong64.go
│ │ │ ├── capi_linux_mips64le.go
│ │ │ ├── capi_linux_ppc64le.go
│ │ │ ├── capi_linux_riscv64.go
│ │ │ ├── capi_linux_s390x.go
│ │ │ ├── capi_netbsd_amd64.go
│ │ │ ├── capi_netbsd_arm.go
│ │ │ ├── capi_openbsd_386.go
│ │ │ ├── capi_openbsd_amd64.go
│ │ │ ├── capi_openbsd_arm64.go
│ │ │ ├── poll_darwin_amd64.go
│ │ │ ├── poll_darwin_arm64.go
│ │ │ ├── poll_freebsd_386.go
│ │ │ ├── poll_freebsd_amd64.go
│ │ │ ├── poll_freebsd_arm.go
│ │ │ ├── poll_freebsd_arm64.go
│ │ │ ├── poll_illumos_amd64.go
│ │ │ ├── poll_linux_386.go
│ │ │ ├── poll_linux_amd64.go
│ │ │ ├── poll_linux_arm.go
│ │ │ ├── poll_linux_arm64.go
│ │ │ ├── poll_linux_loong64.go
│ │ │ ├── poll_linux_mips64le.go
│ │ │ ├── poll_linux_ppc64le.go
│ │ │ ├── poll_linux_riscv64.go
│ │ │ ├── poll_linux_s390x.go
│ │ │ ├── poll_netbsd_amd64.go
│ │ │ ├── poll_netbsd_arm.go
│ │ │ ├── poll_openbsd_386.go
│ │ │ ├── poll_openbsd_amd64.go
│ │ │ └── poll_openbsd_arm64.go
│ │ ├── printf.go
│ │ ├── probes.go
│ │ ├── pthread/
│ │ │ ├── capi_darwin_amd64.go
│ │ │ ├── capi_darwin_arm64.go
│ │ │ ├── capi_freebsd_386.go
│ │ │ ├── capi_freebsd_amd64.go
│ │ │ ├── capi_freebsd_arm.go
│ │ │ ├── capi_freebsd_arm64.go
│ │ │ ├── capi_illumos_amd64.go
│ │ │ ├── capi_linux_386.go
│ │ │ ├── capi_linux_amd64.go
│ │ │ ├── capi_linux_arm.go
│ │ │ ├── capi_linux_arm64.go
│ │ │ ├── capi_linux_loong64.go
│ │ │ ├── capi_linux_mips64le.go
│ │ │ ├── capi_linux_ppc64le.go
│ │ │ ├── capi_linux_riscv64.go
│ │ │ ├── capi_linux_s390x.go
│ │ │ ├── capi_netbsd_amd64.go
│ │ │ ├── capi_netbsd_arm.go
│ │ │ ├── capi_openbsd_386.go
│ │ │ ├── capi_openbsd_amd64.go
│ │ │ ├── capi_openbsd_arm64.go
│ │ │ ├── capi_windows_386.go
│ │ │ ├── capi_windows_amd64.go
│ │ │ ├── capi_windows_arm64.go
│ │ │ ├── pthread_darwin_amd64.go
│ │ │ ├── pthread_darwin_arm64.go
│ │ │ ├── pthread_freebsd_386.go
│ │ │ ├── pthread_freebsd_amd64.go
│ │ │ ├── pthread_freebsd_arm.go
│ │ │ ├── pthread_freebsd_arm64.go
│ │ │ ├── pthread_illumos_amd64.go
│ │ │ ├── pthread_linux_386.go
│ │ │ ├── pthread_linux_amd64.go
│ │ │ ├── pthread_linux_arm.go
│ │ │ ├── pthread_linux_arm64.go
│ │ │ ├── pthread_linux_loong64.go
│ │ │ ├── pthread_linux_mips64le.go
│ │ │ ├── pthread_linux_ppc64le.go
│ │ │ ├── pthread_linux_riscv64.go
│ │ │ ├── pthread_linux_s390x.go
│ │ │ ├── pthread_netbsd_amd64.go
│ │ │ ├── pthread_netbsd_arm.go
│ │ │ ├── pthread_openbsd_386.go
│ │ │ ├── pthread_openbsd_amd64.go
│ │ │ ├── pthread_openbsd_arm64.go
│ │ │ ├── pthread_windows_386.go
│ │ │ ├── pthread_windows_amd64.go
│ │ │ └── pthread_windows_arm64.go
│ │ ├── pthread.go
│ │ ├── pthread_all.go
│ │ ├── pthread_musl.go
│ │ ├── pwd/
│ │ │ ├── capi_darwin_amd64.go
│ │ │ ├── capi_darwin_arm64.go
│ │ │ ├── capi_freebsd_386.go
│ │ │ ├── capi_freebsd_amd64.go
│ │ │ ├── capi_freebsd_arm.go
│ │ │ ├── capi_freebsd_arm64.go
│ │ │ ├── capi_illumos_amd64.go
│ │ │ ├── capi_linux_386.go
│ │ │ ├── capi_linux_amd64.go
│ │ │ ├── capi_linux_arm.go
│ │ │ ├── capi_linux_arm64.go
│ │ │ ├── capi_linux_loong64.go
│ │ │ ├── capi_linux_mips64le.go
│ │ │ ├── capi_linux_ppc64le.go
│ │ │ ├── capi_linux_riscv64.go
│ │ │ ├── capi_linux_s390x.go
│ │ │ ├── capi_netbsd_amd64.go
│ │ │ ├── capi_netbsd_arm.go
│ │ │ ├── capi_openbsd_386.go
│ │ │ ├── capi_openbsd_amd64.go
│ │ │ ├── capi_openbsd_arm64.go
│ │ │ ├── pwd_darwin_amd64.go
│ │ │ ├── pwd_darwin_arm64.go
│ │ │ ├── pwd_freebsd_386.go
│ │ │ ├── pwd_freebsd_amd64.go
│ │ │ ├── pwd_freebsd_arm.go
│ │ │ ├── pwd_freebsd_arm64.go
│ │ │ ├── pwd_illumos_amd64.go
│ │ │ ├── pwd_linux_386.go
│ │ │ ├── pwd_linux_amd64.go
│ │ │ ├── pwd_linux_arm.go
│ │ │ ├── pwd_linux_arm64.go
│ │ │ ├── pwd_linux_loong64.go
│ │ │ ├── pwd_linux_mips64le.go
│ │ │ ├── pwd_linux_ppc64le.go
│ │ │ ├── pwd_linux_riscv64.go
│ │ │ ├── pwd_linux_s390x.go
│ │ │ ├── pwd_netbsd_amd64.go
│ │ │ ├── pwd_netbsd_arm.go
│ │ │ ├── pwd_openbsd_386.go
│ │ │ ├── pwd_openbsd_amd64.go
│ │ │ └── pwd_openbsd_arm64.go
│ │ ├── rtl.go
│ │ ├── scanf.go
│ │ ├── signal/
│ │ │ ├── capi_darwin_amd64.go
│ │ │ ├── capi_darwin_arm64.go
│ │ │ ├── capi_freebsd_386.go
│ │ │ ├── capi_freebsd_amd64.go
│ │ │ ├── capi_freebsd_arm.go
│ │ │ ├── capi_freebsd_arm64.go
│ │ │ ├── capi_illumos_amd64.go
│ │ │ ├── capi_linux_386.go
│ │ │ ├── capi_linux_amd64.go
│ │ │ ├── capi_linux_arm.go
│ │ │ ├── capi_linux_arm64.go
│ │ │ ├── capi_linux_loong64.go
│ │ │ ├── capi_linux_mips64le.go
│ │ │ ├── capi_linux_ppc64le.go
│ │ │ ├── capi_linux_riscv64.go
│ │ │ ├── capi_linux_s390x.go
│ │ │ ├── capi_netbsd_amd64.go
│ │ │ ├── capi_netbsd_arm.go
│ │ │ ├── capi_openbsd_386.go
│ │ │ ├── capi_openbsd_amd64.go
│ │ │ ├── capi_openbsd_arm64.go
│ │ │ ├── capi_windows_386.go
│ │ │ ├── capi_windows_amd64.go
│ │ │ ├── capi_windows_arm64.go
│ │ │ ├── more_darwin_amd64.go
│ │ │ ├── more_darwin_arm64.go
│ │ │ ├── more_freebsd_386.go
│ │ │ ├── more_freebsd_amd64.go
│ │ │ ├── more_freebsd_arm.go
│ │ │ ├── more_freebsd_arm64.go
│ │ │ ├── more_illumos_amd64.go
│ │ │ ├── more_linux_386.go
│ │ │ ├── more_linux_amd64.go
│ │ │ ├── more_linux_arm.go
│ │ │ ├── more_linux_arm64.go
│ │ │ ├── more_linux_loong64.go
│ │ │ ├── more_linux_mips64le.go
│ │ │ ├── more_linux_ppc64le.go
│ │ │ ├── more_linux_riscv64.go
│ │ │ ├── more_linux_s390x.go
│ │ │ ├── more_netbsd_amd64.go
│ │ │ ├── more_netbsd_arm.go
│ │ │ ├── more_openbsd_386.go
│ │ │ ├── more_openbsd_amd64.go
│ │ │ ├── more_openbsd_arm64.go
│ │ │ ├── signal_darwin_amd64.go
│ │ │ ├── signal_darwin_arm64.go
│ │ │ ├── signal_freebsd_386.go
│ │ │ ├── signal_freebsd_amd64.go
│ │ │ ├── signal_freebsd_arm.go
│ │ │ ├── signal_freebsd_arm64.go
│ │ │ ├── signal_illumos_amd64.go
│ │ │ ├── signal_linux_386.go
│ │ │ ├── signal_linux_amd64.go
│ │ │ ├── signal_linux_arm.go
│ │ │ ├── signal_linux_arm64.go
│ │ │ ├── signal_linux_loong64.go
│ │ │ ├── signal_linux_mips64le.go
│ │ │ ├── signal_linux_ppc64le.go
│ │ │ ├── signal_linux_riscv64.go
│ │ │ ├── signal_linux_s390x.go
│ │ │ ├── signal_netbsd_amd64.go
│ │ │ ├── signal_netbsd_arm.go
│ │ │ ├── signal_openbsd_386.go
│ │ │ ├── signal_openbsd_amd64.go
│ │ │ ├── signal_openbsd_arm64.go
│ │ │ ├── signal_windows_386.go
│ │ │ ├── signal_windows_amd64.go
│ │ │ └── signal_windows_arm64.go
│ │ ├── stdatomic.go
│ │ ├── stdio/
│ │ │ ├── capi_darwin_amd64.go
│ │ │ ├── capi_darwin_arm64.go
│ │ │ ├── capi_freebsd_386.go
│ │ │ ├── capi_freebsd_amd64.go
│ │ │ ├── capi_freebsd_arm.go
│ │ │ ├── capi_freebsd_arm64.go
│ │ │ ├── capi_illumos_amd64.go
│ │ │ ├── capi_linux_386.go
│ │ │ ├── capi_linux_amd64.go
│ │ │ ├── capi_linux_arm.go
│ │ │ ├── capi_linux_arm64.go
│ │ │ ├── capi_linux_loong64.go
│ │ │ ├── capi_linux_mips64le.go
│ │ │ ├── capi_linux_ppc64le.go
│ │ │ ├── capi_linux_riscv64.go
│ │ │ ├── capi_linux_s390x.go
│ │ │ ├── capi_netbsd_amd64.go
│ │ │ ├── capi_netbsd_arm.go
│ │ │ ├── capi_openbsd_386.go
│ │ │ ├── capi_openbsd_amd64.go
│ │ │ ├── capi_openbsd_arm64.go
│ │ │ ├── capi_windows_386.go
│ │ │ ├── capi_windows_amd64.go
│ │ │ ├── capi_windows_arm64.go
│ │ │ ├── stdio_darwin_amd64.go
│ │ │ ├── stdio_darwin_arm64.go
│ │ │ ├── stdio_freebsd_386.go
│ │ │ ├── stdio_freebsd_amd64.go
│ │ │ ├── stdio_freebsd_arm.go
│ │ │ ├── stdio_freebsd_arm64.go
│ │ │ ├── stdio_illumos_amd64.go
│ │ │ ├── stdio_linux_386.go
│ │ │ ├── stdio_linux_amd64.go
│ │ │ ├── stdio_linux_arm.go
│ │ │ ├── stdio_linux_arm64.go
│ │ │ ├── stdio_linux_loong64.go
│ │ │ ├── stdio_linux_mips64le.go
│ │ │ ├── stdio_linux_ppc64le.go
│ │ │ ├── stdio_linux_riscv64.go
│ │ │ ├── stdio_linux_s390x.go
│ │ │ ├── stdio_netbsd_amd64.go
│ │ │ ├── stdio_netbsd_arm.go
│ │ │ ├── stdio_openbsd_386.go
│ │ │ ├── stdio_openbsd_amd64.go
│ │ │ ├── stdio_openbsd_arm64.go
│ │ │ ├── stdio_windows_386.go
│ │ │ ├── stdio_windows_amd64.go
│ │ │ └── stdio_windows_arm64.go
│ │ ├── stdlib/
│ │ │ ├── capi_darwin_amd64.go
│ │ │ ├── capi_darwin_arm64.go
│ │ │ ├── capi_freebsd_386.go
│ │ │ ├── capi_freebsd_amd64.go
│ │ │ ├── capi_freebsd_arm.go
│ │ │ ├── capi_freebsd_arm64.go
│ │ │ ├── capi_illumos_amd64.go
│ │ │ ├── capi_linux_386.go
│ │ │ ├── capi_linux_amd64.go
│ │ │ ├── capi_linux_arm.go
│ │ │ ├── capi_linux_arm64.go
│ │ │ ├── capi_linux_loong64.go
│ │ │ ├── capi_linux_mips64le.go
│ │ │ ├── capi_linux_ppc64le.go
│ │ │ ├── capi_linux_riscv64.go
│ │ │ ├── capi_linux_s390x.go
│ │ │ ├── capi_netbsd_amd64.go
│ │ │ ├── capi_netbsd_arm.go
│ │ │ ├── capi_openbsd_386.go
│ │ │ ├── capi_openbsd_amd64.go
│ │ │ ├── capi_openbsd_arm64.go
│ │ │ ├── capi_windows_386.go
│ │ │ ├── capi_windows_amd64.go
│ │ │ ├── capi_windows_arm64.go
│ │ │ ├── stdlib_darwin_amd64.go
│ │ │ ├── stdlib_darwin_arm64.go
│ │ │ ├── stdlib_freebsd_386.go
│ │ │ ├── stdlib_freebsd_amd64.go
│ │ │ ├── stdlib_freebsd_arm.go
│ │ │ ├── stdlib_freebsd_arm64.go
│ │ │ ├── stdlib_illumos_amd64.go
│ │ │ ├── stdlib_linux_386.go
│ │ │ ├── stdlib_linux_amd64.go
│ │ │ ├── stdlib_linux_arm.go
│ │ │ ├── stdlib_linux_arm64.go
│ │ │ ├── stdlib_linux_loong64.go
│ │ │ ├── stdlib_linux_mips64le.go
│ │ │ ├── stdlib_linux_ppc64le.go
│ │ │ ├── stdlib_linux_riscv64.go
│ │ │ ├── stdlib_linux_s390x.go
│ │ │ ├── stdlib_netbsd_amd64.go
│ │ │ ├── stdlib_netbsd_arm.go
│ │ │ ├── stdlib_openbsd_386.go
│ │ │ ├── stdlib_openbsd_amd64.go
│ │ │ ├── stdlib_openbsd_arm64.go
│ │ │ ├── stdlib_windows_386.go
│ │ │ ├── stdlib_windows_amd64.go
│ │ │ └── stdlib_windows_arm64.go
│ │ ├── straceoff.go
│ │ ├── straceon.go
│ │ ├── surface.new
│ │ ├── surface.old
│ │ ├── sync.go
│ │ ├── sys/
│ │ │ ├── socket/
│ │ │ │ ├── capi_darwin_amd64.go
│ │ │ │ ├── capi_darwin_arm64.go
│ │ │ │ ├── capi_freebsd_386.go
│ │ │ │ ├── capi_freebsd_amd64.go
│ │ │ │ ├── capi_freebsd_arm.go
│ │ │ │ ├── capi_freebsd_arm64.go
│ │ │ │ ├── capi_illumos_amd64.go
│ │ │ │ ├── capi_linux_386.go
│ │ │ │ ├── capi_linux_amd64.go
│ │ │ │ ├── capi_linux_arm.go
│ │ │ │ ├── capi_linux_arm64.go
│ │ │ │ ├── capi_linux_loong64.go
│ │ │ │ ├── capi_linux_mips64le.go
│ │ │ │ ├── capi_linux_ppc64le.go
│ │ │ │ ├── capi_linux_riscv64.go
│ │ │ │ ├── capi_linux_s390x.go
│ │ │ │ ├── capi_netbsd_amd64.go
│ │ │ │ ├── capi_netbsd_arm.go
│ │ │ │ ├── capi_openbsd_386.go
│ │ │ │ ├── capi_openbsd_amd64.go
│ │ │ │ ├── capi_openbsd_arm64.go
│ │ │ │ ├── socket_darwin_amd64.go
│ │ │ │ ├── socket_darwin_arm64.go
│ │ │ │ ├── socket_freebsd_386.go
│ │ │ │ ├── socket_freebsd_amd64.go
│ │ │ │ ├── socket_freebsd_arm.go
│ │ │ │ ├── socket_freebsd_arm64.go
│ │ │ │ ├── socket_illumos_amd64.go
│ │ │ │ ├── socket_linux_386.go
│ │ │ │ ├── socket_linux_amd64.go
│ │ │ │ ├── socket_linux_arm.go
│ │ │ │ ├── socket_linux_arm64.go
│ │ │ │ ├── socket_linux_loong64.go
│ │ │ │ ├── socket_linux_mips64le.go
│ │ │ │ ├── socket_linux_ppc64le.go
│ │ │ │ ├── socket_linux_riscv64.go
│ │ │ │ ├── socket_linux_s390x.go
│ │ │ │ ├── socket_netbsd_amd64.go
│ │ │ │ ├── socket_netbsd_arm.go
│ │ │ │ ├── socket_openbsd_386.go
│ │ │ │ ├── socket_openbsd_amd64.go
│ │ │ │ └── socket_openbsd_arm64.go
│ │ │ ├── stat/
│ │ │ │ ├── capi_darwin_amd64.go
│ │ │ │ ├── capi_darwin_arm64.go
│ │ │ │ ├── capi_freebsd_386.go
│ │ │ │ ├── capi_freebsd_amd64.go
│ │ │ │ ├── capi_freebsd_arm.go
│ │ │ │ ├── capi_freebsd_arm64.go
│ │ │ │ ├── capi_illumos_amd64.go
│ │ │ │ ├── capi_linux_386.go
│ │ │ │ ├── capi_linux_amd64.go
│ │ │ │ ├── capi_linux_arm.go
│ │ │ │ ├── capi_linux_arm64.go
│ │ │ │ ├── capi_linux_loong64.go
│ │ │ │ ├── capi_linux_mips64le.go
│ │ │ │ ├── capi_linux_ppc64le.go
│ │ │ │ ├── capi_linux_riscv64.go
│ │ │ │ ├── capi_linux_s390x.go
│ │ │ │ ├── capi_netbsd_amd64.go
│ │ │ │ ├── capi_netbsd_arm.go
│ │ │ │ ├── capi_openbsd_386.go
│ │ │ │ ├── capi_openbsd_amd64.go
│ │ │ │ ├── capi_openbsd_arm64.go
│ │ │ │ ├── capi_windows_386.go
│ │ │ │ ├── capi_windows_amd64.go
│ │ │ │ ├── capi_windows_arm64.go
│ │ │ │ ├── stat_darwin_amd64.go
│ │ │ │ ├── stat_darwin_arm64.go
│ │ │ │ ├── stat_freebsd_386.go
│ │ │ │ ├── stat_freebsd_amd64.go
│ │ │ │ ├── stat_freebsd_arm.go
│ │ │ │ ├── stat_freebsd_arm64.go
│ │ │ │ ├── stat_illumos_amd64.go
│ │ │ │ ├── stat_linux_386.go
│ │ │ │ ├── stat_linux_amd64.go
│ │ │ │ ├── stat_linux_arm.go
│ │ │ │ ├── stat_linux_arm64.go
│ │ │ │ ├── stat_linux_loong64.go
│ │ │ │ ├── stat_linux_mips64le.go
│ │ │ │ ├── stat_linux_ppc64le.go
│ │ │ │ ├── stat_linux_riscv64.go
│ │ │ │ ├── stat_linux_s390x.go
│ │ │ │ ├── stat_netbsd_amd64.go
│ │ │ │ ├── stat_netbsd_arm.go
│ │ │ │ ├── stat_openbsd_386.go
│ │ │ │ ├── stat_openbsd_amd64.go
│ │ │ │ ├── stat_openbsd_arm64.go
│ │ │ │ ├── stat_windows_386.go
│ │ │ │ ├── stat_windows_amd64.go
│ │ │ │ └── stat_windows_arm64.go
│ │ │ └── types/
│ │ │ ├── capi_darwin_amd64.go
│ │ │ ├── capi_darwin_arm64.go
│ │ │ ├── capi_freebsd_386.go
│ │ │ ├── capi_freebsd_amd64.go
│ │ │ ├── capi_freebsd_arm.go
│ │ │ ├── capi_freebsd_arm64.go
│ │ │ ├── capi_illumos_amd64.go
│ │ │ ├── capi_linux_386.go
│ │ │ ├── capi_linux_amd64.go
│ │ │ ├── capi_linux_arm.go
│ │ │ ├── capi_linux_arm64.go
│ │ │ ├── capi_linux_loong64.go
│ │ │ ├── capi_linux_mips64le.go
│ │ │ ├── capi_linux_ppc64le.go
│ │ │ ├── capi_linux_riscv64.go
│ │ │ ├── capi_linux_s390x.go
│ │ │ ├── capi_netbsd_amd64.go
│ │ │ ├── capi_netbsd_arm.go
│ │ │ ├── capi_openbsd_386.go
│ │ │ ├── capi_openbsd_amd64.go
│ │ │ ├── capi_openbsd_arm64.go
│ │ │ ├── capi_windows_386.go
│ │ │ ├── capi_windows_amd64.go
│ │ │ ├── capi_windows_arm64.go
│ │ │ ├── types_darwin_amd64.go
│ │ │ ├── types_darwin_arm64.go
│ │ │ ├── types_freebsd_386.go
│ │ │ ├── types_freebsd_amd64.go
│ │ │ ├── types_freebsd_arm.go
│ │ │ ├── types_freebsd_arm64.go
│ │ │ ├── types_illumos_amd64.go
│ │ │ ├── types_linux_386.go
│ │ │ ├── types_linux_amd64.go
│ │ │ ├── types_linux_arm.go
│ │ │ ├── types_linux_arm64.go
│ │ │ ├── types_linux_loong64.go
│ │ │ ├── types_linux_mips64le.go
│ │ │ ├── types_linux_ppc64le.go
│ │ │ ├── types_linux_riscv64.go
│ │ │ ├── types_linux_s390x.go
│ │ │ ├── types_netbsd_amd64.go
│ │ │ ├── types_netbsd_arm.go
│ │ │ ├── types_openbsd_386.go
│ │ │ ├── types_openbsd_amd64.go
│ │ │ ├── types_openbsd_arm64.go
│ │ │ ├── types_windows_386.go
│ │ │ ├── types_windows_amd64.go
│ │ │ └── types_windows_arm64.go
│ │ ├── syscall_musl.go
│ │ ├── termios/
│ │ │ ├── capi_darwin_amd64.go
│ │ │ ├── capi_darwin_arm64.go
│ │ │ ├── capi_freebsd_386.go
│ │ │ ├── capi_freebsd_amd64.go
│ │ │ ├── capi_freebsd_arm.go
│ │ │ ├── capi_freebsd_arm64.go
│ │ │ ├── capi_illumos_amd64.go
│ │ │ ├── capi_linux_386.go
│ │ │ ├── capi_linux_amd64.go
│ │ │ ├── capi_linux_arm.go
│ │ │ ├── capi_linux_arm64.go
│ │ │ ├── capi_linux_loong64.go
│ │ │ ├── capi_linux_mips64le.go
│ │ │ ├── capi_linux_ppc64le.go
│ │ │ ├── capi_linux_riscv64.go
│ │ │ ├── capi_linux_s390x.go
│ │ │ ├── capi_netbsd_amd64.go
│ │ │ ├── capi_netbsd_arm.go
│ │ │ ├── capi_openbsd_386.go
│ │ │ ├── capi_openbsd_amd64.go
│ │ │ ├── capi_openbsd_arm64.go
│ │ │ ├── termios_darwin_amd64.go
│ │ │ ├── termios_darwin_arm64.go
│ │ │ ├── termios_freebsd_386.go
│ │ │ ├── termios_freebsd_amd64.go
│ │ │ ├── termios_freebsd_arm.go
│ │ │ ├── termios_freebsd_arm64.go
│ │ │ ├── termios_illumos_amd64.go
│ │ │ ├── termios_linux_386.go
│ │ │ ├── termios_linux_amd64.go
│ │ │ ├── termios_linux_arm.go
│ │ │ ├── termios_linux_arm64.go
│ │ │ ├── termios_linux_loong64.go
│ │ │ ├── termios_linux_mips64le.go
│ │ │ ├── termios_linux_ppc64le.go
│ │ │ ├── termios_linux_riscv64.go
│ │ │ ├── termios_linux_s390x.go
│ │ │ ├── termios_netbsd_amd64.go
│ │ │ ├── termios_netbsd_arm.go
│ │ │ ├── termios_openbsd_386.go
│ │ │ ├── termios_openbsd_amd64.go
│ │ │ └── termios_openbsd_arm64.go
│ │ ├── time/
│ │ │ ├── capi_darwin_amd64.go
│ │ │ ├── capi_darwin_arm64.go
│ │ │ ├── capi_freebsd_386.go
│ │ │ ├── capi_freebsd_amd64.go
│ │ │ ├── capi_freebsd_arm.go
│ │ │ ├── capi_freebsd_arm64.go
│ │ │ ├── capi_illumos_amd64.go
│ │ │ ├── capi_linux_386.go
│ │ │ ├── capi_linux_amd64.go
│ │ │ ├── capi_linux_arm.go
│ │ │ ├── capi_linux_arm64.go
│ │ │ ├── capi_linux_loong64.go
│ │ │ ├── capi_linux_mips64le.go
│ │ │ ├── capi_linux_ppc64le.go
│ │ │ ├── capi_linux_riscv64.go
│ │ │ ├── capi_linux_s390x.go
│ │ │ ├── capi_netbsd_amd64.go
│ │ │ ├── capi_netbsd_arm.go
│ │ │ ├── capi_openbsd_386.go
│ │ │ ├── capi_openbsd_amd64.go
│ │ │ ├── capi_openbsd_arm64.go
│ │ │ ├── capi_windows_386.go
│ │ │ ├── capi_windows_amd64.go
│ │ │ ├── capi_windows_arm64.go
│ │ │ ├── time_darwin_amd64.go
│ │ │ ├── time_darwin_arm64.go
│ │ │ ├── time_freebsd_386.go
│ │ │ ├── time_freebsd_amd64.go
│ │ │ ├── time_freebsd_arm.go
│ │ │ ├── time_freebsd_arm64.go
│ │ │ ├── time_illumos_amd64.go
│ │ │ ├── time_linux_386.go
│ │ │ ├── time_linux_amd64.go
│ │ │ ├── time_linux_arm.go
│ │ │ ├── time_linux_arm64.go
│ │ │ ├── time_linux_loong64.go
│ │ │ ├── time_linux_mips64le.go
│ │ │ ├── time_linux_ppc64le.go
│ │ │ ├── time_linux_riscv64.go
│ │ │ ├── time_linux_s390x.go
│ │ │ ├── time_netbsd_amd64.go
│ │ │ ├── time_netbsd_arm.go
│ │ │ ├── time_openbsd_386.go
│ │ │ ├── time_openbsd_amd64.go
│ │ │ ├── time_openbsd_arm64.go
│ │ │ ├── time_windows_386.go
│ │ │ ├── time_windows_amd64.go
│ │ │ └── time_windows_arm64.go
│ │ ├── tls_linux_amd64.go
│ │ ├── tls_linux_amd64.s
│ │ ├── unistd/
│ │ │ ├── capi_darwin_amd64.go
│ │ │ ├── capi_darwin_arm64.go
│ │ │ ├── capi_freebsd_386.go
│ │ │ ├── capi_freebsd_amd64.go
│ │ │ ├── capi_freebsd_arm.go
│ │ │ ├── capi_freebsd_arm64.go
│ │ │ ├── capi_illumos_amd64.go
│ │ │ ├── capi_linux_386.go
│ │ │ ├── capi_linux_amd64.go
│ │ │ ├── capi_linux_arm.go
│ │ │ ├── capi_linux_arm64.go
│ │ │ ├── capi_linux_loong64.go
│ │ │ ├── capi_linux_mips64le.go
│ │ │ ├── capi_linux_ppc64le.go
│ │ │ ├── capi_linux_riscv64.go
│ │ │ ├── capi_linux_s390x.go
│ │ │ ├── capi_netbsd_amd64.go
│ │ │ ├── capi_netbsd_arm.go
│ │ │ ├── capi_openbsd_386.go
│ │ │ ├── capi_openbsd_amd64.go
│ │ │ ├── capi_openbsd_arm64.go
│ │ │ ├── capi_windows_386.go
│ │ │ ├── capi_windows_amd64.go
│ │ │ ├── capi_windows_arm64.go
│ │ │ ├── unistd_darwin_amd64.go
│ │ │ ├── unistd_darwin_arm64.go
│ │ │ ├── unistd_freebsd_386.go
│ │ │ ├── unistd_freebsd_amd64.go
│ │ │ ├── unistd_freebsd_arm.go
│ │ │ ├── unistd_freebsd_arm64.go
│ │ │ ├── unistd_illumos_amd64.go
│ │ │ ├── unistd_linux_386.go
│ │ │ ├── unistd_linux_amd64.go
│ │ │ ├── unistd_linux_arm.go
│ │ │ ├── unistd_linux_arm64.go
│ │ │ ├── unistd_linux_loong64.go
│ │ │ ├── unistd_linux_mips64le.go
│ │ │ ├── unistd_linux_ppc64le.go
│ │ │ ├── unistd_linux_riscv64.go
│ │ │ ├── unistd_linux_s390x.go
│ │ │ ├── unistd_netbsd_amd64.go
│ │ │ ├── unistd_netbsd_arm.go
│ │ │ ├── unistd_openbsd_386.go
│ │ │ ├── unistd_openbsd_amd64.go
│ │ │ ├── unistd_openbsd_arm64.go
│ │ │ ├── unistd_windows_386.go
│ │ │ ├── unistd_windows_amd64.go
│ │ │ └── unistd_windows_arm64.go
│ │ ├── utime/
│ │ │ ├── capi_darwin_amd64.go
│ │ │ ├── capi_darwin_arm64.go
│ │ │ ├── capi_freebsd_386.go
│ │ │ ├── capi_freebsd_amd64.go
│ │ │ ├── capi_freebsd_arm.go
│ │ │ ├── capi_freebsd_arm64.go
│ │ │ ├── capi_illumos_amd64.go
│ │ │ ├── capi_linux_386.go
│ │ │ ├── capi_linux_amd64.go
│ │ │ ├── capi_linux_arm.go
│ │ │ ├── capi_linux_arm64.go
│ │ │ ├── capi_linux_loong64.go
│ │ │ ├── capi_linux_mips64le.go
│ │ │ ├── capi_linux_ppc64le.go
│ │ │ ├── capi_linux_riscv64.go
│ │ │ ├── capi_linux_s390x.go
│ │ │ ├── capi_netbsd_amd64.go
│ │ │ ├── capi_netbsd_arm.go
│ │ │ ├── capi_openbsd_386.go
│ │ │ ├── capi_openbsd_amd64.go
│ │ │ ├── capi_openbsd_arm64.go
│ │ │ ├── capi_windows_386.go
│ │ │ ├── capi_windows_amd64.go
│ │ │ ├── capi_windows_arm64.go
│ │ │ ├── utime_darwin_amd64.go
│ │ │ ├── utime_darwin_arm64.go
│ │ │ ├── utime_freebsd_386.go
│ │ │ ├── utime_freebsd_amd64.go
│ │ │ ├── utime_freebsd_arm.go
│ │ │ ├── utime_freebsd_arm64.go
│ │ │ ├── utime_illumos_amd64.go
│ │ │ ├── utime_linux_386.go
│ │ │ ├── utime_linux_amd64.go
│ │ │ ├── utime_linux_arm.go
│ │ │ ├── utime_linux_arm64.go
│ │ │ ├── utime_linux_loong64.go
│ │ │ ├── utime_linux_mips64le.go
│ │ │ ├── utime_linux_ppc64le.go
│ │ │ ├── utime_linux_riscv64.go
│ │ │ ├── utime_linux_s390x.go
│ │ │ ├── utime_netbsd_amd64.go
│ │ │ ├── utime_netbsd_arm.go
│ │ │ ├── utime_openbsd_386.go
│ │ │ ├── utime_openbsd_amd64.go
│ │ │ ├── utime_openbsd_arm64.go
│ │ │ ├── utime_windows_386.go
│ │ │ ├── utime_windows_amd64.go
│ │ │ └── utime_windows_arm64.go
│ │ ├── uuid/
│ │ │ ├── capi_freebsd_386.go
│ │ │ ├── capi_freebsd_amd64.go
│ │ │ ├── capi_freebsd_arm.go
│ │ │ ├── capi_freebsd_arm64.go
│ │ │ ├── capi_netbsd_amd64.go
│ │ │ ├── capi_netbsd_arm.go
│ │ │ ├── capi_openbsd_386.go
│ │ │ ├── capi_openbsd_amd64.go
│ │ │ ├── capi_openbsd_arm64.go
│ │ │ ├── uuid/
│ │ │ │ ├── capi_darwin_amd64.go
│ │ │ │ ├── capi_darwin_arm64.go
│ │ │ │ ├── capi_illumos_amd64.go
│ │ │ │ ├── capi_linux_386.go
│ │ │ │ ├── capi_linux_amd64.go
│ │ │ │ ├── capi_linux_arm.go
│ │ │ │ ├── capi_linux_arm64.go
│ │ │ │ ├── capi_linux_loong64.go
│ │ │ │ ├── capi_linux_mips64le.go
│ │ │ │ ├── capi_linux_ppc64le.go
│ │ │ │ ├── capi_linux_riscv64.go
│ │ │ │ ├── capi_linux_s390x.go
│ │ │ │ ├── uuid_darwin_amd64.go
│ │ │ │ ├── uuid_darwin_arm64.go
│ │ │ │ ├── uuid_illumos_amd64.go
│ │ │ │ ├── uuid_linux_386.go
│ │ │ │ ├── uuid_linux_amd64.go
│ │ │ │ ├── uuid_linux_arm.go
│ │ │ │ ├── uuid_linux_arm64.go
│ │ │ │ ├── uuid_linux_loong64.go
│ │ │ │ ├── uuid_linux_mips64le.go
│ │ │ │ ├── uuid_linux_ppc64le.go
│ │ │ │ ├── uuid_linux_riscv64.go
│ │ │ │ └── uuid_linux_s390x.go
│ │ │ ├── uuid_freebsd_386.go
│ │ │ ├── uuid_freebsd_amd64.go
│ │ │ ├── uuid_freebsd_arm.go
│ │ │ ├── uuid_freebsd_arm64.go
│ │ │ ├── uuid_netbsd_amd64.go
│ │ │ ├── uuid_netbsd_arm.go
│ │ │ ├── uuid_openbsd_386.go
│ │ │ ├── uuid_openbsd_amd64.go
│ │ │ └── uuid_openbsd_arm64.go
│ │ ├── watch.go
│ │ └── wctype/
│ │ ├── capi_darwin_amd64.go
│ │ ├── capi_darwin_arm64.go
│ │ ├── capi_freebsd_386.go
│ │ ├── capi_freebsd_amd64.go
│ │ ├── capi_freebsd_arm.go
│ │ ├── capi_freebsd_arm64.go
│ │ ├── capi_illumos_amd64.go
│ │ ├── capi_linux_386.go
│ │ ├── capi_linux_amd64.go
│ │ ├── capi_linux_arm.go
│ │ ├── capi_linux_arm64.go
│ │ ├── capi_linux_loong64.go
│ │ ├── capi_linux_mips64le.go
│ │ ├── capi_linux_ppc64le.go
│ │ ├── capi_linux_riscv64.go
│ │ ├── capi_linux_s390x.go
│ │ ├── capi_netbsd_amd64.go
│ │ ├── capi_netbsd_arm.go
│ │ ├── capi_openbsd_386.go
│ │ ├── capi_openbsd_amd64.go
│ │ ├── capi_openbsd_arm64.go
│ │ ├── capi_windows_386.go
│ │ ├── capi_windows_amd64.go
│ │ ├── capi_windows_arm64.go
│ │ ├── wctype_darwin_amd64.go
│ │ ├── wctype_darwin_arm64.go
│ │ ├── wctype_freebsd_386.go
│ │ ├── wctype_freebsd_amd64.go
│ │ ├── wctype_freebsd_arm.go
│ │ ├── wctype_freebsd_arm64.go
│ │ ├── wctype_illumos_amd64.go
│ │ ├── wctype_linux_386.go
│ │ ├── wctype_linux_amd64.go
│ │ ├── wctype_linux_arm.go
│ │ ├── wctype_linux_arm64.go
│ │ ├── wctype_linux_loong64.go
│ │ ├── wctype_linux_mips64le.go
│ │ ├── wctype_linux_ppc64le.go
│ │ ├── wctype_linux_riscv64.go
│ │ ├── wctype_linux_s390x.go
│ │ ├── wctype_netbsd_amd64.go
│ │ ├── wctype_netbsd_arm.go
│ │ ├── wctype_openbsd_386.go
│ │ ├── wctype_openbsd_amd64.go
│ │ ├── wctype_openbsd_arm64.go
│ │ ├── wctype_windows_386.go
│ │ ├── wctype_windows_amd64.go
│ │ └── wctype_windows_arm64.go
│ ├── mathutil/
│ │ ├── AUTHORS
│ │ ├── CONTRIBUTORS
│ │ ├── LICENSE
│ │ ├── Makefile
│ │ ├── README
│ │ ├── binarylog.go
│ │ ├── bits.go
│ │ ├── builder.json
│ │ ├── envelope.go
│ │ ├── int.go
│ │ ├── mathutil.go
│ │ ├── nist-sts-2-1-1-report
│ │ ├── permute.go
│ │ ├── poly.go
│ │ ├── primes.go
│ │ ├── rat.go
│ │ ├── rnd.go
│ │ ├── sqr.go
│ │ ├── sqr_std.go
│ │ ├── tables.go
│ │ └── test_deps.go
│ ├── memory/
│ │ ├── AUTHORS
│ │ ├── CONTRIBUTORS
│ │ ├── LICENSE
│ │ ├── LICENSE-GO
│ │ ├── LICENSE-LOGO
│ │ ├── LICENSE-MMAP-GO
│ │ ├── Makefile
│ │ ├── README.md
│ │ ├── builder.json
│ │ ├── counters.go
│ │ ├── memory.go
│ │ ├── memory32.go
│ │ ├── memory64.go
│ │ ├── mmap_unix.go
│ │ ├── mmap_windows.go
│ │ ├── nocounters.go
│ │ ├── trace_disabled.go
│ │ └── trace_enabled.go
│ └── sqlite/
│ ├── AUTHORS
│ ├── CHANGELOG.md
│ ├── CONTRIBUTORS
│ ├── GOVERNANCE.md
│ ├── HACKING.md
│ ├── LICENSE
│ ├── Makefile
│ ├── README.md
│ ├── SQLITE-LICENSE
│ ├── backup.go
│ ├── builder.json
│ ├── conn.go
│ ├── convert.go
│ ├── dmesg.go
│ ├── doc.go
│ ├── driver.go
│ ├── error.go
│ ├── fcntl.go
│ ├── issue120.diff
│ ├── lib/
│ │ ├── defs.go
│ │ ├── hooks.go
│ │ ├── hooks_linux_arm64.go
│ │ ├── mutex.go
│ │ ├── sqlite_darwin_amd64.go
│ │ ├── sqlite_darwin_arm64.go
│ │ ├── sqlite_freebsd_386.go
│ │ ├── sqlite_freebsd_amd64.go
│ │ ├── sqlite_freebsd_arm.go
│ │ ├── sqlite_freebsd_arm64.go
│ │ ├── sqlite_linux_386.go
│ │ ├── sqlite_linux_amd64.go
│ │ ├── sqlite_linux_arm.go
│ │ ├── sqlite_linux_arm64.go
│ │ ├── sqlite_linux_loong64.go
│ │ ├── sqlite_linux_ppc64le.go
│ │ ├── sqlite_linux_riscv64.go
│ │ ├── sqlite_linux_s390x.go
│ │ ├── sqlite_netbsd_amd64.go
│ │ ├── sqlite_openbsd_amd64.go
│ │ ├── sqlite_openbsd_arm64.go
│ │ ├── sqlite_windows.go
│ │ └── sqlite_windows_386.go
│ ├── mutex.go
│ ├── nodmesg.go
│ ├── norlimit.go
│ ├── pre_update_hook.go
│ ├── result.go
│ ├── rlimit.go
│ ├── rows.go
│ ├── rulimit.go
│ ├── sqlite.go
│ ├── stmt.go
│ ├── tpch.sh
│ ├── tx.go
│ ├── unconvert.sh
│ ├── vtab/
│ │ ├── doc.go
│ │ └── vtab.go
│ └── vtab.go
└── modules.txt
================================================
FILE CONTENTS
================================================
================================================
FILE: .dockerignore
================================================
node_modules
================================================
FILE: .github/dependabot.yml
================================================
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "monthly"
groups:
"GitHub Actions updates":
patterns:
- "*"
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "weekly"
groups:
"Go modules updates":
dependency-type: "production"
applies-to: "security-updates"
================================================
FILE: .github/workflows/ci.yml
================================================
name: build
on: [push, pull_request]
jobs:
build:
name: build
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v6
- name: set up go 1.25
uses: actions/setup-go@v6
with:
go-version: "1.25"
id: go
- name: test
run: |
go test -v -timeout=60s -covermode=count -coverprofile=$GITHUB_WORKSPACE/profile.cov_tmp ./...
cat $GITHUB_WORKSPACE/profile.cov_tmp | grep -v "mock_" > $GITHUB_WORKSPACE/profile.cov
working-directory: app
env:
TZ: "America/Chicago"
- name: golangci-lint
uses: golangci/golangci-lint-action@v9
with:
version: v2.7.2
- name: install goveralls
run: go install github.com/mattn/goveralls@latest
- name: build
run: go build -v
working-directory: app
- name: submit coverage
run: $(go env GOPATH)/bin/goveralls -service="github" -coverprofile=$GITHUB_WORKSPACE/profile.cov
env:
COVERALLS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
docker:
needs: build
if: github.event_name == 'push'
strategy:
fail-fast: false
matrix:
include:
- platform: linux/amd64
runner: ubuntu-latest
artifact: linux-amd64
- platform: linux/arm64
runner: ubuntu-24.04-arm
artifact: linux-arm64
runs-on: ${{ matrix.runner }}
steps:
- uses: actions/checkout@v6
- uses: docker/setup-buildx-action@v4
- uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKERHUB_USER }}
password: ${{ secrets.DOCKERHUB_PASSWD }}
- name: build and push by digest
id: build
uses: docker/build-push-action@v7
with:
context: .
platforms: ${{ matrix.platform }}
outputs: type=image,name=umputun/secrets,push-by-digest=true,name-canonical=true,push=true
- name: export digest
run: |
mkdir -p /tmp/digests
digest="${{ steps.build.outputs.digest }}"
touch "/tmp/digests/${digest#sha256:}"
- uses: actions/upload-artifact@v7
with:
name: digests-${{ matrix.artifact }}
path: /tmp/digests/*
retention-days: 1
docker-merge:
needs: docker
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v8
with:
path: /tmp/digests
pattern: digests-*
merge-multiple: true
- uses: docker/setup-buildx-action@v4
- uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKERHUB_USER }}
password: ${{ secrets.DOCKERHUB_PASSWD }}
- name: determine tags
id: tags
run: |
ref="${GITHUB_REF#refs/*/}"
ref="${ref//\//_}"
echo "ref=${ref}" >> $GITHUB_OUTPUT
if [[ "$GITHUB_REF" == refs/tags/v* ]]; then
echo "is_tag=true" >> $GITHUB_OUTPUT
else
echo "is_tag=false" >> $GITHUB_OUTPUT
fi
- name: create manifest and push
working-directory: /tmp/digests
run: |
ref="${{ steps.tags.outputs.ref }}"
is_tag="${{ steps.tags.outputs.is_tag }}"
tags="-t umputun/secrets:${ref}"
if [[ "$is_tag" == "true" ]]; then
tags="${tags} -t umputun/secrets:latest"
fi
docker buildx imagetools create ${tags} \
$(printf 'umputun/secrets@sha256:%s ' *)
================================================
FILE: .github/workflows/e2e.yml
================================================
name: e2e
on:
push:
branches: [master]
pull_request:
workflow_dispatch:
permissions:
contents: read
jobs:
e2e:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v6
- name: setup go
uses: actions/setup-go@v6
with:
go-version: "1.25"
- name: cache playwright browsers
uses: actions/cache@v5
id: playwright-cache
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ hashFiles('go.sum') }}
- name: install playwright browsers
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: go run github.com/playwright-community/playwright-go/cmd/playwright@latest install --with-deps chromium
- name: install playwright deps only
if: steps.playwright-cache.outputs.cache-hit == 'true'
run: go run github.com/playwright-community/playwright-go/cmd/playwright@latest install-deps chromium
- name: run e2e tests
run: go test -v -count=1 -timeout=5m -tags=e2e ./e2e/...
================================================
FILE: .github/workflows/release.yml
================================================
name: release
on:
push:
tags:
- 'v*'
permissions:
contents: write
jobs:
goreleaser:
runs-on: ubuntu-latest
steps:
- name: check out code
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: set up go
uses: actions/setup-go@v6
with:
go-version: "1.25"
- name: run goreleaser
uses: goreleaser/goreleaser-action@v7
with:
version: ~> 1.25
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GORELEASER_GITHUB_TOKEN }}
================================================
FILE: .gitignore
================================================
*.test
*.prof
.cover/
etc/ssl/
ssl/
target/
secrets.bd
docroot
*.cov
.cover
target
/logs/
/target/
/var/
debug
debug.test
.vscode
.idea/
/web/node_modules/
/web/public/
*.prof
*.test
/var
# Build artifacts
/app/secrets
secrets
coverage.out
coverage.html
.playwright-mcp/
================================================
FILE: .golangci.yml
================================================
version: "2"
run:
concurrency: 4
linters:
default: none
enable:
- asciicheck
- bidichk
- bodyclose
- copyloopvar
- dupl
- durationcheck
- errcheck
- errname
- errorlint
- exhaustive
- fatcontext
- gochecknoinits
- goconst
- gocritic
- gocyclo
- godoclint
- gosec
- govet
- ineffassign
- intrange
- makezero
- misspell
- modernize
- nakedret
- nestif
- nilerr
- nilnil
- noctx
- nolintlint
- perfsprint
- predeclared
- prealloc
- reassign
- revive
- sqlclosecheck
- staticcheck
- testifylint
- tparallel
- unconvert
- unparam
- unused
- usestdlibvars
- wastedassign
- whitespace
- wrapcheck
settings:
exhaustive:
default-signifies-exhaustive: true
nolintlint:
require-explanation: true
require-specific: true
dupl:
threshold: 100
goconst:
min-len: 2
min-occurrences: 7
gocritic:
disabled-checks:
- wrapperFunc
- hugeParam
- rangeValCopy
enabled-tags:
- performance
- style
- experimental
gocyclo:
min-complexity: 20
govet:
enable:
- shadow
lll:
line-length: 140
misspell:
locale: US
revive:
rules:
- name: early-return
- name: indent-error-flow
- name: superfluous-else
- name: unreachable-code
- name: empty-block
- name: redefines-builtin-id
exclusions:
generated: lax
rules:
- linters:
- golint
text: should have a package comment, unless it's in another file for this package
- linters:
- gocritic
text: "exitAfterDefer:"
- linters:
- gocritic
text: "whyNoLint: include an explanation for nolint directive"
- linters:
- revive
text: should have a package comment
- linters:
- staticcheck
text: at least one file in a package should have a package comment
- linters:
- gocritic
text: "commentedOutCode: may want to remove commented-out code"
- linters:
- gocritic
text: "unnamedResult: consider giving a name to these results"
- linters:
- revive
text: "var-naming: don't use an underscore in package name"
- linters:
- staticcheck
text: should not use underscores in package names
- linters:
- govet
text: struct literal uses unkeyed fields
- linters:
- revive
- unparam
- unused
path: _test\.go$
text: unused-parameter
- linters:
- dupl
- goconst
- noctx
- usestdlibvars
path: _test\.go$
- linters:
- gosec
path: e2e/
text: "G101: Potential hardcoded credentials"
- linters:
- goconst
text: "string `text` has"
- linters:
- godoclint
path: lib/stash/
- linters:
- errcheck
text: "Error return value of .*.Close.*is not checked"
- linters:
- errcheck
path: _test\.go$
text: "Error return value of .*(os\\.Remove|os\\.RemoveAll|Body\\.Close).*is not checked"
- linters:
- staticcheck
text: "SA5008: duplicate struct tag"
paths:
- vendor
- third_party$
- builtin$
- examples$
formatters:
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$
================================================
FILE: .goreleaser.yml
================================================
project_name: secrets
dist: .bin
builds:
- id: secrets
binary: "secrets"
env:
- CGO_ENABLED=0
goos:
- linux
- darwin
- windows
goarch:
- amd64
- arm
- arm64
ignore:
- goos: windows
goarch: arm
- goos: windows
goarch: arm64
dir: app
ldflags: "-s -w -X main.revision={{.Tag}}-{{.ShortCommit}}-{{.CommitDate}}"
archives:
- id: secrets
name_template: >-
{{.ProjectName}}_
{{- .Tag}}_
{{- if eq .Os "darwin"}}macos
{{- else if eq .Os "windows"}}win
{{- else}}{{.Os}}{{end}}_
{{- if eq .Arch "amd64"}}x86_64
{{- else if eq .Arch "386"}}i386
{{- else}}{{.Arch}}{{end}}
format_overrides:
- goos: windows
format: zip
files:
- LICENSE
- README.md
- completions/*
rlcp: true
brews:
- name: secrets
repository:
owner: umputun
name: homebrew-apps
branch: master
directory: Formula
commit_author:
name: umputun
email: umputun@gmail.com
commit_msg_template: "Brew formula update for {{ .ProjectName }} version {{ .Tag }}"
homepage: "https://github.com/umputun/secrets"
description: "Self-hosted service for sharing encrypted secrets with one-time access"
license: "MIT"
extra_install: |
bash_completion.install "completions/secrets.bash" => "secrets"
zsh_completion.install "completions/secrets.zsh" => "_secrets"
fish_completion.install "completions/secrets.fish" => "secrets.fish"
nfpms:
- id: secrets
package_name: secrets
file_name_template: "{{.ProjectName}}_{{.Tag}}_{{.Os}}_{{.Arch}}"
vendor: Umputun
homepage: https://github.com/umputun/secrets
maintainer: Umputun <umputun@gmail.com>
description: Self-hosted service for sharing encrypted secrets with one-time access
license: MIT
formats:
- deb
- rpm
bindir: /usr/bin
epoch: 1
release: 1
contents:
- src: completions/secrets.bash
dst: /usr/share/bash-completion/completions/secrets
- src: completions/secrets.zsh
dst: /usr/share/zsh/vendor-completions/_secrets
- src: completions/secrets.fish
dst: /usr/share/fish/vendor_completions.d/secrets.fish
================================================
FILE: .zed/tasks.json
================================================
[
{
"label": "build: binary",
"command": "make build",
"cwd": "$ZED_WORKTREE_ROOT"
},
{
"label": "test: race detector",
"command": "make race",
"cwd": "$ZED_WORKTREE_ROOT"
},
{
"label": "test: coverage html",
"command": "make coverage && open coverage.html",
"cwd": "$ZED_WORKTREE_ROOT"
},
{
"label": "e2e: headless",
"command": "make e2e",
"cwd": "$ZED_WORKTREE_ROOT"
},
{
"label": "e2e: with browser",
"command": "make e2e-ui",
"cwd": "$ZED_WORKTREE_ROOT"
},
{
"label": "e2e: setup playwright",
"command": "make e2e-setup",
"cwd": "$ZED_WORKTREE_ROOT"
},
{
"label": "docker: build image",
"command": "make docker",
"cwd": "$ZED_WORKTREE_ROOT"
},
{
"label": "run: dev compose",
"command": "make run-dev",
"cwd": "$ZED_WORKTREE_ROOT",
"use_new_terminal": true,
"allow_concurrent_runs": false
}
]
================================================
FILE: CHANGELOG.md
================================================
# Changelog
All notable changes to this project are documented in this file.
## [2.2.6] - 2026-04-01
### Fixed
- Fix long filename wrapping in file upload (#114)
- Add directory field to publish formula to Formula/
### Changed
- Add shell completions for bash, zsh, and fish (#105)
- Update go dependencies (x/crypto, sqlite, slack-go, x/net, x/sys)
- Bump the github-actions-updates group with 6 updates (#113)
- Bump github.com/go-pkgz/lgr from 0.12.1 to 0.12.3 (#112)
## [2.2.5] - 2026-01-16
### Fixed
- Enforce minimum 16-byte sign key length at startup to prevent weak encryption keys
### Changed
- Extract inline JavaScript to external app.js for CSP compliance (#103)
- Switch Docker image to scratch-based for smaller footprint
- Use /data directory for SQLite storage in Docker by default
- Bump golang.org/x/crypto from 0.46.0 to 0.47.0 (#102)
- Bump github.com/go-pkgz/rest from 1.20.7 to 1.21.0 (#101)
- Bump github-actions-updates group (#100)
## [2.2.4] - 2025-12-30
### Fixed
- Prevent JavaScript re-execution on HTMX boosted navigation (modal buttons not working after page reload)
## [2.2.3] - 2025-12-30
### Fixed
- Improve card header layout with proper alignment of title and mode toggle
- Replace iMessage with Signal in secure messenger examples
## [2.2.2] - 2025-12-29
### Fixed
- Show friendly 404 error page for non-existent messages instead of confusing PIN form
## [2.2.1] - 2025-12-29
### Fixed
- Add version-based cache busting for static assets to prevent browser cache issues after deployments
## [2.2.0] - 2025-12-29
### Added
- Optional PIN protection for secrets (#98)
- Users can skip PIN for convenience while maintaining encryption
- Secrets without PIN are directly accessible via link
- Ciphertext format validation for UI routes (#97)
### Changed
- Bump modernc.org/sqlite from 1.41.0 to 1.42.2 (#99)
## [2.1.0] - 2025-12-28
### Changed
- Replace paranoid mode with hybrid encryption (#96)
- UI always uses client-side AES-128-GCM encryption, API uses server-side encryption
- Add RequireHTMX middleware to ensure JavaScript for UI encryption
- Add security headers middleware (CSP, X-Frame-Options, HSTS)
## [2.0.0] - 2025-12-26
### Added
- SQLite storage engine as alternative to BoltDB and in-memory (#96)
- Paranoid mode for zero-knowledge client-side AES-128-GCM encryption
- Server stores only encrypted blobs, never sees plaintext
- Encryption key derived from PIN, never transmitted to server
- Visual indicator with shield icon when paranoid mode active
- Playwright E2E test suite for paranoid mode
### Changed
- **BREAKING**: Replace BoltDB with SQLite for persistent storage
- `--engine=BOLT` option removed
- Existing BoltDB databases not migrated automatically
- Module path changed to `github.com/umputun/secrets/v2`
## [1.9.3] - 2025-12-22
### Changed
- Update go-pkgz/rest to v1.20.6 for CDN-compatible RealIP middleware
## [1.9.2] - 2025-12-22
### Added
- Playwright E2E test suite for web UI (#93)
- Improved audit logging for security and usage analytics (#94)
## [1.9.1] - 2025-12-18
### Fixed
- Security review findings in server package
## [1.9.0] - 2025-12-18
### Added
- Email sharing for secure links (#92)
- SMTP configuration with TLS/STARTTLS support
- Custom email templates
- Rate limiting on email sending
## [1.8.1] - 2025-12-16
### Added
- GoReleaser for binary releases
- Comprehensive SEO improvements
### Fixed
- CI workflow for proper release builds
- Digits-only input validation for PIN fields
## [1.8.0] - 2025-12-16
### Changed
- Complete frontend redesign with modern dark theme (#91)
## [1.7.1] - 2025-12-16
### Fixed
- Content-Type header not being set for JSON responses (#90)
## [1.7.0] - 2025-12-16
### Added
- Optional authentication for link generation (#89)
- bcrypt password hash configuration
- Session-based authentication with configurable TTL
- Encrypted file upload and download support (#88)
- Configurable max file size
- Content-type preservation
- One-time download with PIN protection
## [1.6.3] - 2025-10-18
### Fixed
- Version detection in Docker builds using baseimage script
## [1.6.2] - 2025-10-18
### Added
- Multiple domains support via comma-separated list (#79)
- Comprehensive SEO improvements (#76)
- Open Graph and Twitter Card meta tags
- JSON-LD structured data
- Sitemap and robots.txt
### Changed
- Replaced purple/indigo color scheme with professional blue palette
- Simplified theme toggle to two states (light/dark) with system preference detection
### Fixed
- Graceful server shutdown with 10-second timeout
- IPv6 URL generation with proper bracketing
## [1.6.1] - 2025-08-26
### Fixed
- Regression on ping endpoints (#72)
## [1.6.0] - 2025-08-21
### Changed
- Migrate from chi router to go-pkgz/routegroup for Go stdlib alignment
- Update tollbooth to v8 for improved rate limiting
- Enhanced logging for message access events
- Remove pkg/errors dependency in favor of standard library
- Routes use Go 1.22+ patterns with method prefixes
## [1.5.1] - 2025-08-20
### Fixed
- PIN_SIZE configuration not working in UI (#70)
- Dynamic PIN length in web interface
- CLI flag typo: `--pinszie` → `--pinsize`
- Pluralization in duration display (#69)
- Correctly shows singular forms for single units
## [1.5.0] - 2025-08-19
### Added
- Customizable branding via `--branding` parameter
- Allows company-specific application title
- Support for environment variable (`BRANDING`)
## [1.4.0] - 2025-08-19
### Added
- Complete UI redesign with modern card-based layout
- Light/dark/auto theme support with persistent cookies
- HTMX v2 for dynamic interactions without JavaScript
- Copy feedback with server-side popups
- Copyright footer with dynamic year
### Changed
- Replaced emoji icons with accessible SVG icons
- Improved mobile responsiveness
- Enhanced accessibility with prefers-reduced-motion support
- Removed all Bootstrap dependencies
- Updated to Go 1.24
- Configured Dependabot for security updates only
### Fixed
- HTMX error handling for invalid PIN entry
- XSS vulnerability in copy feedback
- Embedded static files serving
- Theme toggle icon sizing and positioning
- Improved test coverage from 40.7% to 82.7%
## [1.3.0] - 2024-09-16
### Changed
- Code refactor for configurable protocol (#40, #41, #43)
- Updated Go version and dependencies (#44)
- Pin golangci-lint version (#37)
### Added
- Dependabot updates for GitHub Actions and Go modules (#36)
- Integrations section in README (#35)
## [1.2.4] - 2024-01-13
### Changed
- Bump dependencies
## [1.2.0] - 2023-10-08
### Changed
- Replace separate UI with embedded HTMX-based interface (#31, #32, #33)
- Remove old frontend
### Added
- Improved test coverage for messager (#30)
## [1.1.0] - 2021-03-16
### Changed
- Update JavaScript dependencies
- Remove external nacl and rewriter middleware
- Switch to current Go version
## [1.0.0] - 2020-02-21
Initial release.
### Added
- REST API for encrypted message storage and retrieval
- Web UI for message creation
- PIN-protected message access with attempt limiting
- Configurable message expiration
- In-memory and BoltDB storage engines
- Docker deployment support
================================================
FILE: CLAUDE.md
================================================
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
Safesecret is a Go-based web service for sharing sensitive information securely. It encrypts messages with a PIN, stores them temporarily, and allows one-time retrieval. The service uses SQLite for storage (both in-memory and persistent modes).
**Hybrid Encryption:** Route-based encryption mode where UI (web browser) always uses zero-knowledge client-side encryption (Web Crypto API AES-128-GCM), while API always uses server-side encryption. This provides maximum security for interactive users while maintaining API simplicity.
## Build and Development Commands
### Run the application
```bash
# Build and run locally (single domain)
cd app && go build -o secrets && ./secrets --key=<SIGN_KEY> --domain=localhost --protocol=http
# Build and run locally (multiple domains)
cd app && go build -o secrets && ./secrets --key=<SIGN_KEY> --domain="localhost,127.0.0.1" --protocol=http
# Run with Docker (development)
docker-compose -f docker-compose-dev.yml up
```
### Testing
```bash
# Run all tests
go test -v -timeout=60s -covermode=count -coverprofile=coverage.out ./...
# Run tests with race detection
go test -race ./...
# Run specific test
go test -run TestMessageProc ./app/messager
# Generate coverage report
go test -coverprofile=coverage.out ./... && go tool cover -html=coverage.out
```
### Linting and Formatting
```bash
# Run linter (from project root)
golangci-lint run
# Format code
gofmt -s -w $(find . -type f -name "*.go" -not -path "./vendor/*")
# Run goimports
goimports -w $(find . -type f -name "*.go" -not -path "./vendor/*")
```
## Architecture
### Package Structure
- **app/main.go** - Entry point, initializes storage engine, crypter, and starts server
- **app/messager/** - Core business logic for message encryption/decryption and storage operations
- Uses injected `Engine` interface for storage abstraction
- Encrypts messages with user-provided PIN (hashed with bcrypt)
- Implements rate limiting on PIN attempts
- **app/server/** - HTTP REST API and web UI serving
- Handles routing with chi/v5
- Implements middleware for rate limiting, logging, and request validation
- Serves both API endpoints and web UI templates
- **app/store/** - Storage layer implementations
- `Engine` interface with `Save`, `Load`, `IncErr`, and `Remove` methods
- SQLite-based implementation (both in-memory and file-backed)
- Short 12-char base62 IDs with unbiased rejection sampling
- **app/server/assets/** - Frontend assets embedded via Go 1.16+ embed
- Static HTML/CSS/JS for web interface
- Templates for dynamic content rendering
### Key Interfaces
**Messager** (app/server/server.go):
```go
type Messager interface {
MakeMessage(req messager.MsgReq) (result *store.Message, err error)
LoadMessage(key, pin string) (msg *store.Message, err error)
IsFile(key string) bool // checks if message is a file without decrypting (false for ClientEnc)
}
```
**Engine** (app/messager/messeger.go):
```go
type Engine interface {
Save(ctx context.Context, msg *store.Message) (err error)
Load(ctx context.Context, key string) (result *store.Message, err error)
IncErr(ctx context.Context, key string) (count int, err error)
Remove(ctx context.Context, key string) (err error)
}
```
**Crypter** (app/messager/messeger.go):
```go
type Crypter interface {
Encrypt(req Request) (result []byte, err error)
Decrypt(req Request) (result []byte, err error)
}
```
### Data Flow
1. User submits message + PIN via web UI or API
2. Server validates input (PIN size, expiration limits)
3. MessageProc hashes PIN with bcrypt, encrypts message data
4. Encrypted message saved to storage engine with UUID key and expiration
5. For retrieval: validate PIN attempts, decrypt if correct, delete after successful read
### File Message Format
File messages use a distinct storage format with encrypted metadata:
- **Stored format**: `!!FILE!!<encrypted blob>`
- **Encrypted blob contains**: `filename!!content-type!!\n<binary data>`
- Only the `!!FILE!!` prefix is unencrypted (used to detect file vs text messages)
- Filename and content-type are encrypted together with file content for privacy
**Validation requirements** (to prevent header parsing issues):
- Filename: no `!!`, `\n`, `\r`, `\x00`, `/`, `\`, `..`, control chars; max 255 chars
- Content-type: no `!!`, `\n`, `\r`, `\x00`
**Key functions**:
- `IsFileMessage(data)` - checks for `!!FILE!!` prefix
- `ParseFileHeader(data)` - extracts filename, content-type, data start position (4KB scan limit)
- `IsFile(key)` - loads message to check type without decrypting (used for UI to show "Download" vs "Reveal")
### Hybrid Encryption Architecture
Route-based encryption where UI uses client-side encryption and API uses server-side encryption:
**Encryption modes:**
- **UI routes** (`/generate-link`): Always client-side encryption (`ClientEnc=true`)
- **API routes** (`/api/v1/message`): Always server-side encryption (`ClientEnc=false`)
- The `ClientEnc` field in `store.Message` tracks which mode was used
**Client-side encryption (UI):**
- Client generates 128-bit AES-GCM key per message (22-char base64url)
- Key stored only in URL fragment (`#key`) - never sent to server
- Encryption/decryption happens entirely in browser via Web Crypto API
- Server stores opaque encrypted blobs, validates PIN via bcrypt hash
- RequireHTMX middleware ensures JavaScript is present (prevents plaintext storage)
**Payload format (client-encrypted, before encryption):**
- Text: `0x00 || utf8(plaintext)`
- File: `0x01 || len_be16(filename) || filename || len_be16(contentType) || contentType || data`
**Ciphertext format:** `base64url(IV[12] || encrypted || tag[16])`
**Implementation details:**
- `msg.ClientEnc` field determines encryption/decryption path on retrieval
- `IsFile()` returns false for `ClientEnc=true` messages (server cannot inspect content)
- Size limits adjusted: `MaxFileSize * 1.4` for base64 overhead (UI route)
- Client-side crypto module: `app/server/assets/static/js/crypto.js`
### Optional PIN Architecture
When `--allow-no-pin` / `ALLOW_NO_PIN` is enabled, secrets can be created without PIN protection for use cases where the sharing channel is already secure (Signal or other E2E encrypted messengers).
**Feature control:**
- Operator-controlled flag (default: false)
- Only affects web UI routes - API always requires PIN
- `AllowNoPin` in server.Config, passed to templates via `templateData.AllowNoPin`
**Creation flow (UI only):**
1. User leaves PIN field empty during secret creation
2. JavaScript detects empty PIN, shows confirmation modal
3. On confirm: proceeds with client-side encryption, stores empty `PinHash`
4. On cancel: refocuses PIN field
**Storage:**
- `PinHash` stored as empty string (`""`) for PIN-less messages
- No schema changes - empty string is valid
- `MsgReq.AllowEmptyPin` flag controls whether empty PIN is accepted
**Retrieval flow:**
- `HasPin(key)` checks if message requires PIN (`msg.PinHash != ""`)
- UI adapts: PIN-less shows "Reveal Secret" button, with-PIN shows decrypt form
- `checkHash()` returns true when both stored hash and provided PIN are empty
**Key methods:**
- `HasPin(ctx, key) (bool, error)` - checks if message requires PIN
- `checkHash(msg, pin)` - returns true when both are empty
- `validatePIN(pin, pinValues, pinSize) error` - validates PIN format
### Middleware Architecture
- **rest.RealIP middleware** - Extracts client IP from headers for CDN/proxy compatibility (from go-pkgz/rest v1.20.6+)
- Header priority: X-Real-IP → CF-Connecting-IP → leftmost public IP in X-Forwarded-For → RemoteAddr
- Filters private/loopback/link-local IPs automatically
- **HashedIP middleware** - Anonymizes client IP using HMAC-SHA1 hash (12-char hex) for audit logging
- Must run after rest.RealIP middleware (reads `r.RemoteAddr` set by RealIP)
- **Logger middleware** - Logs requests with masked sensitive paths (PINs) and anonymized IPs
- Must run after HashedIP middleware (reads hashed IP from context)
- **Middleware chain order matters**: rest.RealIP → HashedIP → Logger
### API Endpoints
- `POST /api/v1/message` - Create encrypted message
- `GET /api/v1/message/:key/:pin` - Retrieve and decrypt message
- `GET /api/v1/params` - Get service configuration
- `GET /ping` or `GET /api/v1/ping` - Health check
## Configuration
Key configuration via environment variables or flags:
- `SIGN_KEY` - Encryption signing key (required)
- `ENGINE` - Storage engine: MEMORY or SQLITE (default: MEMORY)
- `SQLITE_FILE` - SQLite database file path (default: /data/secrets.db in Docker, /tmp/secrets.db otherwise)
- `MAX_EXPIRE` - Maximum message lifetime (default: 24h)
- `PIN_SIZE` - PIN length in characters (default: 5)
- `PIN_ATTEMPTS` - Max failed PIN attempts (default: 3)
- `ALLOW_NO_PIN` - Allow creating secrets without PIN protection (default: false)
- `DOMAIN` - Allowed domain(s), supports comma-separated list (e.g., "example.com,alt.example.com")
- `PROTOCOL` - http or https (default: https)
- `LISTEN` - Server listen address, ip:port or :port format (default: :8080)
- `FILES_ENABLED` - Enable file uploads (default: false)
- `FILES_MAX_SIZE` - Maximum file size in bytes (default: 1MB)
- `AUTH_HASH` - bcrypt hash of password (enables auth for link generation if set)
- `AUTH_SESSION_TTL` - Session lifetime (default: 168h / 7 days)
## Testing Approach
- Table-driven tests using testify/assert
- Mock generation with moq for interfaces (see go:generate directives)
- Test files follow naming convention: `*_test.go` alongside source files
- Integration tests for storage engines with cleanup
## Dependencies
Core libraries used:
- `github.com/go-chi/chi/v5` - HTTP routing
- `github.com/go-pkgz/lgr` - Structured logging
- `github.com/go-pkgz/rest` - REST middleware utilities (v1.20.6+ for CDN-compatible RealIP)
- `modernc.org/sqlite` - Pure Go SQLite storage engine
- `golang.org/x/crypto` - Encryption and bcrypt hashing
- `github.com/stretchr/testify` - Testing assertions
- `github.com/didip/tollbooth` - Rate limiting
## Frontend Architecture
### Template System
- Go html/template with modular structure: base template (`index.tmpl.html`) + named blocks
- Partials in `app/server/assets/html/partials/` for reusable components (`decoded-message.tmpl.html`, `secure-link.tmpl.html`)
- HTMX integration for dynamic updates without page reloads
- Template inheritance pattern with `{{define "base"}}` and `{{template "main" .}}`
### Design System
- CSS custom properties-based design system with comprehensive theming
- 8px grid spacing system: `--spacing-xs` (4px) through `--spacing-5xl` (96px)
- Typography scale with Inter (UI) and Poppins (branding) fonts
- Light/dark theme support via CSS custom properties and `[data-theme]` selectors
- SVG icon system with `currentColor` for automatic theme adaptation
### Static Assets Organization
- CSS: Design system approach with modular sections (variables, typography, components)
- JavaScript: External `app.js` file for all application logic (CSP-compliant, no inline scripts)
- Icons: Inline SVG for consistency and theming
- Fonts: Google Fonts integration with preconnect optimization
### Local Development Configuration
- Server requires explicit local config: `--domain=localhost:8080 --protocol=http`
- Default protocol is HTTPS, must override for local development
- Link generation uses request domain if allowed, falls back to first configured domain
- Multiple domains supported via comma-separated list: `--domain="example.com,alt.example.com"`
- **Embedded assets require rebuild**: UI assets (CSS, JS, templates) are embedded via `//go:embed`. Changes to `app/server/assets/` files require rebuilding and restarting the server. After killing the server, verify it stopped with `curl http://localhost:8080/ping` before restarting.
## HTMX Implementation
### Version and Extensions
- HTMX v2.0.3 with response-targets extension for proper error handling
- Server-driven UI pattern with minimal client-side JavaScript
- Uses `hx-target-[status]` attributes for HTTP status-specific targeting (400, 403, 404, 500)
### Form Handling Pattern
- Forms use `hx-post` with `hx-target="#form-card"` and `hx-swap="outerHTML"` to replace entire form with result
- Error handling via response-targets: `hx-target-400="#form-errors"` for validation errors
- Loading indicators with `hx-indicator="#form-spinner"` for visual feedback during requests
### Theme System
- Server-side theme switching via POST /theme endpoint
- Theme stored in browser cookies (1-year expiry) for stateless per-user preferences
- Theme cycling: light → dark → auto → light
- Uses `HX-Refresh: true` header to trigger full page reload on theme change
- Template rendering passes theme to all views via `getTheme(r)` helper
### JavaScript Architecture (CSP-Compliant)
- All JavaScript in external `app/server/assets/static/js/app.js` file
- No inline scripts or `hx-on::` handlers (enables strict CSP with `script-src 'self'`)
- Event delegation pattern with data attributes (`data-action`, `data-numeric-only`, etc.)
- MutationObserver for `data-autofocus` on dynamically loaded content
- Script tags: HTMX core, response-targets extension, crypto.js, app.js
### Web Endpoints Structure
- Web UI endpoints grouped separately from API endpoints in router
- Web handlers in server/web.go, API handlers in server/server.go
- Template-specific controllers suffix: `*ViewCtrl` for pages, `*Ctrl` for actions
- All web controllers pass CurrentYear and Theme to templates for consistent rendering
### HTTP Status Code Conventions
- 200: Successful operations and normal page renders
- 400: Validation errors (triggers error display in form)
- 403: Authentication failures (wrong PIN)
- 404: Resource not found (expired/missing messages)
- HTMX requests return appropriate status codes, non-HTMX fallback to 200 with error template
### Dynamic Content Patterns
- **Autofocus on HTMX-loaded content**: `autofocus` attribute doesn't work on dynamically loaded content. Add `data-autofocus` attribute to the element - app.js uses MutationObserver to detect and focus these elements automatically.
- **Form state preservation after popup**: `HX-Refresh: true` causes full page reload, losing form data. Better pattern: return `HX-Trigger: eventName` header + on form use `hx-trigger="submit, eventName from:body"` to re-submit with preserved data (works with multipart file uploads too).
- **HX-Trigger event targeting**: Events from `HX-Trigger` header dispatch to the *target* element. To catch on other elements, use `hx-trigger="eventName from:body"` syntax.
- **Event handlers via data attributes**: Use `data-action="action-name"` instead of inline onclick/hx-on:: handlers. app.js handles these via event delegation.
### Template Data Pattern
- `templateData` struct wraps all template variables with consistent fields:
- Form: Contains form-specific data and validation
- PinSize: Configuration for PIN input rendering
- CurrentYear: For copyright footer
- Theme: Current user theme preference
## CI/CD Pipeline
### GitHub Actions Workflow
- CI runs on every push and pull request using `.github/workflows/ci.yml`
- Tests execute with 60s timeout and coverage reporting
- GolangCI-Lint v2.3.1 enforces code quality standards
- Docker images automatically built and pushed to DockerHub on master and tagged releases
- Tagged releases deploy as both `umputun/secrets:vX.Y.Z` and `umputun/secrets:latest`
### Release Process
- Hotfix releases follow semantic versioning (v1.5.0 → v1.5.1 for bug fixes)
- GitHub releases titled as "Version X.Y.Z" (no "v" prefix in title)
- Release notes should avoid emojis in GitHub communications
- Docker images available immediately after tagged release CI completion
## Template Functions
### Custom Template Functions
- `until(n int)`: Generates slice of integers from 0 to n-1 for iteration
- `add(a, b int)`: Addition function for template arithmetic
- Template FuncMap defined in `app/server/web.go` during template parsing
- Used for dynamic content generation based on configuration (e.g., PIN_SIZE)
## Configuration Nuances
### CLI Flags vs Environment Variables
- Both CLI flags and environment variables supported for all configuration
- CLI flag names use lowercase with no underscores (e.g., `--pinsize`)
- Environment variables use uppercase with underscores (e.g., `PIN_SIZE`)
- Some historical typos may exist in CLI flags but environment variables are reliable
## Email/SMTP Configuration
### Mailgun SMTP Settings
- **Use port 465 with implicit TLS** (`--email.tls`), NOT port 587 with STARTTLS
- Mailgun requires IP allowlisting for SMTP authentication (implemented April 2024)
- Authentication failures (535) often indicate IP not in allowlist, not wrong credentials
- Test SMTP credentials via Mailgun HTTP API first: `curl --user 'user:pass' https://api.mailgun.net/v3/domain/messages`
### Email Feature Flags
- `--email.enabled` - enables email sharing feature
- `--email.host`, `--email.port`, `--email.username`, `--email.password` - SMTP server config
- `--email.tls` - use implicit TLS (port 465), `--email.starttls` - use STARTTLS (port 587)
- `--email.from` - sender address with display name format: `"Name <email@domain>"`
## Testing Patterns
### Local Testing Workflow
- Port conflicts common during testing (8080 often in use)
- Tests may fail locally if port is occupied but pass in CI
- Build binary embeds UI assets, no need for `--web` flag after building
- Run formatter, goimports, and unfuck-ai-comments before committing
- **AUTH_HASH in environment**: When testing without auth, use `--auth.hash=""` explicitly - the env may have AUTH_HASH set which overrides the default
### E2E Tests
- Located in `e2e/` directory, require build tag: `go test -tags=e2e ./e2e/...`
- Use Playwright for browser automation
- **Timeout**: Use 120 seconds max (`timeout 120 go test -tags=e2e ./e2e/...`)
- **Failfast**: Use `-failfast` to stop on first failure (`go test -failfast -tags=e2e ./e2e/...`)
- Run headless by default, set `E2E_HEADLESS=false` for UI debugging
## Deployment Process
### Beta Deployment (beta.safesecret.info)
- Master image deploys to beta after CI passes
- Server: ssh to eclipse-love.exe.xyz
- Deploy commands:
```bash
cd /srv
docker compose pull
docker compose up -d
```
- Verify deployment: `curl -I https://beta.safesecret.info/ping` and check `App-Version` header
================================================
FILE: Dockerfile
================================================
ARG TZ=America/Chicago
FROM umputun/baseimage:buildgo-latest AS build-backend
ARG CI
ARG GIT_BRANCH
ARG SKIP_TEST
ARG GITHUB_SHA
ADD . /build/secrets
WORKDIR /build/secrets
# run tests and linters
RUN \
if [ -z "$SKIP_TEST" ] ; then \
go test -timeout=30s ./... && \
golangci-lint run ; \
else echo "skip tests and linter" ; fi
RUN \
version=$(/script/version.sh) && \
echo "version=$version" && \
cd app && go build -o /build/secrets.bin -ldflags "-X main.revision=${version} -s -w"
# prepare empty /tmp with sticky bit for scratch image
RUN rm -rf /build/tmp && mkdir -p /build/tmp && chmod 1777 /build/tmp
FROM umputun/baseimage:scratch-latest
# enables automatic changelog generation by tools like Dependabot
LABEL org.opencontainers.image.source="https://github.com/umputun/secrets"
COPY --from=build-backend /build/secrets.bin /srv/secrets
# create /data for sqlite storage (mount a volume here for persistence)
COPY --from=build-backend /build/tmp /data
ENV SQLITE_FILE=/data/secrets.db
WORKDIR /srv
EXPOSE 8080
USER app
CMD ["/srv/secrets"]
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2025 Umputun
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: Makefile
================================================
B=$(shell git rev-parse --abbrev-ref HEAD)
BRANCH=$(subst /,-,$(B))
GITREV=$(shell git describe --abbrev=7 --always --tags)
REV=$(GITREV)-$(BRANCH)-$(shell date +%Y%m%d-%H:%M:%S)
.PHONY: build test lint race coverage docker docker-push run-dev clean info help e2e-setup e2e e2e-ui
build: info
cd app && go build -ldflags "-X main.revision=$(REV) -s -w" -o ../secrets
test:
go test -v -timeout=60s ./...
lint:
golangci-lint run
race:
go test -race -timeout=60s ./...
coverage:
go test -v -timeout=60s -covermode=count -coverprofile=coverage.out.tmp ./...
grep -v "mock_" coverage.out.tmp > coverage.out
rm -f coverage.out.tmp
go tool cover -html=coverage.out -o coverage.html
@echo "coverage report: coverage.html"
docker:
docker build -t secrets:$(BRANCH) .
docker-push:
docker buildx build -t umputun/secrets:$(BRANCH) --platform linux/amd64,linux/arm64 --push .
run-dev:
docker compose -f docker-compose-dev.yml up --build
clean:
rm -f secrets coverage.out coverage.out.tmp coverage.html
info:
@echo "revision: $(REV)"
e2e-setup:
go run github.com/playwright-community/playwright-go/cmd/playwright@latest install --with-deps chromium
e2e:
go test -v -count=1 -timeout=5m -tags=e2e ./e2e/...
e2e-ui:
E2E_HEADLESS=false go test -v -count=1 -timeout=10m -tags=e2e ./e2e/...
help:
@echo "targets:"
@echo " build - build binary to ./secrets"
@echo " test - run tests"
@echo " lint - run golangci-lint"
@echo " race - run tests with race detector"
@echo " coverage - generate coverage report"
@echo " docker - build docker image for current platform"
@echo " docker-push - build and push multi-arch image (amd64, arm64)"
@echo " run-dev - run local dev with docker compose"
@echo " clean - remove build artifacts"
@echo " info - show version info"
@echo " e2e-setup - install playwright browsers"
@echo " e2e - run e2e tests (headless)"
@echo " e2e-ui - run e2e tests with visible browser"
================================================
FILE: README.md
================================================
# Safe Secrets - safe(r) and easy way to transfer sensitive data
[](https://github.com/umputun/secrets/actions) [](https://goreportcard.com/report/github.com/umputun/secrets) [](https://coveralls.io/github/umputun/secrets?branch=master) [](https://hub.docker.com/r/umputun/secrets/)
The primary use case is sharing sensitive data securely - messages that self-destruct, can only be accessed once, and are protected by an easy-to-share PIN code. I got tired of the usual "security" approach of sending username and password in two separate emails - that's just a joke. So I built this as a simple and better alternative to passing passwords around.
## Quick Start
```bash
# run with docker
docker run -p 8080:8080 -e SIGN_KEY=your-random-secret-key -e DOMAIN=localhost -e PROTOCOL=http umputun/secrets
# or build and run locally
cd app && go build -o secrets && ./secrets -k "your-secret-key" -d localhost -p http
```
Then open http://localhost:8080 in your browser.
## How It Works
1. Enter your secret message (or upload a file)
2. Set expiration time and a PIN
3. Get a one-time link to share
Your recipient opens the link, enters the PIN, and sees the message. That's it. The message is deleted immediately after reading, and wrong PIN attempts are limited (default: 3 tries).
**Try it live:** [safesecret.info](https://safesecret.info) - feel free to use it if you're crazy enough to trust me, or run your own instance.
<details>
<summary><b>Screenshots</b> (click to expand)</summary>
### Desktop View

### Dark Mode

### Mobile View

### PIN Entry

### Decoded Message

</details>
## How Safe Is This Thing
- Messages are encrypted with your PIN (which is also hashed) - the original is never stored
- Nothing sensitive in logs
- Nothing on disk by default (in-memory storage)
- Messages are permanently destroyed after reading or expiration
- An attacker would need both the link AND the PIN to access anything
- **Zero-knowledge by default** for web UI: all encryption happens in your browser
_Feel free to suggest any other ways to make the process safer._
### Encryption Architecture
The service uses **hybrid encryption** based on how you access it:
**Web UI (zero-knowledge):**
- All encryption/decryption happens in your browser using Web Crypto API (AES-128-GCM)
- The server stores only encrypted blobs - it cannot read your messages
- The decryption key is stored in the URL fragment (`#key`) which never leaves your browser
- Even if the server is compromised, your secrets remain encrypted
**API (server-side):**
- Server handles encryption/decryption for API clients
- Simpler integration - no client-side crypto needed
- Server encrypts with your PIN before storing
**Requirements for web UI:**
- HTTPS is required (Web Crypto API doesn't work on plain HTTP, except localhost)
- JavaScript must be enabled
- The full URL including the `#key` fragment must be shared - some apps strip URL fragments
**Trade-offs:**
- Server cannot distinguish text from files in web-created messages (all content is opaque)
- If you lose the URL fragment, the message is unrecoverable
### Security Architecture
**Encryption:**
- Server-side: AES-256-GCM for message encryption
- Client-side (web UI): AES-128-GCM via Web Crypto API
- PIN hashing: bcrypt (cost 14)
- Random key generation: 32-byte cryptographically secure
- Server rejects unencrypted content from web clients (ciphertext format validation)
**HTTP Security Headers:**
- `Content-Security-Policy`: restricts scripts, styles, fonts to trusted sources; `frame-ancestors 'none'`; `form-action 'self'`
- `Strict-Transport-Security`: HSTS with 1-year max-age (HTTPS only)
- `X-Frame-Options: DENY` - prevents clickjacking
- `X-Content-Type-Options: nosniff` - prevents MIME sniffing
- `Referrer-Policy: strict-origin-when-cross-origin`
- `Cache-Control`: `no-cache, no-store, must-revalidate` for dynamic content; long cache for static assets
**Rate Limiting:**
- API requests: 10 req/sec per IP (configurable via `--limit`)
- PIN attempts: 3 max per message (configurable via `--pinattempts`)
- Failed attempts permanently logged with anonymized IP
**Privacy:**
- IP addresses hashed with HMAC-SHA256 before logging (8-char prefix)
- Sensitive URL paths masked in logs (`/message/key/pin` → `/message/partial-key/*****`)
- No cookies except theme preference
- No analytics or tracking
## Installation
### Docker (Recommended)
**Simple setup:**
```bash
docker run -p 8080:8080 \
-e SIGN_KEY=your-long-random-secret \
-e DOMAIN=example.com \
-e PROTOCOL=https \
umputun/secrets
```
**Production setup with docker-compose:**
1. Download `docker-compose.yml` from this repo
2. Configure environment variables (see Configuration section below)
3. Run `docker-compose up -d`
For SSL termination, put a reverse proxy in front (e.g., [reproxy](https://github.com/umputun/reproxy), nginx, or traefik).
_See [docker-compose.yml](https://github.com/umputun/secrets/blob/master/docker-compose.yml) for a complete example._
#### Container Security
The Docker image is built on a minimal scratch-based image for security hardening:
- **Minimal attack surface**: No shell, package manager, or unnecessary utilities
- **Non-root user**: Runs as `app` user with UID/GID 1001
- **Small footprint**: ~21MB total image size
**Volume permissions**: The container stores SQLite data in `/data` by default. When mounting volumes for persistence, ensure the directory is accessible by UID 1001:
```bash
# Option 1: Set ownership on the host
mkdir -p /data/secrets && chown 1001:1001 /data/secrets
docker run -v /data/secrets:/data ... umputun/secrets
# Option 2: Run as your host user (e.g., UID 1000)
docker run --user 1000:1000 -v ./data:/data ... umputun/secrets
```
In docker-compose:
```yaml
services:
secrets:
image: umputun/secrets
user: "1000:1000" # run as your host user instead of default 1001
volumes:
- ./data:/data
```
Alternatively, use Docker named volumes which handle permissions automatically:
```yaml
services:
secrets:
image: umputun/secrets
# no user override needed - named volumes adapt to container's UID
volumes:
- secrets-data:/data
volumes:
secrets-data:
```
### Binary
Download from releases or build from source:
```bash
cd app && go build -o secrets
./secrets -k "your-secret-key" -d "example.com" -p https
```
### Running Tests
```bash
# Unit tests
go test ./...
# E2E tests (requires playwright setup)
make e2e-setup # one-time: install playwright browsers
make e2e # run e2e tests (headless)
make e2e-ui # run with visible browser for debugging
```
## Configuration
All options work as both CLI flags and environment variables.
### Core Options
| Flag | Env Variable | Default | Description |
|------|--------------|---------|-------------|
| `-k, --key` | `SIGN_KEY` | *required* | Signing key for encryption |
| `-d, --domain` | `DOMAIN` | *required* | Site domain(s), comma-separated for multiple |
| `-p, --protocol` | `PROTOCOL` | `https` | Site protocol (http/https) |
| `--listen` | `LISTEN` | `:8080` | Server listen address (ip:port or :port) |
| `--branding` | `BRANDING` | `Safe Secrets` | Application title |
| `--branding-url` | `BRANDING_URL` | `https://safesecret.info` | Branding link URL for emails |
| `--dbg` | - | `false` | Enable debug mode |
| `--proxy-security-headers` | `PROXY_SECURITY_HEADERS` | `false` | Disable security headers (when proxy handles them) |
### Message Settings
| Flag | Env Variable | Default | Description |
|------|--------------|---------|-------------|
| `--pinsize` | `PIN_SIZE` | `5` | PIN length in characters |
| `--expire` | `MAX_EXPIRE` | `24h` | Maximum message lifetime |
| `--pinattempts` | `PIN_ATTEMPTS` | `3` | Max wrong PIN attempts |
| `--allow-no-pin` | `ALLOW_NO_PIN` | `false` | Allow creating secrets without PIN protection |
When `--allow-no-pin` is enabled, users can skip PIN entry during secret creation. A confirmation modal ensures this is intentional. Use this for workflows where the sharing channel itself is already secure (e.g., Signal or other end-to-end encrypted messengers).
### Storage
| Flag | Env Variable | Default | Description |
|------|--------------|---------|-------------|
| `-e, --engine` | `ENGINE` | `MEMORY` | Storage engine: MEMORY or SQLITE |
| `--sqlite` | `SQLITE_FILE` | `/tmp/secrets.db` | SQLite database file path |
### File Uploads
Share files securely - they're encrypted with your PIN just like text messages and self-destruct after download. The filename is preserved but stored encrypted.
| Flag | Env Variable | Default | Description |
|------|--------------|---------|-------------|
| `--files.enabled` | `FILES_ENABLED` | `false` | Enable file uploads |
| `--files.max-size` | `FILES_MAX_SIZE` | `1048576` | Max file size in bytes (1MB) |
### Authentication
Optional password protection for creating secrets. When enabled, users must log in before they can generate links. Viewing/consuming secrets remains anonymous - no login required to open a link with the correct PIN.
| Flag | Env Variable | Default | Description |
|------|--------------|---------|-------------|
| `--auth.hash` | `AUTH_HASH` | *disabled* | bcrypt hash to enable auth |
| `--auth.session-ttl` | `AUTH_SESSION_TTL` | `168h` | Session lifetime (7 days) |
**Generate a bcrypt hash:**
```bash
# htpasswd (Apache utils)
htpasswd -bnBC 10 "" yourpassword | tr -d ':'
# mkpasswd (apt install whois)
mkpasswd -m bcrypt yourpassword
# Docker
docker run --rm caddy caddy hash-password --plaintext yourpassword
```
**Web UI:** Login popup appears when creating a secret. Sessions stored in cookies.
**API:** Requires HTTP Basic Auth with username `secrets` and your password.
### Email Sharing
Send secret links directly via email. Recipients receive a nicely formatted email with the link - they still need the PIN (share it separately for security).
| Flag | Env Variable | Default | Description |
|------|--------------|---------|-------------|
| `--email.enabled` | `EMAIL_ENABLED` | `false` | Enable email sharing |
| `--email.host` | `EMAIL_HOST` | *required* | SMTP server host |
| `--email.port` | `EMAIL_PORT` | `587` | SMTP server port |
| `--email.username` | `EMAIL_USERNAME` | - | SMTP auth username |
| `--email.password` | `EMAIL_PASSWORD` | - | SMTP auth password |
| `--email.from` | `EMAIL_FROM` | *required* | Sender address (e.g., `"App Name <noreply@example.com>"`) |
| `--email.tls` | `EMAIL_TLS` | `false` | Use TLS (not STARTTLS) |
| `--email.timeout` | `EMAIL_TIMEOUT` | `30s` | Connection timeout |
| `--email.template` | `EMAIL_TEMPLATE` | *built-in* | Custom email template path |
When enabled, a "Send Email" button appears after creating a secret link. The email includes a preview of the message body (customizable via template).
> [!WARNING]
> **Do not enable email sharing on public instances without authentication (`--auth.hash`).** Without auth, anyone can use your SMTP server to send emails to arbitrary addresses, which can be abused for spam or phishing. Always require authentication when email sharing is enabled on publicly accessible instances.
<details>
<summary><b>Mailgun SMTP Setup</b></summary>
Mailgun requires specific configuration:
```bash
--email.enabled \
--email.host=smtp.mailgun.org \
--email.port=465 \
--email.tls \
--email.username=postmaster@mg.yourdomain.com \
--email.password=your-mailgun-smtp-password \
--email.from="Your App <noreply@mg.yourdomain.com>"
```
**Important notes:**
- Use port **465 with `--email.tls`** (implicit TLS), not port 587 with STARTTLS
- Add your server's IP to Mailgun's **Authorized Recipients** or **IP Allowlist** (required since April 2024)
- Authentication failures (535) usually indicate IP not in allowlist, not wrong credentials
- Sandbox domains can only send to verified recipients
</details>
### Examples
```bash
# basic usage (web UI uses zero-knowledge encryption automatically)
./secrets -k "secret-key" -d "example.com"
# multiple domains
./secrets -k "secret-key" -d "example.com,alt.example.com"
# persistent storage
./secrets -k "secret-key" -d "example.com" -e SQLITE --sqlite=/data/secrets.db
# with file uploads (5MB limit)
./secrets -k "secret-key" -d "example.com" --files.enabled --files.max-size=5242880
# with authentication
./secrets -k "secret-key" -d "example.com" --auth.hash='$2a$10$...'
# with email sharing
./secrets -k "secret-key" -d "example.com" \
--email.enabled --email.host=smtp.example.com \
--email.from="Safe Secrets <noreply@example.com>"
```
## Architecture
**Safesecret** is a single binary with embedded web UI. Typical production setup:
- `secrets` container - handles API and serves the web interface (port 8080)
- reverse proxy - SSL termination ([reproxy](https://github.com/umputun/reproxy), nginx, traefik, etc.)
The app works fine without a proxy for development or if you're running behind a load balancer (AWS ALB, haproxy, etc.).
## Integrations
- [Raycast Extension](https://www.raycast.com/melonamin/safe-secret) - share text quickly from Raycast
- [Apple Shortcut](https://www.icloud.com/shortcuts/1d0a8d22c3884c8d80341ccffb502931) - adds Safesecret to Share menu on iOS/macOS
## API
Simple REST API for programmatic access.
### Health Check
```
GET /ping
```
```bash
$ curl https://safesecret.info/ping
pong
```
### Create Secret
```
POST /api/v1/message
```
Body: `{"message": "secret text", "exp": 3600, "pin": "12345"}`
- `exp` - expiration in seconds
- `pin` - PIN code (must match configured length)
- Requires Basic Auth when authentication is enabled (user: `secrets`)
```bash
$ curl -X POST https://safesecret.info/api/v1/message \
-H "Content-Type: application/json" \
-d '{"message": "my secret", "exp": 3600, "pin": "12345"}'
{
"exp": "2024-01-15T10:30:00Z",
"key": "f1acfe04-277f-4016-518d-16c312ab84b5"
}
```
### Retrieve Secret
```
GET /api/v1/message/:key/:pin
```
```bash
$ curl https://safesecret.info/api/v1/message/f1acfe04-277f-4016-518d-16c312ab84b5/12345
{
"key": "f1acfe04-277f-4016-518d-16c312ab84b5",
"message": "my secret"
}
```
### Get Configuration
```
GET /api/v1/params
```
```bash
$ curl https://safesecret.info/api/v1/params
{
"max_exp_sec": 86400,
"max_pin_attempts": 3,
"pin_size": 5,
"files_enabled": true,
"max_file_size": 1048576
}
```
================================================
FILE: app/email/email.go
================================================
package email
import (
"bytes"
"context"
_ "embed"
"errors"
"fmt"
"html/template"
"net/mail"
"net/url"
"os"
"strings"
"time"
"github.com/go-pkgz/notify"
)
//go:embed email.tmpl.html
var defaultEmailTemplate string
// Request contains all parameters for sending an email
type Request struct {
To string // recipient email address
Subject string // email subject
FromName string // display name for From header
Link string // the secret link to include in email body
}
//go:generate moq -out mocks/notifier_mock.go -pkg mocks -skip-ensure -fmt goimports . Notifier
// Notifier defines the interface for sending email notifications
type Notifier interface {
Send(ctx context.Context, destination, text string) error
}
// Config contains SMTP configuration
type Config struct {
Enabled bool
Host string
Port int
Username string
Password string
From string // format: "Display Name <email>" or just "email"
TLS bool // implicit TLS (port 465)
StartTLS bool // STARTTLS upgrade (port 587)
InsecureSkipVerify bool // skip certificate verification
LoginAuth bool // use LOGIN auth instead of PLAIN
Timeout time.Duration
Template string // path to custom template file (optional)
Branding string // application name for email footer
BrandingURL string // link URL for branding in email footer
Notifier Notifier // optional, for testing; if nil, creates default SMTP notifier
}
// Sender sends emails with secret links using go-pkgz/notify
type Sender struct {
notifier Notifier
cfg Config
tmpl *template.Template
defaultFromName string // cached default from name
}
// ErrEmailDisabled indicates email feature is not enabled
var ErrEmailDisabled = errors.New("email is disabled")
// NewSender creates a new email sender with the given configuration
func NewSender(cfg Config) (*Sender, error) {
if !cfg.Enabled {
return nil, ErrEmailDisabled
}
if cfg.Host == "" {
return nil, errors.New("email host is required when email is enabled")
}
if cfg.From == "" {
return nil, errors.New("email from address is required when email is enabled")
}
// set defaults
if cfg.Port == 0 {
cfg.Port = 587
}
if cfg.Timeout == 0 {
cfg.Timeout = 30 * time.Second
}
// load template - use default unless custom template is configured
tmplContent := defaultEmailTemplate
if cfg.Template != "" {
content, readErr := os.ReadFile(cfg.Template)
if readErr != nil {
return nil, fmt.Errorf("failed to read email template file: %w", readErr)
}
tmplContent = string(content)
}
tmpl, err := template.New("email").Parse(tmplContent)
if err != nil {
return nil, fmt.Errorf("failed to parse email template: %w", err)
}
s := &Sender{
cfg: cfg,
tmpl: tmpl,
}
// create default notifier if not provided in config
if cfg.Notifier != nil {
s.notifier = cfg.Notifier
} else {
s.notifier = notify.NewEmail(notify.SMTPParams{
Host: cfg.Host,
Port: cfg.Port,
TLS: cfg.TLS,
StartTLS: cfg.StartTLS,
InsecureSkipVerify: cfg.InsecureSkipVerify,
LoginAuth: cfg.LoginAuth,
ContentType: "text/html",
Charset: "UTF-8",
Username: cfg.Username,
Password: cfg.Password,
TimeOut: cfg.Timeout,
})
}
// cache the default from name at construction time
s.defaultFromName = s.computeDefaultFromName()
return s, nil
}
// Send sends an email with the secret link
func (s *Sender) Send(ctx context.Context, req Request) error {
body, err := s.renderBody(req.Link, req.FromName)
if err != nil {
return fmt.Errorf("failed to render email body: %w", err)
}
fromAddr := s.buildFromAddress(req.FromName)
destination := s.buildMailtoDestination(req.To, req.Subject, fromAddr)
if err := s.notifier.Send(ctx, destination, body); err != nil {
return fmt.Errorf("failed to send email: %w", err)
}
return nil
}
// renderBody renders the email body with the given link and from name
func (s *Sender) renderBody(link, fromName string) (string, error) {
data := struct {
Link string
From string
Branding string
BrandingURL string
}{
Link: link,
From: fromName,
Branding: s.cfg.Branding,
BrandingURL: s.cfg.BrandingURL,
}
var buf bytes.Buffer
if err := s.tmpl.Execute(&buf, data); err != nil {
return "", fmt.Errorf("failed to execute email template: %w", err)
}
return buf.String(), nil
}
// buildFromAddress builds the From header value with display name
func (s *Sender) buildFromAddress(displayName string) string {
// extract email from configured From (might be "Name <email>" or just "email")
emailAddr := s.extractEmail(s.cfg.From)
if displayName == "" {
// use the original From as-is
return s.cfg.From
}
// build new From with custom display name
return fmt.Sprintf("%q <%s>", displayName, emailAddr)
}
// extractEmail extracts just the email address from a From string
func (s *Sender) extractEmail(from string) string {
addr, err := mail.ParseAddress(from)
if err != nil {
// assume it's already just an email address
return from
}
return addr.Address
}
// computeDefaultFromName computes the default from name from config or branding
func (s *Sender) computeDefaultFromName() string {
addr, err := mail.ParseAddress(s.cfg.From)
if err == nil && addr.Name != "" {
return addr.Name
}
return s.cfg.Branding
}
// GetDefaultFromName returns the cached default from name
func (s *Sender) GetDefaultFromName() string {
return s.defaultFromName
}
// buildMailtoDestination builds the mailto URL for go-pkgz/notify
func (s *Sender) buildMailtoDestination(recipient, subject, from string) string {
mailto := "mailto:" + recipient
params := url.Values{}
if subject != "" {
params.Set("subject", subject)
}
if from != "" {
params.Set("from", from)
}
if len(params) > 0 {
mailto += "?" + params.Encode()
}
return mailto
}
// IsValidEmail performs email validation using RFC 5322 parsing
func IsValidEmail(email string) bool {
addr, err := mail.ParseAddress(email)
if err != nil {
return false
}
// ensure the parsed address matches the input (no display name was provided)
return addr.Address == email
}
// MaskEmail masks an email address for logging (e.g., "user@example.com" -> "u***@example.com")
func MaskEmail(email string) string {
at := strings.Index(email, "@")
if at <= 0 {
return "***"
}
return email[:1] + "***" + email[at:]
}
================================================
FILE: app/email/email.tmpl.html
================================================
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Secure Message</title>
</head>
<body style="margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; background-color: #f8fafc;">
<table role="presentation" style="width: 100%; border-collapse: collapse;">
<tr>
<td style="padding: 40px 20px;">
<table role="presentation" style="max-width: 600px; margin: 0 auto; background-color: #ffffff; border-radius: 12px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);">
<tr>
<td style="padding: 40px;">
<h1 style="margin: 0 0 24px 0; color: #0f172a; font-size: 24px; font-weight: 600;">
You've received a secure message
</h1>
<p style="margin: 0 0 24px 0; color: #475569; font-size: 16px; line-height: 1.6;">
<strong>{{.From}}</strong> has shared a secure message with you.
</p>
<p style="margin: 0 0 24px 0; color: #475569; font-size: 16px; line-height: 1.6;">
Click the button below to access the message. This link can only be used once and will expire after viewing.
</p>
<p style="margin: 0 0 32px 0; padding: 16px; background-color: #fef3c7; border-radius: 8px; color: #92400e; font-size: 14px; line-height: 1.5;">
<strong>Important:</strong> You'll need a PIN to open this message. The sender should share it with you separately (e.g., via text message or phone call).
</p>
<table role="presentation" style="margin: 0 0 32px 0;">
<tr>
<td style="background: linear-gradient(135deg, #14b8a6 0%, #0d9488 100%); border-radius: 8px;">
<a href="{{.Link}}" style="display: inline-block; padding: 16px 32px; color: #ffffff; text-decoration: none; font-size: 16px; font-weight: 600;">
View Secure Message
</a>
</td>
</tr>
</table>
<p style="margin: 0 0 16px 0; color: #64748b; font-size: 14px; line-height: 1.5;">
Or copy and paste this link into your browser:
</p>
<p style="margin: 0 0 32px 0; color: #14b8a6; font-size: 14px; word-break: break-all;">
{{.Link}}
</p>
<hr style="border: none; border-top: 1px solid #e2e8f0; margin: 32px 0;">
<p style="margin: 0; color: #94a3b8; font-size: 12px; line-height: 1.5;">
This email was sent via <a href="{{.BrandingURL}}" style="color: #14b8a6; text-decoration: none;">{{.Branding}}</a>.
</p>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>
================================================
FILE: app/email/email_test.go
================================================
package email
import (
"context"
"errors"
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/umputun/secrets/v2/app/email/mocks"
)
func TestNewSender(t *testing.T) {
t.Run("disabled returns error", func(t *testing.T) {
sndr, err := NewSender(Config{Enabled: false, Branding: "Test Brand"})
require.ErrorIs(t, err, ErrEmailDisabled)
assert.Nil(t, sndr)
})
t.Run("enabled without host fails", func(t *testing.T) {
_, err := NewSender(Config{Enabled: true, From: "test@example.com", Branding: "Test Brand"})
require.Error(t, err)
assert.Contains(t, err.Error(), "host is required")
})
t.Run("enabled without from fails", func(t *testing.T) {
_, err := NewSender(Config{Enabled: true, Host: "smtp.example.com", Branding: "Test Brand"})
require.Error(t, err)
assert.Contains(t, err.Error(), "from address is required")
})
t.Run("enabled with valid config succeeds", func(t *testing.T) {
sndr, err := NewSender(Config{
Enabled: true,
Host: "smtp.example.com",
Port: 587,
From: "noreply@example.com",
Branding: "Test Brand",
})
require.NoError(t, err)
assert.NotNil(t, sndr)
})
t.Run("invalid template file fails", func(t *testing.T) {
_, err := NewSender(Config{
Enabled: true,
Host: "smtp.example.com",
From: "noreply@example.com",
Template: "/nonexistent/path/template.html",
Branding: "Test Brand",
})
require.Error(t, err)
assert.Contains(t, err.Error(), "failed to read email template")
})
t.Run("custom template file success", func(t *testing.T) {
// create temp file with valid template
tmpFile, err := os.CreateTemp("", "email_template_*.html")
require.NoError(t, err)
defer os.Remove(tmpFile.Name())
customTemplate := `<!DOCTYPE html><html><body>Custom: {{.Link}} from {{.From}}</body></html>`
_, err = tmpFile.WriteString(customTemplate)
require.NoError(t, err)
require.NoError(t, tmpFile.Close())
sndr, err := NewSender(Config{
Enabled: true,
Host: "smtp.example.com",
From: "noreply@example.com",
Template: tmpFile.Name(),
Branding: "Test Brand",
})
require.NoError(t, err)
assert.NotNil(t, sndr)
// verify custom template is used
body, err := sndr.renderBody("https://example.com/msg", "Test User")
require.NoError(t, err)
assert.Contains(t, body, "Custom:")
assert.Contains(t, body, "https://example.com/msg")
})
t.Run("invalid template syntax fails", func(t *testing.T) {
tmpFile, err := os.CreateTemp("", "bad_template_*.html")
require.NoError(t, err)
defer os.Remove(tmpFile.Name())
// template with invalid syntax
_, err = tmpFile.WriteString(`{{.Invalid syntax {{}}`)
require.NoError(t, err)
require.NoError(t, tmpFile.Close())
_, err = NewSender(Config{
Enabled: true,
Host: "smtp.example.com",
From: "noreply@example.com",
Template: tmpFile.Name(),
Branding: "Test Brand",
})
require.Error(t, err)
assert.Contains(t, err.Error(), "failed to parse email template")
})
}
func TestSender_renderBody(t *testing.T) {
sndr, err := NewSender(Config{
Enabled: true,
Host: "smtp.example.com",
From: "noreply@example.com",
Branding: "Safe Secrets",
BrandingURL: "https://safesecret.info",
})
require.NoError(t, err)
body, err := sndr.renderBody("https://example.com/message/abc123", "John Doe")
require.NoError(t, err)
assert.Contains(t, body, "https://example.com/message/abc123")
assert.Contains(t, body, "John Doe")
assert.Contains(t, body, "Safe Secrets")
assert.Contains(t, body, "https://safesecret.info")
assert.Contains(t, body, "View Secure Message")
}
func TestSender_extractEmail(t *testing.T) {
sndr := &Sender{}
tests := []struct {
name string
from string
expected string
}{
{"plain email", "test@example.com", "test@example.com"},
{"with display name", `"John Doe" <john@example.com>`, "john@example.com"},
{"angle brackets only", "<noreply@example.com>", "noreply@example.com"},
{"name and email", "John <john@example.com>", "john@example.com"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := sndr.extractEmail(tt.from)
assert.Equal(t, tt.expected, result)
})
}
}
func TestSender_computeDefaultFromName(t *testing.T) {
tests := []struct {
name string
from string
branding string
expected string
}{
{"plain email returns branding", "test@example.com", "TestBrand", "TestBrand"},
{"with display name returns it", `"John Doe" <john@example.com>`, "TestBrand", "John Doe"},
{"name without quotes returns it", "John Doe <john@example.com>", "TestBrand", "John Doe"},
{"angle brackets only returns branding", "<noreply@example.com>", "TestBrand", "TestBrand"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
sndr := &Sender{cfg: Config{From: tt.from, Branding: tt.branding}}
result := sndr.computeDefaultFromName()
assert.Equal(t, tt.expected, result)
})
}
}
func TestSender_buildFromAddress(t *testing.T) {
tests := []struct {
name string
configFrom string
displayName string
expected string
}{
{"empty display name uses config", "noreply@example.com", "", "noreply@example.com"},
{"custom display name", "noreply@example.com", "My App", `"My App" <noreply@example.com>`},
{"display name with config having display", `"Original" <noreply@example.com>`, "Custom", `"Custom" <noreply@example.com>`},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
sndr := &Sender{cfg: Config{From: tt.configFrom}}
result := sndr.buildFromAddress(tt.displayName)
assert.Equal(t, tt.expected, result)
})
}
}
func TestSender_buildMailtoDestination(t *testing.T) {
sndr := &Sender{}
t.Run("with subject and from", func(t *testing.T) {
result := sndr.buildMailtoDestination("user@example.com", "Test Subject", `"Sender" <sender@example.com>`)
assert.Contains(t, result, "mailto:user@example.com")
assert.Contains(t, result, "subject=")
assert.Contains(t, result, "from=")
})
t.Run("empty subject", func(t *testing.T) {
result := sndr.buildMailtoDestination("user@example.com", "", `"Sender" <sender@example.com>`)
assert.NotContains(t, result, "subject=")
assert.Contains(t, result, "from=")
})
}
func TestSender_GetDefaultFromName(t *testing.T) {
t.Run("returns cached display name from config", func(t *testing.T) {
sndr := &Sender{
cfg: Config{From: `"Safe Secrets" <noreply@example.com>`, Branding: "Fallback Brand"},
defaultFromName: "Safe Secrets", // cached value
}
result := sndr.GetDefaultFromName()
assert.Equal(t, "Safe Secrets", result)
})
t.Run("returns cached branding when no display name", func(t *testing.T) {
sndr := &Sender{
cfg: Config{From: "noreply@example.com", Branding: "Fallback Brand"},
defaultFromName: "Fallback Brand", // cached value
}
result := sndr.GetDefaultFromName()
assert.Equal(t, "Fallback Brand", result)
})
t.Run("via NewSender caches correctly", func(t *testing.T) {
sndr, err := NewSender(Config{
Enabled: true,
Host: "smtp.example.com",
From: `"Test App" <test@example.com>`,
Branding: "Branding",
})
require.NoError(t, err)
assert.Equal(t, "Test App", sndr.GetDefaultFromName())
})
}
func TestDefaultEmailTemplate(t *testing.T) {
// verify template contains expected placeholders and structure
assert.Contains(t, defaultEmailTemplate, "{{.Link}}")
assert.Contains(t, defaultEmailTemplate, "{{.From}}")
assert.Contains(t, defaultEmailTemplate, "{{.Branding}}")
assert.Contains(t, defaultEmailTemplate, "{{.BrandingURL}}")
assert.Contains(t, defaultEmailTemplate, "View Secure Message")
assert.Contains(t, defaultEmailTemplate, "<!DOCTYPE html>")
}
func TestIsValidEmail(t *testing.T) {
tests := []struct {
name string
email string
valid bool
}{
{"valid simple email", "user@example.com", true},
{"valid with subdomain", "user@mail.example.com", true},
{"valid with plus", "user+tag@example.com", true},
{"invalid no at", "userexample.com", false},
{"invalid no domain", "user@", false},
{"invalid no local", "@example.com", false},
{"invalid double at", "user@@example.com", false},
{"invalid trailing dot", "user@example.", false},
{"invalid with display name", "John Doe <john@example.com>", false},
{"invalid empty", "", false},
{"invalid spaces", "user @example.com", false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := IsValidEmail(tt.email)
assert.Equal(t, tt.valid, result)
})
}
}
func TestSender_Send(t *testing.T) {
t.Run("success sends email with correct parameters", func(t *testing.T) {
mockNotifier := &mocks.NotifierMock{
SendFunc: func(_ context.Context, _, _ string) error { return nil },
}
sndr, err := NewSender(Config{
Enabled: true,
Host: "smtp.example.com",
From: "noreply@example.com",
Branding: "Test Brand",
Notifier: mockNotifier,
})
require.NoError(t, err)
req := Request{
To: "recipient@example.com",
Subject: "Test Subject",
FromName: "Sender Name",
Link: "https://example.com/message/abc123",
}
err = sndr.Send(context.Background(), req)
require.NoError(t, err)
// verify notifier was called once
calls := mockNotifier.SendCalls()
require.Len(t, calls, 1)
// verify destination contains recipient email
assert.Contains(t, calls[0].Destination, "mailto:recipient@example.com")
assert.Contains(t, calls[0].Destination, "subject=")
assert.Contains(t, calls[0].Destination, "from=")
// verify body contains link and from name
assert.Contains(t, calls[0].Text, "https://example.com/message/abc123")
assert.Contains(t, calls[0].Text, "Sender Name")
assert.Contains(t, calls[0].Text, "Test Brand")
})
t.Run("notifier error is propagated", func(t *testing.T) {
mockNotifier := &mocks.NotifierMock{
SendFunc: func(_ context.Context, _, _ string) error { return errors.New("smtp connection failed") },
}
sndr, err := NewSender(Config{
Enabled: true,
Host: "smtp.example.com",
From: "noreply@example.com",
Branding: "Test Brand",
Notifier: mockNotifier,
})
require.NoError(t, err)
req := Request{To: "recipient@example.com", Subject: "Test", FromName: "Test", Link: "https://example.com/message/abc"}
err = sndr.Send(context.Background(), req)
require.Error(t, err)
assert.Contains(t, err.Error(), "failed to send email")
assert.Contains(t, err.Error(), "smtp connection failed")
})
t.Run("empty from name uses config default", func(t *testing.T) {
mockNotifier := &mocks.NotifierMock{
SendFunc: func(_ context.Context, _, _ string) error { return nil },
}
sndr, err := NewSender(Config{
Enabled: true,
Host: "smtp.example.com",
From: `"Default Sender" <noreply@example.com>`,
Branding: "Fallback Brand",
Notifier: mockNotifier,
})
require.NoError(t, err)
req := Request{To: "recipient@example.com", Subject: "Test", FromName: "", Link: "https://example.com/message/abc"}
err = sndr.Send(context.Background(), req)
require.NoError(t, err)
calls := mockNotifier.SendCalls()
require.Len(t, calls, 1)
// when FromName is empty, buildFromAddress uses original From config including display name
assert.Contains(t, calls[0].Destination, "Default+Sender") // URL-encoded display name
assert.Contains(t, calls[0].Destination, "noreply%40example.com") // URL-encoded email
})
t.Run("context cancellation is propagated", func(t *testing.T) {
mockNotifier := &mocks.NotifierMock{
SendFunc: func(ctx context.Context, _, _ string) error {
return ctx.Err() // return context error if canceled
},
}
sndr, err := NewSender(Config{
Enabled: true,
Host: "smtp.example.com",
From: "noreply@example.com",
Branding: "Test Brand",
Notifier: mockNotifier,
})
require.NoError(t, err)
ctx, cancel := context.WithCancel(context.Background())
cancel() // cancel immediately
req := Request{To: "recipient@example.com", Subject: "Test", FromName: "Test", Link: "https://example.com/message/abc"}
err = sndr.Send(ctx, req)
require.Error(t, err)
assert.Contains(t, err.Error(), "context canceled")
})
}
func TestMaskEmail(t *testing.T) {
tests := []struct {
input, expected string
}{
{"user@example.com", "u***@example.com"},
{"a@b.com", "a***@b.com"},
{"longname@domain.org", "l***@domain.org"},
{"@invalid.com", "***"},
{"noemail", "***"},
{"", "***"},
}
for _, tt := range tests {
t.Run(tt.input, func(t *testing.T) {
assert.Equal(t, tt.expected, MaskEmail(tt.input))
})
}
}
================================================
FILE: app/email/mocks/notifier_mock.go
================================================
// Code generated by moq; DO NOT EDIT.
// github.com/matryer/moq
package mocks
import (
"context"
"sync"
)
// NotifierMock is a mock implementation of email.Notifier.
//
// func TestSomethingThatUsesNotifier(t *testing.T) {
//
// // make and configure a mocked email.Notifier
// mockedNotifier := &NotifierMock{
// SendFunc: func(ctx context.Context, destination string, text string) error {
// panic("mock out the Send method")
// },
// }
//
// // use mockedNotifier in code that requires email.Notifier
// // and then make assertions.
//
// }
type NotifierMock struct {
// SendFunc mocks the Send method.
SendFunc func(ctx context.Context, destination string, text string) error
// calls tracks calls to the methods.
calls struct {
// Send holds details about calls to the Send method.
Send []struct {
// Ctx is the ctx argument value.
Ctx context.Context
// Destination is the destination argument value.
Destination string
// Text is the text argument value.
Text string
}
}
lockSend sync.RWMutex
}
// Send calls SendFunc.
func (mock *NotifierMock) Send(ctx context.Context, destination string, text string) error {
if mock.SendFunc == nil {
panic("NotifierMock.SendFunc: method is nil but Notifier.Send was just called")
}
callInfo := struct {
Ctx context.Context
Destination string
Text string
}{
Ctx: ctx,
Destination: destination,
Text: text,
}
mock.lockSend.Lock()
mock.calls.Send = append(mock.calls.Send, callInfo)
mock.lockSend.Unlock()
return mock.SendFunc(ctx, destination, text)
}
// SendCalls gets all the calls that were made to Send.
// Check the length with:
//
// len(mockedNotifier.SendCalls())
func (mock *NotifierMock) SendCalls() []struct {
Ctx context.Context
Destination string
Text string
} {
var calls []struct {
Ctx context.Context
Destination string
Text string
}
mock.lockSend.RLock()
calls = mock.calls.Send
mock.lockSend.RUnlock()
return calls
}
================================================
FILE: app/main.go
================================================
package main
import (
"context"
"fmt"
"os"
"os/signal"
"syscall"
"time"
log "github.com/go-pkgz/lgr"
"github.com/umputun/go-flags"
"github.com/umputun/secrets/v2/app/email"
"github.com/umputun/secrets/v2/app/messager"
"github.com/umputun/secrets/v2/app/server"
"github.com/umputun/secrets/v2/app/store"
)
var opts struct {
Engine string `short:"e" long:"engine" env:"ENGINE" description:"storage engine" choice:"MEMORY" choice:"SQLITE" default:"MEMORY"`
SignKey string `short:"k" long:"key" env:"SIGN_KEY" description:"sign key" required:"true"`
PinSize int `long:"pinsize" env:"PIN_SIZE" default:"5" description:"pin size"`
MaxExpire time.Duration `long:"expire" env:"MAX_EXPIRE" default:"24h" description:"max lifetime"`
MaxPinAttempts int `long:"pinattempts" env:"PIN_ATTEMPTS" default:"3" description:"max attempts to enter pin"`
SQLiteDB string `long:"sqlite" env:"SQLITE_FILE" default:"/tmp/secrets.db" description:"sqlite database file"`
WebRoot string `long:"web" env:"WEB" description:"web ui location (dev mode, uses embedded files if not set)"`
Branding string `long:"branding" env:"BRANDING" default:"Safe Secrets" description:"application branding/title"`
BrandingURL string `long:"branding-url" env:"BRANDING_URL" default:"https://safesecret.info" description:"branding link URL for emails"`
Dbg bool `long:"dbg" description:"debug mode"`
Domain []string `short:"d" long:"domain" env:"DOMAIN" env-delim:"," description:"site domain(s)" required:"true"`
Protocol string `short:"p" long:"protocol" env:"PROTOCOL" description:"site protocol" choice:"http" choice:"https" default:"https" required:"true"`
Listen string `long:"listen" env:"LISTEN" default:":8080" description:"server listen address (ip:port or :port)"`
ProxySecurityHeaders bool `long:"proxy-security-headers" env:"PROXY_SECURITY_HEADERS" description:"disable security headers (when proxy handles them)"`
AllowNoPin bool `long:"allow-no-pin" env:"ALLOW_NO_PIN" description:"allow creating secrets without PIN protection"`
Files struct {
Enabled bool `long:"enabled" env:"ENABLED" description:"enable file uploads"`
MaxSize int64 `long:"max-size" env:"MAX_SIZE" default:"1048576" description:"max file size in bytes (default 1MB)"`
} `group:"files" namespace:"files" env-namespace:"FILES"`
Auth struct {
Hash string `long:"hash" env:"HASH" description:"bcrypt hash of password (enables auth if set)"`
SessionTTL time.Duration `long:"session-ttl" env:"SESSION_TTL" default:"168h" description:"session lifetime"`
} `group:"auth" namespace:"auth" env-namespace:"AUTH"`
Email struct {
Enabled bool `long:"enabled" env:"ENABLED" description:"enable email sharing"`
Host string `long:"host" env:"HOST" description:"SMTP server host"`
Port int `long:"port" env:"PORT" default:"587" description:"SMTP server port"`
Username string `long:"username" env:"USERNAME" description:"SMTP auth username"`
Password string `long:"password" env:"PASSWORD" description:"SMTP auth password"`
From string `long:"from" env:"FROM" description:"sender address, format: 'Display Name <email>' or just 'email'"`
TLS bool `long:"tls" env:"TLS" description:"use implicit TLS (port 465)"`
StartTLS bool `long:"starttls" env:"STARTTLS" description:"use STARTTLS (port 587)"`
InsecureSkipVerify bool `long:"insecure" env:"INSECURE_SKIP_VERIFY" description:"skip certificate verification"`
LoginAuth bool `long:"loginauth" env:"LOGIN_AUTH" description:"use LOGIN auth instead of PLAIN"`
Timeout time.Duration `long:"timeout" env:"TIMEOUT" default:"30s" description:"connection timeout"`
Template string `long:"template" env:"TEMPLATE" description:"path to custom email template file"`
} `group:"email" namespace:"email" env-namespace:"EMAIL"`
}
var revision string
func main() {
if _, err := flags.Parse(&opts); err != nil {
os.Exit(1)
}
if os.Getenv("GO_FLAGS_COMPLETION") == "" {
fmt.Printf("secrets %s\n", revision)
}
setupLog(opts.Dbg)
// validate sign key has sufficient entropy (minimum 16 bytes)
if len(opts.SignKey) < 16 {
log.Fatalf("[ERROR] sign key must be at least 16 bytes, got %d", len(opts.SignKey))
}
dataStore := getEngine(opts.Engine, opts.SQLiteDB)
crypter := messager.Crypt{Key: messager.MakeSignKey(opts.SignKey, opts.PinSize)}
params := messager.Params{MaxDuration: opts.MaxExpire, MaxPinAttempts: opts.MaxPinAttempts, MaxFileSize: opts.Files.MaxSize}
if opts.Auth.Hash != "" {
log.Printf("[INFO] authentication enabled (session TTL: %v)", opts.Auth.SessionTTL)
}
// create email sender if enabled
var emailSender *email.Sender
if opts.Email.Enabled {
log.Printf("[INFO] email sharing enabled (host: %s, from: %s)", opts.Email.Host, opts.Email.From)
var emailErr error
emailSender, emailErr = email.NewSender(email.Config{
Enabled: opts.Email.Enabled,
Host: opts.Email.Host,
Port: opts.Email.Port,
Username: opts.Email.Username,
Password: opts.Email.Password,
From: opts.Email.From,
TLS: opts.Email.TLS,
StartTLS: opts.Email.StartTLS,
InsecureSkipVerify: opts.Email.InsecureSkipVerify,
LoginAuth: opts.Email.LoginAuth,
Timeout: opts.Email.Timeout,
Template: opts.Email.Template,
Branding: opts.Branding,
BrandingURL: opts.BrandingURL,
})
if emailErr != nil {
log.Fatalf("[ERROR] can't create email sender, %v", emailErr)
}
}
srv, err := server.New(messager.New(dataStore, crypter, params), revision, server.Config{
Domain: opts.Domain,
Protocol: opts.Protocol,
Listen: opts.Listen,
PinSize: opts.PinSize,
MaxPinAttempts: opts.MaxPinAttempts,
MaxExpire: opts.MaxExpire,
WebRoot: opts.WebRoot,
Branding: opts.Branding,
SignKey: opts.SignKey,
EnableFiles: opts.Files.Enabled,
MaxFileSize: opts.Files.MaxSize,
AuthHash: opts.Auth.Hash,
SessionTTL: opts.Auth.SessionTTL,
EmailEnabled: opts.Email.Enabled,
AllowNoPin: opts.AllowNoPin,
DisableSecurityHeaders: opts.ProxySecurityHeaders,
})
if err != nil {
log.Fatalf("[ERROR] can't create server, %v", err)
}
if emailSender != nil {
srv = srv.WithEmail(emailSender)
}
// setup graceful shutdown with signal handling
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop()
if err = srv.Run(ctx); err != nil {
log.Printf("[ERROR] failed, %+v", err)
}
// cleanup storage on shutdown
if closeErr := dataStore.Close(); closeErr != nil {
log.Printf("[WARN] failed to close storage: %v", closeErr)
}
}
func getEngine(engineType, sqliteFile string) messager.Engine {
switch engineType {
case "MEMORY":
return store.NewInMemory(time.Minute * 5)
default: // SQLITE - validated by go-flags choice constraint
sqliteStore, err := store.NewSQLite(sqliteFile, time.Minute*5)
if err != nil {
log.Fatalf("[ERROR] can't open db, %v", err)
}
return sqliteStore
}
}
func setupLog(dbg bool) {
if dbg {
log.Setup(log.Debug, log.CallerFile, log.Msec, log.LevelBraces)
return
}
log.Setup(log.Msec, log.LevelBraces)
}
================================================
FILE: app/messager/crypt.go
================================================
package messager
import (
"crypto/rand"
"encoding/base64"
"errors"
"fmt"
"io"
"strings"
"golang.org/x/crypto/nacl/secretbox"
)
// Crypt data with a global key + pin.
// It provides NaCl secretbox encryption (XSalsa20-Poly1305) for data
// needed to prevent storing it in naked form even in_memory storage.
type Crypt struct {
Key string
}
// Request for both Encrypt and Decrypt
type Request struct {
Pin string
Data []byte
}
// Encrypt encrypts data with secretbox and returns base64-encoded result
func (c Crypt) Encrypt(req Request) ([]byte, error) {
keyWithPin := fmt.Sprintf("%s%s", c.Key, req.Pin)
if len(keyWithPin) != 32 {
return nil, fmt.Errorf("key+pin should be 32 bytes, got %d", len(keyWithPin))
}
naclKey := new([32]byte)
copy(naclKey[:], keyWithPin[:32])
nonce := new([24]byte)
if _, err := io.ReadFull(rand.Reader, nonce[:]); err != nil {
return nil, fmt.Errorf("could not read from random: %w", err)
}
out := make([]byte, 24)
copy(out, nonce[:])
sealed := secretbox.Seal(out, req.Data, nonce, naclKey)
return []byte(base64.StdEncoding.EncodeToString(sealed)), nil
}
// Decrypt decrypts base64-encoded data with secretbox
func (c Crypt) Decrypt(req Request) ([]byte, error) {
keyWithPin := fmt.Sprintf("%s%s", c.Key, req.Pin)
if len(keyWithPin) != 32 {
return nil, errors.New("key+pin should be 32 bytes")
}
naclKey := new([32]byte)
copy(naclKey[:], keyWithPin[:32])
sealed, err := base64.StdEncoding.DecodeString(string(req.Data))
if err != nil {
return nil, fmt.Errorf("failed to decode: %w", err)
}
nonce := new([24]byte)
copy(nonce[:], sealed[:24])
decrypted, ok := secretbox.Open(nil, sealed[24:], nonce, naclKey)
if !ok {
return nil, errors.New("failed to decrypt")
}
return decrypted, nil
}
// MakeSignKey creates 32-pin bytes signKey for AES256
func MakeSignKey(signKey string, pinSize int) (result string) {
if len(signKey) >= 32-pinSize {
return signKey[:32-pinSize]
}
repeatCount := (32 - pinSize) / len(signKey)
result = strings.Repeat(signKey, repeatCount+1)
return result[:32-pinSize]
}
================================================
FILE: app/messager/crypt_mock.go
================================================
// Code generated by moq; DO NOT EDIT.
// github.com/matryer/moq
package messager
import (
"sync"
)
// Ensure, that CrypterMock does implement Crypter.
// If this is not the case, regenerate this file with moq.
var _ Crypter = &CrypterMock{}
// CrypterMock is a mock implementation of Crypter.
//
// func TestSomethingThatUsesCrypter(t *testing.T) {
//
// // make and configure a mocked Crypter
// mockedCrypter := &CrypterMock{
// DecryptFunc: func(req Request) ([]byte, error) {
// panic("mock out the Decrypt method")
// },
// EncryptFunc: func(req Request) ([]byte, error) {
// panic("mock out the Encrypt method")
// },
// }
//
// // use mockedCrypter in code that requires Crypter
// // and then make assertions.
//
// }
type CrypterMock struct {
// DecryptFunc mocks the Decrypt method.
DecryptFunc func(req Request) ([]byte, error)
// EncryptFunc mocks the Encrypt method.
EncryptFunc func(req Request) ([]byte, error)
// calls tracks calls to the methods.
calls struct {
// Decrypt holds details about calls to the Decrypt method.
Decrypt []struct {
// Req is the req argument value.
Req Request
}
// Encrypt holds details about calls to the Encrypt method.
Encrypt []struct {
// Req is the req argument value.
Req Request
}
}
lockDecrypt sync.RWMutex
lockEncrypt sync.RWMutex
}
// Decrypt calls DecryptFunc.
func (mock *CrypterMock) Decrypt(req Request) ([]byte, error) {
if mock.DecryptFunc == nil {
panic("CrypterMock.DecryptFunc: method is nil but Crypter.Decrypt was just called")
}
callInfo := struct {
Req Request
}{
Req: req,
}
mock.lockDecrypt.Lock()
mock.calls.Decrypt = append(mock.calls.Decrypt, callInfo)
mock.lockDecrypt.Unlock()
return mock.DecryptFunc(req)
}
// DecryptCalls gets all the calls that were made to Decrypt.
// Check the length with:
//
// len(mockedCrypter.DecryptCalls())
func (mock *CrypterMock) DecryptCalls() []struct {
Req Request
} {
var calls []struct {
Req Request
}
mock.lockDecrypt.RLock()
calls = mock.calls.Decrypt
mock.lockDecrypt.RUnlock()
return calls
}
// Encrypt calls EncryptFunc.
func (mock *CrypterMock) Encrypt(req Request) ([]byte, error) {
if mock.EncryptFunc == nil {
panic("CrypterMock.EncryptFunc: method is nil but Crypter.Encrypt was just called")
}
callInfo := struct {
Req Request
}{
Req: req,
}
mock.lockEncrypt.Lock()
mock.calls.Encrypt = append(mock.calls.Encrypt, callInfo)
mock.lockEncrypt.Unlock()
return mock.EncryptFunc(req)
}
// EncryptCalls gets all the calls that were made to Encrypt.
// Check the length with:
//
// len(mockedCrypter.EncryptCalls())
func (mock *CrypterMock) EncryptCalls() []struct {
Req Request
} {
var calls []struct {
Req Request
}
mock.lockEncrypt.RLock()
calls = mock.calls.Encrypt
mock.lockEncrypt.RUnlock()
return calls
}
================================================
FILE: app/messager/crypt_test.go
================================================
package messager
import (
"errors"
"strconv"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestCrypt(t *testing.T) {
c := Crypt{Key: "123456789012345678901234567"}
tbl := []struct {
data string
pin string
err error
}{
{
data: "abcdefg",
pin: "99999",
},
{
data: "abcdefg something 12345 ?? what?",
pin: "00000",
},
{
data: "abcdefg",
pin: "12345",
},
{
data: "",
pin: "12345",
},
{
data: "dfasdfasd asdfasdfa asdfasdf asdfasdfasdf asdfasdf",
pin: "abcde",
},
{
data: "dfasdfasd asdfasdfa asdfasdf asdfasdfasdf asdfasdf",
pin: "abcd",
err: errors.New("key+pin should be 32 bytes, got 31"),
},
}
for i, tt := range tbl {
t.Run(strconv.Itoa(i), func(t *testing.T) {
r1, err := c.Encrypt(Request{Data: []byte(tt.data), Pin: tt.pin})
if tt.err != nil {
require.EqualError(t, err, tt.err.Error())
return
}
require.NoError(t, err)
t.Logf("%x", r1)
r2, err := c.Decrypt(Request{Data: r1, Pin: tt.pin})
require.NoError(t, err)
assert.Equal(t, tt.data, string(r2))
})
}
}
func TestMakeSignKey(t *testing.T) {
tbl := []struct {
key string
pinSize int
res string
}{
{
key: "abcdefg",
pinSize: 5,
res: "abcdefgabcdefgabcdefgabcdef",
},
{
key: "abcdefgabcdefgabcdefgabcdef",
pinSize: 5,
res: "abcdefgabcdefgabcdefgabcdef",
},
{
key: "11223344556677889900112233445566778899001122334455",
pinSize: 6,
res: "11223344556677889900112233",
},
}
for i, tt := range tbl {
t.Run(strconv.Itoa(i), func(t *testing.T) {
assert.Equal(t, tt.res, MakeSignKey(tt.key, tt.pinSize))
assert.Equal(t, 32, len(tt.res)+tt.pinSize)
})
}
}
================================================
FILE: app/messager/engine_mock.go
================================================
// Code generated by moq; DO NOT EDIT.
// github.com/matryer/moq
package messager
import (
"context"
"sync"
"github.com/umputun/secrets/v2/app/store"
)
// Ensure, that EngineMock does implement Engine.
// If this is not the case, regenerate this file with moq.
var _ Engine = &EngineMock{}
// EngineMock is a mock implementation of Engine.
//
// func TestSomethingThatUsesEngine(t *testing.T) {
//
// // make and configure a mocked Engine
// mockedEngine := &EngineMock{
// CloseFunc: func() error {
// panic("mock out the Close method")
// },
// IncErrFunc: func(ctx context.Context, key string) (int, error) {
// panic("mock out the IncErr method")
// },
// LoadFunc: func(ctx context.Context, key string) (*store.Message, error) {
// panic("mock out the Load method")
// },
// RemoveFunc: func(ctx context.Context, key string) error {
// panic("mock out the Remove method")
// },
// SaveFunc: func(ctx context.Context, msg *store.Message) error {
// panic("mock out the Save method")
// },
// }
//
// // use mockedEngine in code that requires Engine
// // and then make assertions.
//
// }
type EngineMock struct {
// CloseFunc mocks the Close method.
CloseFunc func() error
// IncErrFunc mocks the IncErr method.
IncErrFunc func(ctx context.Context, key string) (int, error)
// LoadFunc mocks the Load method.
LoadFunc func(ctx context.Context, key string) (*store.Message, error)
// RemoveFunc mocks the Remove method.
RemoveFunc func(ctx context.Context, key string) error
// SaveFunc mocks the Save method.
SaveFunc func(ctx context.Context, msg *store.Message) error
// calls tracks calls to the methods.
calls struct {
// Close holds details about calls to the Close method.
Close []struct {
}
// IncErr holds details about calls to the IncErr method.
IncErr []struct {
// Ctx is the ctx argument value.
Ctx context.Context
// Key is the key argument value.
Key string
}
// Load holds details about calls to the Load method.
Load []struct {
// Ctx is the ctx argument value.
Ctx context.Context
// Key is the key argument value.
Key string
}
// Remove holds details about calls to the Remove method.
Remove []struct {
// Ctx is the ctx argument value.
Ctx context.Context
// Key is the key argument value.
Key string
}
// Save holds details about calls to the Save method.
Save []struct {
// Ctx is the ctx argument value.
Ctx context.Context
// Msg is the msg argument value.
Msg *store.Message
}
}
lockClose sync.RWMutex
lockIncErr sync.RWMutex
lockLoad sync.RWMutex
lockRemove sync.RWMutex
lockSave sync.RWMutex
}
// Close calls CloseFunc.
func (mock *EngineMock) Close() error {
if mock.CloseFunc == nil {
panic("EngineMock.CloseFunc: method is nil but Engine.Close was just called")
}
callInfo := struct {
}{}
mock.lockClose.Lock()
mock.calls.Close = append(mock.calls.Close, callInfo)
mock.lockClose.Unlock()
return mock.CloseFunc()
}
// CloseCalls gets all the calls that were made to Close.
// Check the length with:
//
// len(mockedEngine.CloseCalls())
func (mock *EngineMock) CloseCalls() []struct {
} {
var calls []struct {
}
mock.lockClose.RLock()
calls = mock.calls.Close
mock.lockClose.RUnlock()
return calls
}
// IncErr calls IncErrFunc.
func (mock *EngineMock) IncErr(ctx context.Context, key string) (int, error) {
if mock.IncErrFunc == nil {
panic("EngineMock.IncErrFunc: method is nil but Engine.IncErr was just called")
}
callInfo := struct {
Ctx context.Context
Key string
}{
Ctx: ctx,
Key: key,
}
mock.lockIncErr.Lock()
mock.calls.IncErr = append(mock.calls.IncErr, callInfo)
mock.lockIncErr.Unlock()
return mock.IncErrFunc(ctx, key)
}
// IncErrCalls gets all the calls that were made to IncErr.
// Check the length with:
//
// len(mockedEngine.IncErrCalls())
func (mock *EngineMock) IncErrCalls() []struct {
Ctx context.Context
Key string
} {
var calls []struct {
Ctx context.Context
Key string
}
mock.lockIncErr.RLock()
calls = mock.calls.IncErr
mock.lockIncErr.RUnlock()
return calls
}
// Load calls LoadFunc.
func (mock *EngineMock) Load(ctx context.Context, key string) (*store.Message, error) {
if mock.LoadFunc == nil {
panic("EngineMock.LoadFunc: method is nil but Engine.Load was just called")
}
callInfo := struct {
Ctx context.Context
Key string
}{
Ctx: ctx,
Key: key,
}
mock.lockLoad.Lock()
mock.calls.Load = append(mock.calls.Load, callInfo)
mock.lockLoad.Unlock()
return mock.LoadFunc(ctx, key)
}
// LoadCalls gets all the calls that were made to Load.
// Check the length with:
//
// len(mockedEngine.LoadCalls())
func (mock *EngineMock) LoadCalls() []struct {
Ctx context.Context
Key string
} {
var calls []struct {
Ctx context.Context
Key string
}
mock.lockLoad.RLock()
calls = mock.calls.Load
mock.lockLoad.RUnlock()
return calls
}
// Remove calls RemoveFunc.
func (mock *EngineMock) Remove(ctx context.Context, key string) error {
if mock.RemoveFunc == nil {
panic("EngineMock.RemoveFunc: method is nil but Engine.Remove was just called")
}
callInfo := struct {
Ctx context.Context
Key string
}{
Ctx: ctx,
Key: key,
}
mock.lockRemove.Lock()
mock.calls.Remove = append(mock.calls.Remove, callInfo)
mock.lockRemove.Unlock()
return mock.RemoveFunc(ctx, key)
}
// RemoveCalls gets all the calls that were made to Remove.
// Check the length with:
//
// len(mockedEngine.RemoveCalls())
func (mock *EngineMock) RemoveCalls() []struct {
Ctx context.Context
Key string
} {
var calls []struct {
Ctx context.Context
Key string
}
mock.lockRemove.RLock()
calls = mock.calls.Remove
mock.lockRemove.RUnlock()
return calls
}
// Save calls SaveFunc.
func (mock *EngineMock) Save(ctx context.Context, msg *store.Message) error {
if mock.SaveFunc == nil {
panic("EngineMock.SaveFunc: method is nil but Engine.Save was just called")
}
callInfo := struct {
Ctx context.Context
Msg *store.Message
}{
Ctx: ctx,
Msg: msg,
}
mock.lockSave.Lock()
mock.calls.Save = append(mock.calls.Save, callInfo)
mock.lockSave.Unlock()
return mock.SaveFunc(ctx, msg)
}
// SaveCalls gets all the calls that were made to Save.
// Check the length with:
//
// len(mockedEngine.SaveCalls())
func (mock *EngineMock) SaveCalls() []struct {
Ctx context.Context
Msg *store.Message
} {
var calls []struct {
Ctx context.Context
Msg *store.Message
}
mock.lockSave.RLock()
calls = mock.calls.Save
mock.lockSave.RUnlock()
return calls
}
================================================
FILE: app/messager/messager.go
================================================
// Package messager package using injected engine.Store to save and load messages.
// It does all encryption/decryption and hashing. Store used as a dump storage only.
// Passed (from user) pin used as a part of encryption key for data and delegated to crypt.Crypt.
// Pins not saved directly, but hashed with bcrypt.
package messager
import (
"context"
"errors"
"fmt"
"strings"
"time"
log "github.com/go-pkgz/lgr"
"golang.org/x/crypto/bcrypt"
"github.com/umputun/secrets/v2/app/store"
)
//go:generate moq -out crypt_mock.go -fmt goimports . Crypter
//go:generate moq -out engine_mock.go -fmt goimports . Engine
// Errors
var (
ErrBadPin = errors.New("wrong pin")
ErrBadPinAttempt = errors.New("wrong pin attempt")
ErrCrypto = errors.New("crypto error")
ErrInternal = errors.New("internal error")
ErrExpired = errors.New("message expired")
ErrDuration = errors.New("bad duration")
ErrFileTooLarge = errors.New("file too large")
ErrBadFileName = errors.New("invalid file name")
ErrBadContentType = errors.New("invalid content type")
)
// filePrefix marks file messages.
// stored format: !!FILE!!<encrypted blob containing metadata+data>
// after decryption, blob contains: filename!!content-type!!\n<binary>
const filePrefix = "!!FILE!!"
// MessageProc creates and save messages and retrieve per key
type MessageProc struct {
Params
crypt Crypter
engine Engine
}
// Params to customize limits
type Params struct {
MaxDuration time.Duration
MaxPinAttempts int
MaxFileSize int64
}
// MsgReq contains data for message creation
type MsgReq struct {
Duration time.Duration
Pin string
Message string
ClientEnc bool // true for client-side encryption (UI), false for server-side (API)
AllowEmptyPin bool // true to allow creating messages without PIN protection
}
// FileRequest contains data for file message creation
type FileRequest struct {
Duration time.Duration
Pin string
FileName string
ContentType string
Data []byte
}
// Crypter interface wraps crypt methods
type Crypter interface {
Encrypt(req Request) (result []byte, err error)
Decrypt(req Request) (result []byte, err error)
}
// Engine defines interface to save, load, remove and inc errors count for messages
type Engine interface {
Save(ctx context.Context, msg *store.Message) (err error)
Load(ctx context.Context, key string) (result *store.Message, err error)
IncErr(ctx context.Context, key string) (count int, err error)
Remove(ctx context.Context, key string) (err error)
Close() error
}
// New makes MessageProc with the engine and crypt
func New(engine Engine, crypter Crypter, params Params) *MessageProc {
if params.MaxDuration == 0 {
params.MaxDuration = time.Hour * 24 * 31 // 31 days if nothing defined
}
if params.MaxPinAttempts == 0 {
params.MaxPinAttempts = 3
}
if params.MaxFileSize == 0 {
params.MaxFileSize = 1024 * 1024 // 1MB default
}
log.Printf("[INFO] created messager with %+v", params)
return &MessageProc{
engine: engine,
crypt: crypter,
Params: params,
}
}
// MakeMessage creates and saves a message from the request.
// If ClientEnc is true, data is stored as-is (client handles encryption).
// If ClientEnc is false, data is encrypted server-side with pin.
func (p MessageProc) MakeMessage(ctx context.Context, req MsgReq) (result *store.Message, err error) {
if req.Pin == "" && !req.AllowEmptyPin {
log.Printf("[WARN] save rejected, empty pin")
return nil, ErrBadPin
}
var pinHash string
if req.Pin != "" {
pinHash, err = p.makeHash(req.Pin)
if err != nil {
log.Printf("[ERROR] can't hash pin, %v", err)
return nil, ErrInternal
}
}
// when Pin is empty and AllowEmptyPin is true, pinHash stays empty string
if req.Duration > p.MaxDuration {
log.Printf("[ERROR] can't use duration, %v > %v", req.Duration, p.MaxDuration)
return nil, ErrDuration
}
exp := time.Now().Add(req.Duration)
result = &store.Message{
Key: store.GenerateID(),
Exp: exp,
PinHash: pinHash,
ClientEnc: req.ClientEnc,
}
// client-side encryption: store data as-is
if req.ClientEnc {
result.Data = []byte(req.Message)
} else {
result.Data, err = p.crypt.Encrypt(Request{Data: []byte(req.Message), Pin: req.Pin})
if err != nil {
log.Printf("[ERROR] failed to encrypt, %v", err)
return nil, ErrCrypto
}
}
if err = p.engine.Save(ctx, result); err != nil {
return nil, fmt.Errorf("save message: %w", err)
}
return result, nil
}
// LoadMessage gets from engine, verifies Message with pin and decrypts content.
// It also removes accessed messages and invalidate them on multiple wrong pins.
// Message decrypted by this function will be returned naked to consumer.
func (p MessageProc) LoadMessage(ctx context.Context, key, pin string) (msg *store.Message, err error) {
msg, err = p.engine.Load(ctx, key)
if err != nil {
return nil, fmt.Errorf("load message: %w", err)
}
if time.Now().After(msg.Exp) {
log.Printf("[WARN] expired %s on %v", msg.Key, msg.Exp)
_ = p.engine.Remove(ctx, key)
return nil, ErrExpired
}
if !p.checkHash(msg, pin) {
count, e := p.engine.IncErr(ctx, key)
if e != nil {
return nil, ErrBadPin
}
log.Printf("[WARN] wrong pin provided for %s (%d times)", key, count)
if count >= p.MaxPinAttempts {
_ = p.engine.Remove(ctx, key)
return nil, ErrBadPin
}
return msg, ErrBadPinAttempt
}
// client-side encrypted messages: return data as-is (client handles decryption)
if msg.ClientEnc {
if rmErr := p.engine.Remove(ctx, key); rmErr != nil {
log.Printf("[WARN] failed to remove, %v", rmErr)
}
return msg, nil
}
// for file messages, everything after !!FILE!! is encrypted (including metadata)
// for text messages, the entire data is encrypted
dataToDecrypt := msg.Data
isFile := IsFileMessage(msg.Data)
if isFile {
// skip !!FILE!! prefix, decrypt the rest (metadata + binary)
dataToDecrypt = msg.Data[len(filePrefix):]
}
r, err := p.crypt.Decrypt(Request{Data: dataToDecrypt, Pin: pin})
if err != nil {
log.Printf("[WARN] can't decrypt, %v", err)
_ = p.engine.Remove(ctx, key)
return nil, ErrBadPin
}
if err := p.engine.Remove(ctx, key); err != nil {
log.Printf("[WARN] failed to remove, %v", err)
}
// for file messages, prepend !!FILE!! to decrypted result for ParseFileHeader compatibility
// decrypted result is: filename!!content-type!!\n<binary>
if isFile {
msg.Data = append([]byte(filePrefix), r...)
} else {
msg.Data = r
}
return msg, nil
}
// checkHash verifies msg.PinHash with provided pin.
// Returns true when both stored hash and provided pin are empty (PIN-less message).
func (p MessageProc) checkHash(msg *store.Message, pin string) bool {
if msg.PinHash == "" && pin == "" {
return true // PIN-less message accessed without PIN
}
if msg.PinHash == "" || pin == "" {
return false // mismatch: one is empty, the other is not
}
return bcrypt.CompareHashAndPassword([]byte(msg.PinHash), []byte(pin)) == nil
}
// makeHash from pin
func (p MessageProc) makeHash(pin string) (result string, err error) {
hashedPin, err := bcrypt.GenerateFromPassword([]byte(pin), bcrypt.DefaultCost)
if err != nil {
return "", fmt.Errorf("can't make hashed pin: %w", err)
}
return string(hashedPin), nil
}
// IsFile checks if a message with given key is a file message (without decrypting).
// Returns false if message doesn't exist, is not a file, or is client-encrypted.
// For client-encrypted messages, server can't inspect the opaque blob.
func (p MessageProc) IsFile(ctx context.Context, key string) bool {
msg, err := p.engine.Load(ctx, key)
if err != nil {
return false
}
if msg.ClientEnc {
return false // server can't inspect client-encrypted content
}
return IsFileMessage(msg.Data)
}
// HasPin checks if a message requires PIN for access.
// Returns true if message has a PIN hash, false if PIN-less.
// Returns error if message doesn't exist.
func (p MessageProc) HasPin(ctx context.Context, key string) (bool, error) {
msg, err := p.engine.Load(ctx, key)
if err != nil {
return false, fmt.Errorf("load message: %w", err)
}
return msg.PinHash != "", nil
}
// MakeFileMessage creates a message from file data with unencrypted prefix for metadata.
// Format: !!FILE!!filename!!content-type!!\n<encrypted binary>
// This function is for API file uploads only (server-side encryption).
// UI file uploads use client-side encryption via MakeMessage with the encrypted blob.
func (p MessageProc) MakeFileMessage(ctx context.Context, req FileRequest) (result *store.Message, err error) {
if req.Pin == "" {
log.Printf("[WARN] save rejected, empty pin")
return nil, ErrBadPin
}
if req.FileName == "" || len(req.FileName) > 255 || strings.Contains(req.FileName, "!!") ||
strings.ContainsAny(req.FileName, "\n\r\x00") || strings.Contains(req.FileName, "..") ||
strings.ContainsAny(req.FileName, "/\\") || p.hasControlChars(req.FileName) {
log.Printf("[WARN] save rejected, invalid file name")
return nil, ErrBadFileName
}
// validate content-type to prevent header parsing corruption
if strings.Contains(req.ContentType, "!!") || strings.ContainsAny(req.ContentType, "\n\r\x00") {
log.Printf("[WARN] save rejected, invalid content type")
return nil, ErrBadContentType
}
if int64(len(req.Data)) > p.MaxFileSize {
log.Printf("[WARN] save rejected, file too large: %d > %d", len(req.Data), p.MaxFileSize)
return nil, ErrFileTooLarge
}
if req.Duration > p.MaxDuration {
log.Printf("[ERROR] can't use duration, %v > %v", req.Duration, p.MaxDuration)
return nil, ErrDuration
}
pinHash, err := p.makeHash(req.Pin)
if err != nil {
log.Printf("[ERROR] can't hash pin, %v", err)
return nil, ErrInternal
}
// build metadata header and combine with binary data for encryption
// format after decryption: filename!!content-type!!\n<binary>
metadata := fmt.Sprintf("%s!!%s!!\n", req.FileName, req.ContentType)
dataToEncrypt := append([]byte(metadata), req.Data...)
// encrypt metadata + binary together (only !!FILE!! prefix stays unencrypted)
encryptedData, err := p.crypt.Encrypt(Request{Data: dataToEncrypt, Pin: req.Pin})
if err != nil {
log.Printf("[ERROR] failed to encrypt file, %v", err)
return nil, ErrCrypto
}
// stored format: !!FILE!!<encrypted blob containing metadata+data>
fullData := append([]byte(filePrefix), encryptedData...)
exp := time.Now().Add(req.Duration)
result = &store.Message{
Key: store.GenerateID(),
Exp: exp,
PinHash: pinHash,
Data: fullData,
}
if err = p.engine.Save(ctx, result); err != nil {
return nil, fmt.Errorf("save file message: %w", err)
}
return result, nil
}
// IsFileMessage checks if message data has file prefix (works on raw stored data)
func IsFileMessage(data []byte) bool {
return len(data) > len(filePrefix) && string(data[:len(filePrefix)]) == filePrefix
}
// ParseFileHeader extracts filename, content-type, and data start position from file message.
// Returns empty strings and -1 if not a valid file message.
func ParseFileHeader(data []byte) (filename, contentType string, dataStart int) {
if !IsFileMessage(data) {
return "", "", -1
}
// format: !!FILE!!filename!!content-type!!\n<data>
// find newline which marks end of header (limit scan to 4KB for safety)
headerEnd := -1
maxScan := min(len(data), len(filePrefix)+4096)
for i := len(filePrefix); i < maxScan; i++ {
if data[i] == '\n' {
headerEnd = i
break
}
}
if headerEnd == -1 {
return "", "", -1
}
// parse header: filename!!content-type!!
header := string(data[len(filePrefix):headerEnd])
parts := strings.Split(header, "!!")
if len(parts) < 2 {
return "", "", -1
}
return parts[0], parts[1], headerEnd + 1
}
// hasControlChars checks if string contains ASCII control characters (0x01-0x1F, excluding already checked \n\r)
func (p MessageProc) hasControlChars(s string) bool {
for _, r := range s {
if r < 32 && r != '\n' && r != '\r' {
return true
}
}
return false
}
================================================
FILE: app/messager/messager_test.go
================================================
package messager
import (
"context"
"errors"
"strings"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/umputun/secrets/v2/app/store"
)
func TestMessageProc_NewDefault(t *testing.T) {
m := New(nil, Crypt{}, Params{})
assert.Equal(t, time.Hour*24*31, m.MaxDuration)
assert.Equal(t, 3, m.MaxPinAttempts)
assert.Equal(t, int64(1024*1024), m.MaxFileSize)
}
func TestMessageProc_MakeMessage(t *testing.T) {
s := &EngineMock{
SaveFunc: func(ctx context.Context, msg *store.Message) error {
return nil
},
}
c := &CrypterMock{
EncryptFunc: func(req Request) ([]byte, error) {
return []byte("encrypted blah"), nil
},
}
m := New(s, c, Params{MaxPinAttempts: 2, MaxDuration: time.Minute})
r, err := m.MakeMessage(t.Context(), MsgReq{Duration: time.Second * 30, Message: "message", Pin: "56789", ClientEnc: false})
t.Logf("%+v", r)
require.NoError(t, err)
assert.Equal(t, "encrypted blah", string(r.Data))
assert.Equal(t, 0, r.Errors)
assert.Contains(t, r.PinHash, "$2a$")
assert.Len(t, s.SaveCalls(), 1)
assert.Len(t, c.EncryptCalls(), 1)
}
func TestMessageProc_MakeMessage_EmptyPinAllowed(t *testing.T) {
s := &EngineMock{
SaveFunc: func(ctx context.Context, msg *store.Message) error { return nil },
}
c := &CrypterMock{
EncryptFunc: func(req Request) ([]byte, error) { return []byte("encrypted blah"), nil },
}
m := New(s, c, Params{MaxPinAttempts: 2, MaxDuration: time.Minute})
r, err := m.MakeMessage(t.Context(), MsgReq{
Duration: time.Second * 30, Message: "message", Pin: "", ClientEnc: true, AllowEmptyPin: true,
})
t.Logf("%+v", r)
require.NoError(t, err)
assert.Equal(t, "message", string(r.Data), "data should be stored as-is for client-enc")
assert.Empty(t, r.PinHash, "pin hash should be empty")
assert.Len(t, s.SaveCalls(), 1)
assert.Empty(t, c.EncryptCalls(), "no encryption for client-enc")
}
func TestMessageProc_MakeMessage_EmptyPinRejected(t *testing.T) {
s := &EngineMock{}
c := &CrypterMock{}
m := New(s, c, Params{MaxPinAttempts: 2, MaxDuration: time.Minute})
_, err := m.MakeMessage(t.Context(), MsgReq{
Duration: time.Second * 30, Message: "message", Pin: "", ClientEnc: true, AllowEmptyPin: false,
})
require.EqualError(t, err, ErrBadPin.Error())
assert.Empty(t, s.SaveCalls())
}
func TestMessageProc_MakeMessage_Errors(t *testing.T) {
s := &EngineMock{}
c := &CrypterMock{}
type args struct {
duration time.Duration
pin string
}
tests := []struct {
name string
args args
wantErr error
}{
{
name: "bad pin error",
wantErr: ErrBadPin,
args: args{
duration: time.Second * 30,
pin: "",
},
},
{
name: "bad duration",
wantErr: ErrDuration,
args: args{
duration: time.Minute * 30,
pin: "1234",
},
},
{
name: "internal error when pin too long",
wantErr: ErrInternal,
args: args{
duration: time.Second * 30,
pin: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed gravida varius nisi, id cursus justo. Nulla facilities. Sed auctor, ex eget bibendum aliquet, nisi turpis",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
m := New(s, c, Params{MaxPinAttempts: 2, MaxDuration: time.Minute})
r, err := m.MakeMessage(t.Context(), MsgReq{Duration: tt.args.duration, Message: "message", Pin: tt.args.pin})
t.Logf("%+v", r)
require.EqualError(t, err, tt.wantErr.Error())
assert.Empty(t, s.SaveCalls())
assert.Empty(t, c.EncryptCalls())
})
}
}
func TestMessageProc_MakeMessage_CrypterError(t *testing.T) {
s := &EngineMock{}
c := &CrypterMock{
EncryptFunc: func(req Request) ([]byte, error) {
return nil, errors.New("crypter error")
},
}
m := New(s, c, Params{MaxPinAttempts: 2, MaxDuration: time.Minute})
r, err := m.MakeMessage(t.Context(), MsgReq{Duration: time.Second * 30, Message: "message", Pin: "56789", ClientEnc: false})
t.Logf("%+v", r)
require.EqualError(t, err, "crypto error")
assert.Empty(t, s.SaveCalls())
assert.Len(t, c.EncryptCalls(), 1)
}
func TestMessageProc_LoadMessage_Err(t *testing.T) {
s := &EngineMock{
LoadFunc: func(ctx context.Context, key string) (*store.Message, error) {
return nil, errors.New("load error")
},
}
c := &CrypterMock{}
m := New(s, c, Params{MaxPinAttempts: 2, MaxDuration: time.Minute})
r, err := m.LoadMessage(t.Context(), "somekey", "56789")
t.Logf("%+v", r)
require.ErrorContains(t, err, "load error")
assert.Len(t, s.LoadCalls(), 1)
assert.Empty(t, s.RemoveCalls())
assert.Empty(t, s.IncErrCalls())
assert.Empty(t, c.DecryptCalls())
}
func TestMessageProc_LoadMessage_ExpiredErr(t *testing.T) {
s := &EngineMock{
LoadFunc: func(ctx context.Context, key string) (*store.Message, error) {
return &store.Message{
Data: []byte("data"),
PinHash: "some-hash",
Exp: time.Now().Add(-1 * time.Minute),
}, nil
},
RemoveFunc: func(ctx context.Context, key string) error {
return nil
},
}
c := &CrypterMock{}
m := New(s, c, Params{MaxPinAttempts: 2, MaxDuration: time.Minute})
r, err := m.LoadMessage(t.Context(), "somekey", "56789")
t.Logf("%+v", r)
require.EqualError(t, err, "message expired")
assert.Len(t, s.LoadCalls(), 1)
assert.Len(t, s.RemoveCalls(), 1)
assert.Empty(t, s.IncErrCalls())
assert.Empty(t, c.DecryptCalls())
}
func TestMessageProc_LoadMessage_BadPin(t *testing.T) {
s := &EngineMock{
LoadFunc: func(ctx context.Context, key string) (*store.Message, error) {
return &store.Message{
Data: []byte("data"),
PinHash: "some-hash",
Exp: time.Now().Add(1 * time.Minute),
}, nil
},
IncErrFunc: func(ctx context.Context, key string) (int, error) {
return 0, errors.New("inc error")
},
}
c := &CrypterMock{}
m := New(s, c, Params{MaxPinAttempts: 2, MaxDuration: time.Minute})
r, err := m.LoadMessage(t.Context(), "somekey", "56789")
t.Logf("%+v", r)
require.EqualError(t, err, "wrong pin")
assert.Len(t, s.LoadCalls(), 1)
assert.Empty(t, s.RemoveCalls())
assert.Len(t, s.IncErrCalls(), 1)
assert.Empty(t, c.DecryptCalls())
}
func TestMessageProc_LoadMessage_BadPin_MaxAttempts(t *testing.T) {
s := &EngineMock{
LoadFunc: func(ctx context.Context, key string) (*store.Message, error) {
return &store.Message{
Data: []byte("data"),
PinHash: "some-hash",
Exp: time.Now().Add(1 * time.Minute),
}, nil
},
RemoveFunc: func(ctx context.Context, key string) error {
return nil
},
IncErrFunc: func(ctx context.Context, key string) (int, error) {
return 2, nil
},
}
c := &CrypterMock{}
m := New(s, c, Params{MaxPinAttempts: 2, MaxDuration: time.Minute})
r, err := m.LoadMessage(t.Context(), "somekey", "56789")
t.Logf("%+v", r)
require.EqualError(t, err, "wrong pin")
assert.Len(t, s.LoadCalls(), 1)
assert.Len(t, s.RemoveCalls(), 1)
assert.Len(t, s.IncErrCalls(), 1)
assert.Empty(t, c.DecryptCalls())
}
func TestMessageProc_LoadMessage_BadPinAttempt(t *testing.T) {
msg := &store.Message{
Data: []byte("data"),
PinHash: "some-hash",
Exp: time.Now().Add(1 * time.Minute),
}
s := &EngineMock{
LoadFunc: func(ctx context.Context, key string) (*store.Message, error) {
return msg, nil
},
IncErrFunc: func(ctx context.Context, key string) (int, error) {
return 1, nil
},
}
c := &CrypterMock{}
m := New(s, c, Params{MaxPinAttempts: 2, MaxDuration: time.Minute})
r, err := m.LoadMessage(t.Context(), "somekey", "56789")
t.Logf("%+v", r)
require.EqualError(t, err, "wrong pin attempt")
assert.Equal(t, r, msg)
assert.Len(t, s.LoadCalls(), 1)
assert.Empty(t, s.RemoveCalls())
assert.Len(t, s.IncErrCalls(), 1)
assert.Empty(t, c.DecryptCalls())
}
func TestMessageProc_LoadMessage_DecryptError(t *testing.T) {
s := &EngineMock{
LoadFunc: func(ctx context.Context, key string) (*store.Message, error) {
return &store.Message{
Data: []byte("data"),
PinHash: "$2a$10$2d9OIFG2.zuVIiZznlpy/uJoTl4quQPbDSFnHbi0LuYDILuxHYkDu",
Exp: time.Now().Add(1 * time.Minute),
}, nil
},
RemoveFunc: func(ctx context.Context, key string) error {
return nil
},
}
c := &CrypterMock{
DecryptFunc: func(req Request) ([]byte, error) {
return nil, errors.New("decrypt error")
},
}
m := New(s, c, Params{MaxPinAttempts: 2, MaxDuration: time.Minute})
r, err := m.LoadMessage(t.Context(), "somekey", "123456")
t.Logf("%+v", r)
require.EqualError(t, err, "wrong pin")
assert.Len(t, s.LoadCalls(), 1)
assert.Len(t, s.RemoveCalls(), 1)
assert.Empty(t, s.IncErrCalls())
assert.Len(t, c.DecryptCalls(), 1)
}
func TestMessageProc_LoadMessage(t *testing.T) {
s := &EngineMock{
LoadFunc: func(ctx context.Context, key string) (*store.Message, error) {
return &store.Message{
Data: []byte("data"),
PinHash: "$2a$10$2d9OIFG2.zuVIiZznlpy/uJoTl4quQPbDSFnHbi0LuYDILuxHYkDu",
Exp: time.Now().Add(1 * time.Minute),
}, nil
},
RemoveFunc: func(ctx context.Context, key string) error {
return nil
},
}
c := &CrypterMock{
DecryptFunc: func(req Request) ([]byte, error) {
return []byte("decrypted blah"), nil
},
}
m := New(s, c, Params{MaxPinAttempts: 2, MaxDuration: time.Minute})
r, err := m.LoadMessage(t.Context(), "somekey", "123456")
t.Logf("%+v", r)
require.NoError(t, err)
assert.Equal(t, "decrypted blah", string(r.Data))
assert.Equal(t, 0, r.Errors)
assert.Contains(t, r.PinHash, "$2a$")
assert.Len(t, s.LoadCalls(), 1)
assert.Len(t, s.RemoveCalls(), 1)
assert.Empty(t, s.IncErrCalls())
assert.Len(t, c.DecryptCalls(), 1)
}
func TestMessageProc_LoadMessage_NoPinMessage(t *testing.T) {
s := &EngineMock{
LoadFunc: func(ctx context.Context, key string) (*store.Message, error) {
return &store.Message{
Data: []byte("client-encrypted-blob"),
PinHash: "", // no PIN
Exp: time.Now().Add(1 * time.Minute),
ClientEnc: true,
}, nil
},
RemoveFunc: func(ctx context.Context, key string) error { return nil },
}
c := &CrypterMock{}
m := New(s, c, Params{MaxPinAttempts: 2, MaxDuration: time.Minute})
r, err := m.LoadMessage(t.Context(), "somekey", "") // empty PIN
require.NoError(t, err)
assert.Equal(t, "client-encrypted-blob", string(r.Data))
assert.Empty(t, r.PinHash)
assert.Len(t, s.LoadCalls(), 1)
assert.Len(t, s.RemoveCalls(), 1)
assert.Empty(t, c.DecryptCalls(), "no decryption for client-enc")
}
func TestMessageProc_LoadMessage_NoPinMessage_WithPinProvided(t *testing.T) {
s := &EngineMock{
LoadFunc: func(ctx context.Context, key string) (*store.Message, error) {
return &store.Message{
Data: []byte("client-encrypted-blob"),
PinHash: "", // no PIN stored
Exp: time.Now().Add(1 * time.Minute),
ClientEnc: true,
}, nil
},
IncErrFunc: func(ctx context.Context, key string) (int, error) { return 1, nil },
}
c := &CrypterMock{}
m := New(s, c, Params{MaxPinAttempts: 2, MaxDuration: time.Minute})
_, err := m.LoadMessage(t.Context(), "somekey", "12345") // PIN provided but message has no PIN
require.EqualError(t, err, "wrong pin attempt")
assert.Len(t, s.IncErrCalls(), 1)
}
func TestMessageProc_HasPin(t *testing.T) {
tests := []struct {
name string
pinHash string
loadErr error
want bool
wantErr bool
}{
{name: "has pin", pinHash: "$2a$10$hash", loadErr: nil, want: true, wantErr: false},
{name: "no pin", pinHash: "", loadErr: nil, want: false, wantErr: false},
{name: "load error", pinHash: "", loadErr: errors.New("not found"), want: false, wantErr: true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := &EngineMock{
LoadFunc: func(ctx context.Context, key string) (*store.Message, error) {
if tt.loadErr != nil {
return nil, tt.loadErr
}
return &store.Message{PinHash: tt.pinHash}, nil
},
}
m := New(s, nil, Params{})
got, err := m.HasPin(t.Context(), "test-key")
if tt.wantErr {
require.Error(t, err)
return
}
require.NoError(t, err)
assert.Equal(t, tt.want, got)
})
}
}
func TestMessageProc_MakeFileMessage(t *testing.T) {
s := &EngineMock{
SaveFunc: func(ctx context.Context, msg *store.Message) error { return nil },
}
c := &CrypterMock{
EncryptFunc: func(req Request) ([]byte, error) { return []byte("encrypted-blob"), nil },
}
m := New(s, c, Params{MaxPinAttempts: 2, MaxDuration: time.Minute, MaxFileSize: 1024})
r, err := m.MakeFileMessage(t.Context(), FileRequest{
Duration: time.Second * 30,
Pin: "12345",
FileName: "test.pdf",
ContentType: "application/pdf",
Data: []byte("file content"),
})
require.NoError(t, err)
assert.True(t, IsFileMessage(r.Data), "should have !!FILE!! prefix")
assert.Contains(t, r.PinHash, "$2a$")
// verify filename is NOT visible in stored data (encrypted)
assert.NotContains(t, string(r.Data), "test.pdf", "filename should be encrypted")
assert.NotContains(t, string(r.Data), "application/pdf", "content-type should be encrypted")
// verify stored format: !!FILE!! + encrypted blob
assert.True(t, strings.HasPrefix(string(r.Data), "!!FILE!!"))
assert.Equal(t, "!!FILE!!encrypted-blob", string(r.Data))
// verify encryption received metadata + data combined
require.Len(t, c.EncryptCalls(), 1)
encryptInput := string(c.EncryptCalls()[0].Req.Data)
assert.Contains(t, encryptInput, "test.pdf!!")
assert.Contains(t, encryptInput, "!!application/pdf!!")
assert.Contains(t, encryptInput, "file content")
assert.Len(t, s.SaveCalls(), 1)
}
func TestMessageProc_LoadFileMessage(t *testing.T) {
// stored data format: !!FILE!! + encrypted blob
// decrypted blob contains: filename!!content-type!!\n + binary data
storedData := []byte("!!FILE!!encrypted-blob")
s := &EngineMock{
LoadFunc: func(ctx context.Context, key string) (*store.Message, error) {
return &store.Message{
Data: storedData,
PinHash: "$2a$10$2d9OIFG2.zuVIiZznlpy/uJoTl4quQPbDSFnHbi0LuYDILuxHYkDu",
Exp: time.Now().Add(1 * time.Minute),
}, nil
},
RemoveFunc: func(ctx context.Context, key string) error { return nil },
}
c := &CrypterMock{
DecryptFunc: func(req Request) ([]byte, error) {
// verify we receive only the encrypted blob (without !!FILE!! prefix)
assert.Equal(t, "encrypted-blob", string(req.Data))
// return decrypted metadata + binary
return []byte("secret-doc.pdf!!application/pdf!!\nfile binary content"), nil
},
}
m := New(s, c, Params{MaxPinAttempts: 2, MaxDuration: time.Minute})
r, err := m.LoadMessage(t.Context(), "somekey", "123456")
require.NoError(t, err)
// verify decrypted result has !!FILE!! prefix prepended for ParseFileHeader compatibility
assert.True(t, IsFileMessage(r.Data), "result should have !!FILE!! prefix")
// verify we can parse the header correctly
filename, contentType, dataStart := ParseFileHeader(r.Data)
assert.Equal(t, "secret-doc.pdf", filename)
assert.Equal(t, "application/pdf", contentType)
assert.Equal(t, "file binary content", string(r.Data[dataStart:]))
assert.Len(t, s.LoadCalls(), 1)
assert.Len(t, s.RemoveCalls(), 1)
assert.Len(t, c.DecryptCalls(), 1)
}
func TestMessageProc_MakeFileMessage_Errors(t *testing.T) {
tests := []struct {
name string
req FileRequest
wantErr error
}{
{name: "empty pin", req: FileRequest{Duration: time.Second, Pin: "", FileName: "f.txt", ContentType: "text/plain", Data: []byte("x")}, wantErr: ErrBadPin},
{name: "empty filename", req: FileRequest{Duration: time.Second, Pin: "123", FileName: "", ContentType: "text/plain", Data: []byte("x")}, wantErr: ErrBadFileName},
{name: "filename too long", req: FileRequest{Duration: time.Second, Pin: "123", FileName: string(make([]byte, 256)), ContentType: "text/plain", Data: []byte("x")}, wantErr: ErrBadFileName},
{name: "filename with delimiter", req: FileRequest{Duration: time.Second, Pin: "123", FileName: "test!!file.txt", ContentType: "text/plain", Data: []byte("x")}, wantErr: ErrBadFileName},
{name: "filename with newline", req: FileRequest{Duration: time.Second, Pin: "123", FileName: "test\nfile.txt", ContentType: "text/plain", Data: []byte("x")}, wantErr: ErrBadFileName},
{name: "filename with path traversal", req: FileRequest{Duration: time.Second, Pin: "123", FileName: "../etc/passwd", ContentType: "text/plain", Data: []byte("x")}, wantErr: ErrBadFileName},
{name: "filename with forward slash", req: FileRequest{Duration: time.Second, Pin: "123", FileName: "path/to/file.txt", ContentType: "text/plain", Data: []byte("x")}, wantErr: ErrBadFileName},
{name: "filename with backslash", req: FileRequest{Duration: time.Second, Pin: "123", FileName: "path\\file.txt", ContentType: "text/plain", Data: []byte("x")}, wantErr: ErrBadFileName},
{name: "filename with null byte", req: FileRequest{Duration: time.Second, Pin: "123", FileName: "test\x00file.txt", ContentType: "text/plain", Data: []byte("x")}, wantErr: ErrBadFileName},
{name: "filename with control char", req: FileRequest{Duration: time.Second, Pin: "123", FileName: "test\x01file.txt", ContentType: "text/plain", Data: []byte("x")}, wantErr: ErrBadFileName},
{name: "filename with tab", req: FileRequest{Duration: time.Second, Pin: "123", FileName: "test\tfile.txt", ContentType: "text/plain", Data: []byte("x")}, wantErr: ErrBadFileName},
{name: "file too large", req: FileRequest{Duration: time.Second, Pin: "123", FileName: "f.txt", ContentType: "text/plain", Data: make([]byte, 2048)}, wantErr: ErrFileTooLarge},
{name: "bad duration", req: FileRequest{Duration: time.Hour, Pin: "123", FileName: "f.txt", ContentType: "text/plain", Data: []byte("x")}, wantErr: ErrDuration},
{name: "content-type with delimiter", req: FileRequest{Duration: time.Second, Pin: "123", FileName: "f.txt", ContentType: "text/plain!!", Data: []byte("x")}, wantErr: ErrBadContentType},
{name: "content-type with newline", req: FileRequest{Duration: time.Second, Pin: "123", FileName: "f.txt", ContentType: "text/plain\n", Data: []byte("x")}, wantErr: ErrBadContentType},
{name: "content-type with carriage return", req: FileRequest{Duration: time.Second, Pin: "123", FileName: "f.txt", ContentType: "text/plain\r", Data: []byte("x")}, wantErr: ErrBadContentType},
{name: "content-type with null byte", req: FileRequest{Duration: time.Second, Pin: "123", FileName: "f.txt", ContentType: "text/plain\x00", Data: []byte("x")}, wantErr: ErrBadContentType},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := &EngineMock{}
c := &CrypterMock{}
m := New(s, c, Params{MaxPinAttempts: 2, MaxDuration: time.Minute, MaxFileSize: 1024})
_, err := m.MakeFileMessage(t.Context(), tt.req)
require.EqualError(t, err, tt.wantErr.Error())
assert.Empty(t, s.SaveCalls())
})
}
}
func TestMessageProc_MakeFileMessage_CrypterError(t *testing.T) {
s := &EngineMock{}
c := &CrypterMock{
EncryptFunc: func(req Request) ([]byte, error) { return nil, errors.New("encrypt error") },
}
m := New(s, c, Params{MaxPinAttempts: 2, MaxDuration: time.Minute, MaxFileSize: 1024})
_, err := m.MakeFileMessage(t.Context(), FileRequest{Duration: time.Second, Pin: "123", FileName: "f.txt", ContentType: "text/plain", Data: []byte("x")})
require.EqualError(t, err, ErrCrypto.Error())
assert.Empty(t, s.SaveCalls())
assert.Len(t, c.EncryptCalls(), 1)
}
func TestMessageProc_MakeFileMessage_SaveError(t *testing.T) {
s := &EngineMock{
SaveFunc: func(ctx context.Context, msg *store.Message) error { return errors.New("storage error") },
}
c := &CrypterMock{
EncryptFunc: func(req Request) ([]byte, error) { return []byte("encrypted"), nil },
}
m := New(s, c, Params{MaxPinAttempts: 2, MaxDuration: time.Minute, MaxFileSize: 1024})
_, err := m.MakeFileMessage(t.Context(), FileRequest{Duration: time.Second, Pin: "123", FileName: "f.txt", ContentType: "text/plain", Data: []byte("x")})
require.ErrorContains(t, err, "storage error")
assert.Len(t, s.SaveCalls(), 1)
assert.Len(t, c.EncryptCalls(), 1)
}
func TestMessageProc_IsFile(t *testing.T) {
tests := []struct {
name string
loadErr error
data []byte
clientEnc bool
want bool
}{
{name: "file message", loadErr: nil, data: []byte("!!FILE!!test.pdf!!application/pdf!!\ndata"), clientEnc: false, want: true},
{name: "text message", loadErr: nil, data: []byte("encrypted text"), clientEnc: false, want: false},
{name: "load error", loadErr: errors.New("not found"), data: nil, clientEnc: false, want: false},
{name: "client-enc file", loadErr: nil, data: []byte("!!FILE!!test.pdf!!application/pdf!!\ndata"), clientEnc: true, want: false},
{name: "client-enc text", loadErr: nil, data: []byte("encrypted blob"), clientEnc: true, want: false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := &EngineMock{
LoadFunc: func(ctx context.Context, key string) (*store.Message, error) {
if tt.loadErr != nil {
return nil, tt.loadErr
}
return &store.Message{Data: tt.data, ClientEnc: tt.clientEnc}, nil
},
}
m := New(s, nil, Params{})
assert.Equal(t, tt.want, m.IsFile(t.Context(), "test-key"))
if tt.loadErr == nil {
assert.Len(t, s.LoadCalls(), 1)
}
})
}
}
func TestIsFileMessage(t *testing.T) {
tests := []struct {
name string
data []byte
want bool
}{
{name: "valid file message", data: []byte("!!FILE!!test.pdf!!application/pdf!!\ndata"), want: true},
{name: "text message", data: []byte("encrypted text"), want: false},
{name: "empty data", data: []byte{}, want: false},
{name: "partial prefix", data: []byte("!!FIL"), want: false},
{name: "just prefix", data: []byte("!!FILE!!"), want: false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.want, IsFileMessage(tt.data))
})
}
}
func TestParseFileHeader(t *testing.T) {
tests := []struct {
name string
data []byte
wantName string
wantType string
wantStart int
wantInvalid bool
}{
{name: "valid header", data: []byte("!!FILE!!test.pdf!!application/pdf!!\nencrypted"), wantName: "test.pdf", wantType: "application/pdf", wantStart: 36},
{name: "empty filename", data: []byte("!!FILE!!!!text/plain!!\ndata"), wantName: "", wantType: "text/plain", wantStart: 23},
{name: "not a file", data: []byte("encrypted text"), wantInvalid: true},
{name: "no newline", data: []byte("!!FILE!!test.pdf!!application/pdf!!"), wantInvalid: true},
{name: "missing content type", data: []byte("!!FILE!!test.pdf!!!!\ndata"), wantName: "test.pdf", wantType: "", wantStart: 21},
{name: "no delimiters", data: []byte("!!FILE!!nodelimiter\ndata"), wantInvalid: true},
{name: "header too long", data: append(append([]byte("!!FILE!!"), make([]byte, 5000)...), '\n'), wantInvalid: true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
name, ctype, start := ParseFileHeader(tt.data)
if tt.wantInvalid {
assert.Equal(t, -1, start)
return
}
assert.Equal(t, tt.wantName, name)
assert.Equal(t, tt.wantType, ctype)
assert.Equal(t, tt.wantStart, start)
})
}
}
func TestMessageProc_MakeMessage_ClientEnc(t *testing.T) {
s := &EngineMock{
SaveFunc: func(ctx context.Context, msg *store.Message) error { return nil },
}
c := &CrypterMock{
EncryptFunc: func(req Request) ([]byte, error) {
t.Fatal("encrypt should not be called with ClientEnc=true")
return nil, nil
},
}
m := New(s, c, Params{MaxPinAttempts: 2, MaxDuration: time.Minute})
r, err := m.MakeMessage(t.Context(), MsgReq{Duration: time.Second * 30, Message: "plain text message", Pin: "56789", ClientEnc: true})
require.NoError(t, err)
assert.Equal(t, "plain text message", string(r.Data), "data should be stored as-is")
assert.True(t, r.ClientEnc, "ClientEnc should be true")
assert.Contains(t, r.PinHash, "$2a$", "pin should still be hashed")
assert.Len(t, s.SaveCalls(), 1)
assert.Empty(t, c.EncryptCalls(), "encrypt should not be called")
}
func TestMessageProc_MakeMessage_ServerEnc(t *testing.T) {
s := &EngineMock{
SaveFunc: func(ctx context.Context, msg *store.Message) error { return nil },
}
c := &CrypterMock{
EncryptFunc: func(req Request) ([]byte, error) {
return []byte("encrypted-data"), nil
},
}
m := New(s, c, Params{MaxPinAttempts: 2, MaxDuration: time.Minute})
r, err := m.MakeMessage(t.Context(), MsgReq{Duration: time.Second * 30, Message: "plain text message", Pin: "56789", ClientEnc: false})
require.NoError(t, err)
assert.Equal(t, "encrypted-data", string(r.Data), "data should be encrypted")
assert.False(t, r.ClientEnc, "ClientEnc should be false")
assert.Len(t, c.EncryptCalls(), 1, "encrypt should be called")
assert.Len(t, s.SaveCalls(), 1)
}
func TestMessageProc_LoadMessage_ClientEnc(t *testing.T) {
storedData := []byte("client-encrypted-blob")
s := &EngineMock{
LoadFunc: func(ctx context.Context, key string) (*store.Message, error) {
return &store.Message{
Key: "test-key",
Data: storedData,
PinHash: "$2a$10$2d9OIFG2.zuVIiZznlpy/uJoTl4quQPbDSFnHbi0LuYDILuxHYkDu", // hash of "123456"
Exp: time.Now().Add(1 * time.Minute),
ClientEnc: true,
}, nil
},
RemoveFunc: func(ctx context.Context, key string) error { return nil },
}
c := &CrypterMock{
DecryptFunc: func(req Request) ([]byte, error) {
t.Fatal("decrypt should not be called for ClientEnc message")
return nil, nil
},
}
m := New(s, c, Params{MaxPinAttempts: 2, MaxDuration: time.Minute})
r, err := m.LoadMessage(t.Context(), "test-key", "123456")
require.NoError(t, err)
assert.Equal(t, "client-encrypted-blob", string(r.Data), "data should be returned as-is")
assert.Len(t, s.LoadCalls(), 1)
assert.Len(t, s.RemoveCalls(), 1, "message should still be removed after access")
assert.Empty(t, c.DecryptCalls(), "decrypt should not be called")
}
func TestMessageProc_LoadMessage_ServerEnc(t *testing.T) {
s := &EngineMock{
LoadFunc: func(ctx context.Context, key string) (*store.Message, error) {
return &store.Message{
Key: "test-key",
Data: []byte("server-encrypted-data"),
PinHash: "$2a$10$2d9OIFG2.zuVIiZznlpy/uJoTl4quQPbDSFnHbi0LuYDILuxHYkDu", // hash of "123456"
Exp: time.Now().Add(1 * time.Minute),
ClientEnc: false,
}, nil
},
RemoveFunc: func(ctx context.Context, key string) error { return nil },
}
c := &CrypterMock{
DecryptFunc: func(req Request) ([]byte, error) {
return []byte("decrypted plaintext"), nil
},
}
m := New(s, c, Params{MaxPinAttempts: 2, MaxDuration: time.Minute})
r, err := m.LoadMessage(t.Context(), "test-key", "123456")
require.NoError(t, err)
assert.Equal(t, "decrypted plaintext", string(r.Data), "data should be decrypted")
assert.Len(t, s.LoadCalls(), 1)
assert.Len(t, s.RemoveCalls(), 1)
assert.Len(t, c.DecryptCalls(), 1, "decrypt should be called")
}
================================================
FILE: app/server/assets/efs.go
================================================
// Package assets provides embedded static files and templates
package assets
import "embed"
// Files is embedded static files
//
//go:embed "html" "static"
var Files embed.FS
================================================
FILE: app/server/assets/html/index.tmpl.html
================================================
{{define "base"}}
<!DOCTYPE html>
<html lang="en" {{if ne .Theme "auto"}}data-theme="{{.Theme}}"{{end}}>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>{{if .PageTitle}}{{.PageTitle}}{{else}}{{template "title" .}} - {{.Branding}}{{end}}</title>
<meta name="description" content="{{if .PageDesc}}{{.PageDesc}}{{else}}Share sensitive information securely with encrypted, self-destructing messages protected by PIN codes. Free, open-source, and privacy-focused.{{end}}">
<meta name="keywords" content="secret sharing, password sharing, secure file sharing, encrypted messages, self-destructing messages, PIN protection, sensitive information, privacy, security">
<meta name="author" content="Umputun">
<meta name="robots" content="{{if .IsMessagePage}}noindex, nofollow{{else}}index, follow{{end}}">
<!-- Canonical URL -->
<link rel="canonical" href="{{.URL}}">
<!-- Open Graph / Facebook -->
<meta property="og:type" content="website">
<meta property="og:url" content="{{.URL}}">
<meta property="og:title" content="{{if .PageTitle}}{{.PageTitle}}{{else}}{{template "title" .}} - {{.Branding}}{{end}}">
<meta property="og:description" content="{{if .PageDesc}}{{.PageDesc}}{{else}}Share sensitive information securely with encrypted, self-destructing messages protected by PIN codes.{{end}}">
<meta property="og:image" content="{{.BaseURL}}/static/img/logo-social.png">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:site_name" content="{{.Branding}}">
<!-- Twitter -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:url" content="{{.URL}}">
<meta name="twitter:title" content="{{if .PageTitle}}{{.PageTitle}}{{else}}{{template "title" .}} - {{.Branding}}{{end}}">
<meta name="twitter:description" content="{{if .PageDesc}}{{.PageDesc}}{{else}}Share sensitive information securely with encrypted, self-destructing messages protected by PIN codes.{{end}}">
<meta name="twitter:image" content="{{.BaseURL}}/static/img/logo-social.png">
<!-- Favicons -->
<link rel='shortcut icon' href='/static/img/favicon.ico' type='image/x-icon'>
<link rel="icon" type="image/png" sizes="32x32" href="/static/img/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/static/img/favicon-16x16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/static/img/apple-touch-icon.png">
<meta name="theme-color" content="#14b8a6">
<!-- Preconnect for performance -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<!-- Stylesheets -->
<link rel='stylesheet' href='/static/css/main.css?v={{.Version}}'>
<!-- Structured Data JSON-LD -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@graph": [
{
"@type": "Organization",
"@id": "{{jsonEscape .BaseURL}}/#organization",
"name": "{{jsonEscape .Branding}}",
"url": "{{jsonEscape .BaseURL}}",
"logo": "{{jsonEscape .BaseURL}}/static/img/logo-social.png"
},
{
"@type": "WebSite",
"@id": "{{jsonEscape .BaseURL}}/#website",
"url": "{{jsonEscape .BaseURL}}",
"name": "{{jsonEscape .Branding}}",
"publisher": {"@id": "{{jsonEscape .BaseURL}}/#organization"}
},
{
"@type": "WebApplication",
"name": "{{jsonEscape .Branding}}",
"url": "{{jsonEscape .BaseURL}}",
"description": "{{if .PageDesc}}{{jsonEscape .PageDesc}}{{else}}{{jsonEscape "Share sensitive information securely with encrypted, self-destructing messages protected by PIN codes."}}{{end}}",
"applicationCategory": "SecurityApplication",
"operatingSystem": "Any",
"offers": {
"@type": "Offer",
"price": "0",
"priceCurrency": "USD"
},
"author": {
"@type": "Person",
"name": "Umputun",
"url": "https://github.com/umputun"
}
},
{
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Home",
"item": "{{jsonEscape .BaseURL}}/"
}{{if .BreadcrumbName}},
{
"@type": "ListItem",
"position": 2,
"name": "{{jsonEscape .BreadcrumbName}}",
"item": "{{jsonEscape .URL}}"
}{{end}}
]
}
]
}
</script>
</head>
<body hx-boost="true" hx-ext="response-targets">
<div id="notifications" class="toast-container"></div>
<div class="app">
<button hx-post="/theme"
hx-trigger="click"
id="theme-toggle"
class="theme-toggle"
aria-label="Toggle theme">
<svg id="theme-icon" width="28" height="28" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
{{if eq .Theme "dark"}}
<!-- sun icon (shown in dark mode, click to go light) -->
<circle cx="12" cy="12" r="4" fill="currentColor"/>
<path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M6.34 17.66l-1.41 1.41M17.66 6.34l1.41-1.41" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
{{else}}
<!-- moon icon (shown in light mode, click to go dark) -->
<path d="M20 11.5C19.25 12.3 18.2 12.9 17 12.9C14.5 12.9 12.5 10.9 12.5 8.4C12.5 7.2 13 6.15 13.8 5.4C13.7 5.4 13.6 5.4 13.5 5.4C9.9 5.4 7 8.3 7 11.9S9.9 18.4 13.5 18.4S20 15.5 20 11.9C20 11.8 20 11.65 20 11.5Z" fill="currentColor" transform="translate(-1, 0)"/>
{{end}}
</svg>
</button>
<div class="app-container">
<div class="logo-title">
<a href='/' class="logo-link" hx-boost="false">
<svg class="logo-icon" width="28" height="28" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="3" y="11" width="18" height="11" rx="2" ry="2" stroke="currentColor" stroke-width="2"/>
<circle cx="12" cy="16" r="1.5" fill="currentColor"/>
<path d="M7 11V7a5 5 0 0 1 10 0v4" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
</svg>
<span class="app-name">{{.Branding}}</span>
</a>
</div>
<main class="main-content">
{{template "main" .}}
</main>
<div class="app-footer">
<a href="/about" class="footer-link">How it works</a>
<span class="separator">•</span>
<a href="https://github.com/umputun/secrets" class="footer-link">Source code</a>
<span class="separator">•</span>
<span class="copyright">© Umputun, {{.CurrentYear}}</span>
</div>
</div>
</div>
<div id="popup" class="popup"></div>
<script src="/static/js/htmx.min.js?v={{.Version}}"></script>
<script src="/static/js/htmx-response-targets.js?v={{.Version}}"></script>
<script src="/static/js/crypto.js?v={{.Version}}"></script>
<script src="/static/js/app.js?v={{.Version}}"></script>
</body>
</html>
{{end}}
================================================
FILE: app/server/assets/html/pages/404.tmpl.html
================================================
{{define "title"}}Not Found{{end}}
{{define "main"}}
<h1>NOT FOUND</h1>
{{end}}
================================================
FILE: app/server/assets/html/pages/about.tmpl.html
================================================
{{define "title"}}How it works{{end}}
{{define "main"}}
<div class="card">
<div class="card-header">
<h1 class="card-title">How SafeSecret Works</h1>
<p class="card-description">
SafeSecret is a simple service made for a single purpose: sharing confidential information in an easy, quick and secure way.
Think of it as writing a paper note, letting someone read it, then burning it.
</p>
<p class="card-description">
Once the link is opened with the input of your 5-digit PIN, it can never be opened or seen again — the information self-destructs without a trace.
</p>
</div>
</div>
<div class="how-it-works-container">
<h1>How it works</h1>
<div class="steps-container">
<div class="step-card">
<div class="circle">1</div>
<div class="step-text">
<p>Simply type or paste any text into SafeSecret</p>
</div>
</div>
<div class="step-card">
<div class="circle">2</div>
<div class="step-text">
<p>Create a 5-digit PIN</p>
</div>
</div>
<div class="step-card">
<div class="circle">3</div>
<div class="step-text">
<p>Define for how long you'd like the information to be accessible</p>
</div>
</div>
<div class="step-card">
<div class="circle">4</div>
<div class="step-text">
<p>Copy the link generated by SafeSecret</p>
</div>
</div>
<div class="step-card">
<div class="circle">5</div>
<div class="step-text">
<p>Share it with someone in any way you'd like</p>
</div>
</div>
<div class="step-card">
<div class="circle">6</div>
<div class="step-text">
<p>Share your PIN using a different communication channel</p>
</div>
</div>
</div>
<a href="/" class="main-btn-link" hx-boost="false">Generate Secure Link</a>
</div>
{{end}}
================================================
FILE: app/server/assets/html/pages/home.tmpl.html
================================================
{{define "title"}}Home{{end}}
{{define "main"}}
<div class="card" id="form-card">
<div class="card-header">
<div class="card-title-row">
<h2 class="card-title">Create a Secure Message</h2>
{{if .FilesEnabled}}
<div class="mode-toggle">
<button type="button" class="mode-btn active" id="text-tab" data-action="switch-tab" data-mode="text">Text</button>
<button type="button" class="mode-btn" id="file-tab" data-action="switch-tab" data-mode="file">File</button>
</div>
{{end}}
</div>
<p class="card-description">Share sensitive information that self-destructs after being read</p>
</div>
<form id="secret-form"
data-max-file-size="{{.MaxFileSize}}"
hx-post="/generate-link"
hx-target="#form-card"
hx-swap="outerHTML"
hx-indicator="#form-spinner"
hx-target-400="#form-card"
hx-target-401="#popup"
hx-target-500="#notifications"
hx-trigger="submit, submitSecretForm from:body">
<div id="content-input">
<div id="text-input-container">
{{template "text-input" .}}
</div>
{{if .FilesEnabled}}
<div id="file-input-container" style="display: none;">
{{template "file-input" .}}
</div>
{{end}}
</div>
<div class="form-row two-cols">
<div class="form-group">
<label for="pin">
<svg class="input-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="3" y="11" width="18" height="11" rx="2" ry="2" stroke="currentColor" stroke-width="2"/>
<circle cx="12" cy="16" r="1" fill="currentColor"/>
<path d="M7 11V7a5 5 0 0 1 10 0v4" stroke="currentColor" stroke-width="2"/>
</svg>
{{if .AllowNoPin}}{{.PinSize}}-digit PIN <span class="optional-hint">(optional)</span>{{else}}Create {{.PinSize}}-digit PIN{{end}}
</label>
<input type="text"
name="pin"
id="pin"
class="pin-input {{if .Form.FieldErrors.pin}}error-input{{end}}"
{{if not .AllowNoPin}}required{{end}}
maxlength="{{.PinSize}}"
inputmode="numeric"
pattern="{{if .AllowNoPin}}|[0-9]{{printf "{%d}" .PinSize}}{{else}}[0-9]{{printf "{%d}" .PinSize}}{{end}}"
placeholder="{{range $i := until .PinSize}}{{add $i 1}}{{end}}"
title="{{if .AllowNoPin}}PIN is optional or must be exactly {{.PinSize}} digits{{else}}PIN must be exactly {{.PinSize}} digits{{end}}"
aria-label="{{.PinSize}}-digit PIN"
data-numeric-only />
{{with .Form.FieldErrors.pin}}
<span class='error'>{{.}}</span>
{{end}}
</div>
<div class="form-group">
<label for="exp">
Expire in
<span class="tooltip">
<svg class="tooltip-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2"/>
<path d="M9.09 9C9.3251 8.33167 9.78915 7.76811 10.4 7.40913C11.0108 7.05016 11.7289 6.91894 12.4272 7.03871C13.1255 7.15849 13.7588 7.52152 14.2151 8.06353C14.6713 8.60553 14.9211 9.29152 14.92 10C14.92 12 11.92 13 11.92 13" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 17H12.01" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
<span class="tooltip-text">{{if .Form.MaxExp}}Maximum: {{.Form.MaxExp}}{{else}}Set expiration time for automatic deletion{{end}}</span>
</span>
</label>
<div class="expire-container">
<input type="number"
name="exp"
id="exp"
required
min="1"
value="{{.Form.Exp}}"
{{if .Form.FieldErrors.exp}}class="error-input" data-clear-expire-errors{{end}} />
<select name="expUnit" id="expUnit" aria-label="Time unit"
{{if .Form.FieldErrors.expUnit}}class="error-input"{{end}}
{{if or .Form.FieldErrors.exp .Form.FieldErrors.expUnit}}data-clear-expire-errors{{end}}>
<option value="m" {{if eq .Form.ExpUnit "m"}}selected{{end}}>minutes</option>
<option value="h" {{if eq .Form.ExpUnit "h"}}selected{{end}}>hours</option>
<option value="d" {{if eq .Form.ExpUnit "d"}}selected{{end}}>days</option>
</select>
</div>
{{with .Form.FieldErrors.exp}}
<span class='error'>{{.}}</span>
{{end}}
{{with .Form.FieldErrors.expUnit}}
<span class='error'>{{.}}</span>
{{end}}
</div>
</div>
<div id="form-errors"></div>
<button type="submit" class="main-btn">
<span class="htmx-indicator" id="form-spinner">
<svg class="spinner-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
</svg>
Generating...
</span>
<span class="button-text">
<svg class="btn-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" stroke="currentColor" stroke-width="2"/>
<path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" stroke="currentColor" stroke-width="2"/>
</svg>
Generate Secure Link
</span>
</button>
</form>
</div>
{{template "no-pin-modal" .}}
{{end}}
{{define "text-input"}}
<div class="form-group">
<label for="message">
<svg class="input-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" stroke="currentColor" stroke-width="2"/>
<polyline points="14,2 14,8 20,8" stroke="currentColor" stroke-width="2"/>
<line x1="16" y1="13" x2="8" y2="13" stroke="currentColor" stroke-width="2"/>
<line x1="16" y1="17" x2="8" y2="17" stroke="currentColor" stroke-width="2"/>
<polyline points="10,9 9,9 8,9" stroke="currentColor" stroke-width="2"/>
</svg>
Enter text for sharing
</label>
<textarea name="message" id="message" class="content-input-area{{if .Form.FieldErrors.message}} error-input{{end}}"
placeholder="Type or paste your confidential message here..."
required
autofocus>{{.Form.Message}}</textarea>
{{with .Form.FieldErrors.message}}
<span class='error'>{{.}}</span>
{{end}}
</div>
{{end}}
{{define "file-input"}}
<div class="form-group">
<label>
<svg class="input-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" stroke="currentColor" stroke-width="2"/>
<polyline points="17 8 12 3 7 8" stroke="currentColor" stroke-width="2"/>
<line x1="12" y1="3" x2="12" y2="15" stroke="currentColor" stroke-width="2"/>
</svg>
Upload file
</label>
<div id="drop-zone" class="drop-zone content-input-area" data-action="trigger-file-input">
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" stroke="currentColor" stroke-width="1.5"/>
<polyline points="17 8 12 3 7 8" stroke="currentColor" stroke-width="1.5"/>
<line x1="12" y1="3" x2="12" y2="15" stroke="currentColor" stroke-width="1.5"/>
</svg>
<p>Drop file here or click to browse</p>
<p id="file-info" class="file-info" style="display:none"></p>
</div>
<input type="file" id="file" name="file" style="display:none" />
</div>
{{end}}
================================================
FILE: app/server/assets/html/pages/message-error.tmpl.html
================================================
{{define "title"}}Message Unavailable{{end}}
{{define "main"}}
<div class="card error-card">
<div class="card-header">
<h2 class="card-title">Message Unavailable</h2>
<p class="card-description">{{.Form}}</p>
</div>
<a class="main-btn" href="/" hx-boost="false">Create New Secret</a>
</div>
{{end}}
================================================
FILE: app/server/assets/html/pages/show-message.tmpl.html
================================================
{{define "title"}}Your message{{end}}
{{define "main"}}
<div id="show-msg" class="show-msg">
<div id="message-container">
{{/* error div for client-encrypted messages with missing key */}}
<div id="key-error" class="card error-card" style="display:none;">
<div class="card-header">
<h2 class="card-title">Decryption Key Missing</h2>
</div>
<p class="error-message">The decryption key is missing from the URL. This can happen when sharing links through apps that strip URL fragments.</p>
<p class="error-message">Please ask the sender to share the complete link including the # portion.</p>
<a href="/" class="main-btn" hx-boost="false">Back to Main Page</a>
</div>
{{/* client-side decryption form - shown when URL has #key */}}
<div id="client-decrypt-form" class="card load-msg-form" style="display:none;">
<div class="card-header">
<h2 class="card-title">{{if .HasPin}}Decrypt Secret{{else}}Reveal Secret{{end}}</h2>
<p class="card-description">{{if .HasPin}}Enter your {{.PinSize}}-digit PIN to decrypt the secret{{else}}Click below to reveal and decrypt the secret{{end}}</p>
</div>
<form id="decrypt-form" hx-boost="false">
<input type="hidden" name="key" value="{{.Form.Key}}" />
{{if .HasPin}}
<div class="form-group">
<input type="text"
name="pin"
id="client-pin"
class="pin-input"
required
maxlength="{{.PinSize}}"
inputmode="numeric"
pattern="[0-9]{{printf "{%d}" .PinSize}}"
placeholder="{{range $i := until .PinSize}}{{add $i 1}}{{end}}"
title="PIN must be exactly {{.PinSize}} digits"
aria-label="{{.PinSize}}-digit PIN"
data-numeric-only
data-error-target="client-pin-error" />
<div id="client-pin-error">
{{with .Form.FieldErrors.pin}}
<span class='error'>{{.}}</span>
{{end}}
</div>
</div>
{{else}}
<input type="hidden" name="pin" id="client-pin" value="" />
<div id="client-pin-error"></div>
{{end}}
<button class="main-btn" type="submit" id="decrypt-btn">
<span class="button-text" id="btn-text">
<svg class="btn-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
{{if .HasPin}}
<rect x="3" y="11" width="18" height="11" rx="2" ry="2" stroke="currentColor" stroke-width="2"/>
<circle cx="12" cy="16" r="1" fill="currentColor"/>
<path d="M7 11V7a5 5 0 0 1 10 0v4" stroke="currentColor" stroke-width="2"/>
{{else}}
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" stroke="currentColor" stroke-width="2"/>
<circle cx="12" cy="12" r="3" stroke="currentColor" stroke-width="2"/>
{{end}}
</svg>
{{if .HasPin}}Decrypt{{else}}Reveal Secret{{end}}
</span>
<span class="button-text" id="btn-loading" style="display:none;">{{if .HasPin}}Decrypting{{else}}Revealing{{end}}...</span>
</button>
</form>
</div>
{{/* server-side forms - shown when no #key in URL */}}
<div id="server-forms">
{{if .IsFile}}
{{/* file download: use JS to handle binary response */}}
<div class="card load-msg-form" id="pin-form-card">
<div class="card-header">
<h2 class="card-title">Download File</h2>
<p class="card-description">{{if .HasPin}}Enter your {{.PinSize}}-digit PIN to download the encrypted file{{else}}Click below to download the encrypted file{{end}}</p>
</div>
<form id="download-form" hx-boost="false">
<input type="hidden" name="key" value="{{.Form.Key}}" />
{{if .HasPin}}
<div class="form-group">
<input type="text"
name="pin"
id="pin"
class="pin-input {{if .Form.FieldErrors.pin}}error-input{{end}}"
required
maxlength="{{.PinSize}}"
inputmode="numeric"
pattern="[0-9]{{printf "{%d}" .PinSize}}"
placeholder="{{range $i := until .PinSize}}{{add $i 1}}{{end}}"
title="PIN must be exactly {{.PinSize}} digits"
aria-label="{{.PinSize}}-digit PIN"
autofocus
data-numeric-only
data-error-target="pin-error" />
<div id="pin-error">
{{with .Form.FieldErrors.pin}}
<span class='error'>{{.}}</span>
{{end}}
</div>
</div>
{{else}}
<input type="hidden" name="pin" id="pin" value="" />
{{end}}
<button class="main-btn" type="submit" id="download-btn">
<span class="button-text" id="download-btn-text">
<svg class="btn-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" stroke="currentColor" stroke-width="2"/>
<polyline points="7 10 12 15 17 10" stroke="currentColor" stroke-width="2"/>
<line x1="12" y1="15" x2="12" y2="3" stroke="currentColor" stroke-width="2"/>
</svg>
Download File
</span>
<span class="button-text" id="download-btn-loading" style="display:none;">Downloading...</span>
</button>
</form>
</div>
{{else}}
{{/* text message: use HTMX for inline decryption */}}
<div class="card load-msg-form" id="pin-form-card">
<div class="card-header">
<h2 class="card-title">{{if .HasPin}}Access Message{{else}}Reveal Secret{{end}}</h2>
<p class="card-description">{{if .HasPin}}Enter your {{.PinSize}}-digit PIN to decrypt and view the message{{else}}Click below to reveal the secret message{{end}}</p>
</div>
<form hx-post="/load-message"
hx-target="#message-container"
hx-swap="innerHTML"
hx-indicator="#decrypt-spinner"
hx-target-404="#message-container"
hx-target-403="#message-container"
id="load-msg-form">
<input type="hidden" name="key" id="key" value="{{.Form.Key}}" />
{{if .HasPin}}
<div class="form-group">
<input type="text"
name="pin"
id="pin"
class="pin-input {{if .Form.FieldErrors.pin}}error-input{{end}}"
required
maxlength="{{.PinSize}}"
inputmode="numeric"
pattern="[0-9]{{printf "{%d}" .PinSize}}"
placeholder="{{range $i := until .PinSize}}{{add $i 1}}{{end}}"
title="PIN must be exactly {{.PinSize}} digits"
aria-label="{{.PinSize}}-digit PIN"
autofocus
data-numeric-only
data-error-target="pin-error" />
<div id="pin-error">
{{with .Form.FieldErrors.pin}}
<span class='error'>{{.}}</span>
{{end}}
</div>
</div>
{{else}}
<input type="hidden" name="pin" id="pin" value="" />
{{end}}
<button class="main-btn" type="submit">
<span class="htmx-indicator" id="decrypt-spinner">
<svg class="spinner-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
</svg>
{{if .HasPin}}Decrypting{{else}}Revealing{{end}}...
</span>
<span class="button-text">
<svg class="btn-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
{{if .HasPin}}
<rect x="3" y="11" width="18" height="11" rx="2" ry="2" stroke="currentColor" stroke-width="2"/>
<circle cx="12" cy="16" r="1" fill="currentColor"/>
<path d="M7 11V7a5 5 0 0 1 10 0v4" stroke="currentColor" stroke-width="2"/>
{{else}}
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" stroke="currentColor" stroke-width="2"/>
<circle cx="12" cy="12" r="3" stroke="currentColor" stroke-width="2"/>
{{end}}
</svg>
{{if .HasPin}}Decode Message{{else}}Reveal Secret{{end}}
</span>
</button>
</form>
</div>
{{end}}
</div>
</div>
</div>
{{end}}
================================================
FILE: app/server/assets/html/partials/copy-button.tmpl.html
================================================
{{define "copy-button"}}
<button type="button"
class="main-btn copy-btn"
data-action="copy-text"
data-text="{{.Text}}"
data-type="{{.Type}}"
hx-post="/copy-feedback"
hx-vals='{"type": "{{.Type}}"}'
hx-target="#popup"
hx-swap="outerHTML"
hx-trigger="click">
<svg class="btn-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="9" y="9" width="13" height="13" rx="2" ry="2" stroke="currentColor" stroke-width="2"/>
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" stroke="currentColor" stroke-width="2"/>
</svg>
<span class="btn-text">{{.ButtonText}}</span>
</button>
{{end}}
{{define "copy-success"}}
<button type="button" class="main-btn copy-btn" style="background: var(--color-success);">
<svg class="btn-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<polyline points="20,6 9,17 4,12" stroke="currentColor" stroke-width="2"/>
</svg>
<span class="btn-text">Copied!</span>
</button>
{{end}}
================================================
FILE: app/server/assets/html/partials/decoded-message.tmpl.html
================================================
{{define "decoded-message"}}
<div id="msg" class="card">
<div class="card-header">
<h2 class="card-title card-title-with-icon">
<svg class="title-icon" width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="3" y="11" width="18" height="10" rx="2" ry="2" stroke="currentColor" stroke-width="2"/>
<circle cx="12" cy="16" r="1" fill="currentColor"/>
<path d="M7 11V7a5 5 0 0 1 10 0" stroke="currentColor" stroke-width="2"/>
</svg>
Message Decrypted
</h2>
<p class="card-description">This message will self-destruct immediately. Copy it now if needed.</p>
</div>
<div class="form-group">
<label for="decoded-msg-text">
<svg class="input-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" stroke="currentColor" stroke-width="2"/>
<polyline points="14,2 14,8 20,8" stroke="currentColor" stroke-width="2"/>
<line x1="16" y1="13" x2="8" y2="13" stroke="currentColor" stroke-width="2"/>
<line x1="16" y1="17" x2="8" y2="17" stroke="currentColor" stroke-width="2"/>
<polyline points="10,9 9,9 8,9" stroke="currentColor" stroke-width="2"/>
</svg>
Your Secret Message
</label>
<textarea name="msg-text"
id="decoded-msg-text"
readonly>{{.}}</textarea>
</div>
<button type="button"
class="main-btn"
id="copy-msg-btn"
data-action="copy-decoded-message"
data-source="decoded-msg-text">
<svg class="btn-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="9" y="9" width="13" height="13" rx="2" ry="2" stroke="currentColor" stroke-width="2"/>
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" stroke="currentColor" stroke-width="2"/>
</svg>
Copy Message
</button>
</div>
{{end}}
================================================
FILE: app/server/assets/html/partials/email-popup.tmpl.html
================================================
{{define "email-popup"}}
<div id="popup" class="popup active">
<div class="popup-content email-popup">
<div class="popup-header">
<h2 class="card-title card-title-with-icon">
<svg class="title-icon" width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M22 2L11 13" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M22 2L15 22L11 13L2 9L22 2Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
Send via Email
</h2>
</div>
<form hx-post="/send-email"
hx-target="#popup"
hx-swap="outerHTML"
class="email-form">
{{if .Error}}
<div class="form-error">{{.Error}}</div>
{{end}}
<input type="hidden" name="link" value="{{.Link}}">
<div class="form-field">
<label for="subject">Subject</label>
<input type="text"
id="subject"
name="subject"
value="{{.Subject}}"
placeholder="Email subject"
required>
</div>
<div class="form-field">
<label for="from-name">From (display name)</label>
<input type="text"
id="from-name"
name="from_name"
value="{{.FromName}}"
placeholder="Sender name">
</div>
<div class="form-field">
<label for="to">To</label>
<input type="email"
id="to"
name="to"
value="{{.To}}"
placeholder="recipient@example.com"
autocomplete="email"
data-autofocus
required>
</div>
<div class="form-actions">
<button type="button"
hx-get="/close-popup"
hx-target="#popup"
hx-swap="outerHTML"
class="second-btn">Cancel</button>
<button type="submit" class="main-btn">
<svg class="btn-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M22 2L11 13" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M22 2L15 22L11 13L2 9L22 2Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
Send
</button>
</div>
</form>
</div>
</div>
{{end}}
================================================
FILE: app/server/assets/html/partials/email-sent.tmpl.html
================================================
{{define "email-sent"}}
<div id="popup" class="popup active">
<div class="popup-content">
<div class="popup-header">
<div></div>
<button hx-get="/close-popup"
hx-target="#popup"
hx-swap="outerHTML"
class="close-popup">
<img src="/static/img/close.svg" alt="close" />
</button>
</div>
<div class="popup-text email-sent-success">
<svg class="success-icon" width="48" height="48" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2"/>
<polyline points="8,12 11,15 16,9" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
<strong>Email sent successfully!</strong>
<span>The secure link has been sent to {{.To}}</span>
</div>
</div>
</div>
{{end}}
================================================
FILE: app/server/assets/html/partials/error.tmpl.html
================================================
{{define "error"}}
<div class="card error-card">
<div class="card-header" style="text-align: center;">
<h2 class="card-title">Message Unavailable</h2>
<p class="error-message" style="color: var(--color-error);">{{.}}</p>
</div>
<a class="main-btn" href="/" hx-boost="false">Create New Secret</a>
</div>
{{end}}
================================================
FILE: app/server/assets/html/partials/login-popup.tmpl.html
================================================
{{define "login-popup"}}
<div id="popup" class="popup active">
<div class="popup-content login-popup">
<div class="popup-header">
<span class="popup-title">Login Required</span>
<button hx-get="/close-popup"
hx-target="#popup"
hx-swap="outerHTML"
class="close-popup">
<img src="/static/img/close.svg" alt="close" />
</button>
</div>
<form hx-post="/login"
hx-target="#popup"
hx-swap="outerHTML"
class="login-form">
{{if .Error}}
<div class="form-error">{{.Error}}</div>
{{end}}
<div class="form-field">
<label for="password">Password</label>
<input type="password"
id="password"
name="password"
placeholder="Enter password"
autocomplete="current-password"
data-autofocus
required>
</div>
<button type="submit" class="btn btn-primary">Login</button>
</form>
</div>
</div>
{{end}}
================================================
FILE: app/server/assets/html/partials/no-pin-modal.tmpl.html
================================================
{{define "no-pin-modal"}}
{{if .AllowNoPin}}
<div id="no-pin-modal" class="popup">
<div class="popup-content no-pin-modal-content">
<h2 class="no-pin-title">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg">
<path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/>
<line x1="12" y1="9" x2="12" y2="13"/>
<line x1="12" y1="17" x2="12.01" y2="17"/>
</svg>
Create without PIN?
</h2>
<p class="no-pin-description">
Anyone with this link can access your secret once. After viewing, it will be permanently deleted.
</p>
<p class="no-pin-hint">
Use this option when sharing via Signal or other end-to-end encrypted messengers.
</p>
<div class="no-pin-actions">
<button type="button" id="no-pin-cancel" class="second-btn">Add PIN</button>
<button type="button" id="no-pin-confirm" class="main-btn">Continue</button>
</div>
</div>
</div>
{{end}}
{{end}}
================================================
FILE: app/server/assets/html/partials/popup.tmpl.html
================================================
{{define "popup"}}
<div id="popup" class="popup active">
<div class="popup-content">
<div class="popup-header">
<div></div>
<button hx-get="/close-popup"
hx-target="#popup"
hx-swap="outerHTML"
class="close-popup">
<img src="/static/img/close.svg" alt="close" />
</button>
</div>
<div class="popup-text">
<strong>{{.CopyType}} copied!</strong>
{{if eq .CopyType "Link"}}<br/>Share this link to access your secret content{{end}}
</div>
</div>
</div>
{{end}}
{{define "popup-closed"}}
<div id="popup" class="popup"></div>
{{end}}
================================
gitextract__fg68ugu/
├── .dockerignore
├── .github/
│ ├── dependabot.yml
│ └── workflows/
│ ├── ci.yml
│ ├── e2e.yml
│ └── release.yml
├── .gitignore
├── .golangci.yml
├── .goreleaser.yml
├── .zed/
│ └── tasks.json
├── CHANGELOG.md
├── CLAUDE.md
├── Dockerfile
├── LICENSE
├── Makefile
├── README.md
├── app/
│ ├── email/
│ │ ├── email.go
│ │ ├── email.tmpl.html
│ │ ├── email_test.go
│ │ └── mocks/
│ │ └── notifier_mock.go
│ ├── main.go
│ ├── messager/
│ │ ├── crypt.go
│ │ ├── crypt_mock.go
│ │ ├── crypt_test.go
│ │ ├── engine_mock.go
│ │ ├── messager.go
│ │ └── messager_test.go
│ ├── server/
│ │ ├── assets/
│ │ │ ├── efs.go
│ │ │ ├── html/
│ │ │ │ ├── index.tmpl.html
│ │ │ │ ├── pages/
│ │ │ │ │ ├── 404.tmpl.html
│ │ │ │ │ ├── about.tmpl.html
│ │ │ │ │ ├── home.tmpl.html
│ │ │ │ │ ├── message-error.tmpl.html
│ │ │ │ │ └── show-message.tmpl.html
│ │ │ │ └── partials/
│ │ │ │ ├── copy-button.tmpl.html
│ │ │ │ ├── decoded-message.tmpl.html
│ │ │ │ ├── email-popup.tmpl.html
│ │ │ │ ├── email-sent.tmpl.html
│ │ │ │ ├── error.tmpl.html
│ │ │ │ ├── login-popup.tmpl.html
│ │ │ │ ├── no-pin-modal.tmpl.html
│ │ │ │ ├── popup.tmpl.html
│ │ │ │ └── secure-link.tmpl.html
│ │ │ └── static/
│ │ │ ├── css/
│ │ │ │ └── main.css
│ │ │ └── js/
│ │ │ ├── app.js
│ │ │ ├── crypto.js
│ │ │ └── htmx-response-targets.js
│ │ ├── auth.go
│ │ ├── auth_test.go
│ │ ├── middleware.go
│ │ ├── middleware_test.go
│ │ ├── mocks/
│ │ │ └── email_sender_mock.go
│ │ ├── server.go
│ │ ├── server_test.go
│ │ ├── validator/
│ │ │ ├── validator.go
│ │ │ └── validator_test.go
│ │ ├── web.go
│ │ └── web_test.go
│ └── store/
│ ├── sqlite.go
│ ├── sqlite_test.go
│ ├── store.go
│ └── store_test.go
├── completions/
│ ├── secrets.bash
│ ├── secrets.fish
│ └── secrets.zsh
├── docker-compose-dev.yml
├── docker-compose-reproxy.yml
├── docker-compose.yml
├── docs/
│ └── plans/
│ └── completed/
│ ├── 2025-12-26-paranoid-mode-sqlite.md
│ ├── 2025-12-27-hybrid-encryption.md
│ ├── 2025-12-29-optional-pin.md
│ └── 2026-01-15-csp-inline-scripts-elimination.md
├── e2e/
│ ├── auth_test.go
│ ├── crypto_test.go
│ ├── e2e_test.go
│ ├── email_test.go
│ ├── file_test.go
│ ├── hybrid_test.go
│ └── no_pin_test.go
├── go.mod
├── go.sum
├── secrets-nginx.conf
├── secrets.rest
└── vendor/
├── github.com/
│ ├── aymerick/
│ │ └── douceur/
│ │ ├── LICENSE
│ │ ├── css/
│ │ │ ├── declaration.go
│ │ │ ├── rule.go
│ │ │ └── stylesheet.go
│ │ └── parser/
│ │ └── parser.go
│ ├── davecgh/
│ │ └── go-spew/
│ │ ├── LICENSE
│ │ └── spew/
│ │ ├── bypass.go
│ │ ├── bypasssafe.go
│ │ ├── common.go
│ │ ├── config.go
│ │ ├── doc.go
│ │ ├── dump.go
│ │ ├── format.go
│ │ └── spew.go
│ ├── deckarep/
│ │ └── golang-set/
│ │ └── v2/
│ │ ├── .gitignore
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── iterator.go
│ │ ├── set.go
│ │ ├── sorted.go
│ │ ├── threadsafe.go
│ │ └── threadunsafe.go
│ ├── didip/
│ │ └── tollbooth/
│ │ └── v8/
│ │ ├── .gitignore
│ │ ├── .golangci.yml
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── errors/
│ │ │ └── errors.go
│ │ ├── internal/
│ │ │ └── time/
│ │ │ ├── AUTHORS
│ │ │ ├── CONTRIBUTORS
│ │ │ ├── LICENSE
│ │ │ ├── PATENTS
│ │ │ └── rate/
│ │ │ └── rate.go
│ │ ├── libstring/
│ │ │ └── libstring.go
│ │ ├── limiter/
│ │ │ ├── limiter.go
│ │ │ └── limiter_options.go
│ │ └── tollbooth.go
│ ├── dustin/
│ │ └── go-humanize/
│ │ ├── .travis.yml
│ │ ├── LICENSE
│ │ ├── README.markdown
│ │ ├── big.go
│ │ ├── bigbytes.go
│ │ ├── bytes.go
│ │ ├── comma.go
│ │ ├── commaf.go
│ │ ├── ftoa.go
│ │ ├── humanize.go
│ │ ├── number.go
│ │ ├── ordinals.go
│ │ ├── si.go
│ │ └── times.go
│ ├── go-jose/
│ │ └── go-jose/
│ │ └── v3/
│ │ ├── LICENSE
│ │ └── json/
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── decode.go
│ │ ├── encode.go
│ │ ├── indent.go
│ │ ├── scanner.go
│ │ ├── stream.go
│ │ └── tags.go
│ ├── go-pkgz/
│ │ ├── email/
│ │ │ ├── .gitignore
│ │ │ ├── .golangci.yml
│ │ │ ├── LICENSE
│ │ │ ├── README.md
│ │ │ ├── auth.go
│ │ │ ├── email.go
│ │ │ └── options.go
│ │ ├── expirable-cache/
│ │ │ └── v3/
│ │ │ ├── LICENSE
│ │ │ ├── cache.go
│ │ │ └── options.go
│ │ ├── notify/
│ │ │ ├── .golangci.yml
│ │ │ ├── LICENSE
│ │ │ ├── README.md
│ │ │ ├── email.go
│ │ │ ├── interface.go
│ │ │ ├── slack.go
│ │ │ ├── telegram.go
│ │ │ └── webhook.go
│ │ ├── repeater/
│ │ │ ├── .gitignore
│ │ │ ├── .golangci.yml
│ │ │ ├── LICENSE
│ │ │ ├── README.md
│ │ │ ├── repeater.go
│ │ │ └── strategy/
│ │ │ ├── backoff.go
│ │ │ ├── fixed.go
│ │ │ └── strategy.go
│ │ └── routegroup/
│ │ ├── .gitignore
│ │ ├── .golangci.yml
│ │ ├── LICENSE
│ │ ├── README.md
│ │ └── group.go
│ ├── go-stack/
│ │ └── stack/
│ │ ├── LICENSE.md
│ │ ├── README.md
│ │ └── stack.go
│ ├── google/
│ │ └── uuid/
│ │ ├── CHANGELOG.md
│ │ ├── CONTRIBUTING.md
│ │ ├── CONTRIBUTORS
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── dce.go
│ │ ├── doc.go
│ │ ├── hash.go
│ │ ├── marshal.go
│ │ ├── node.go
│ │ ├── node_js.go
│ │ ├── node_net.go
│ │ ├── null.go
│ │ ├── sql.go
│ │ ├── time.go
│ │ ├── util.go
│ │ ├── uuid.go
│ │ ├── version1.go
│ │ ├── version4.go
│ │ ├── version6.go
│ │ └── version7.go
│ ├── gorilla/
│ │ ├── css/
│ │ │ ├── LICENSE
│ │ │ └── scanner/
│ │ │ ├── doc.go
│ │ │ └── scanner.go
│ │ └── websocket/
│ │ ├── .gitignore
│ │ ├── AUTHORS
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── client.go
│ │ ├── compression.go
│ │ ├── conn.go
│ │ ├── doc.go
│ │ ├── join.go
│ │ ├── json.go
│ │ ├── mask.go
│ │ ├── mask_safe.go
│ │ ├── prepared.go
│ │ ├── proxy.go
│ │ ├── server.go
│ │ ├── tls_handshake.go
│ │ ├── tls_handshake_116.go
│ │ ├── util.go
│ │ └── x_net_proxy.go
│ ├── mattn/
│ │ └── go-isatty/
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── doc.go
│ │ ├── go.test.sh
│ │ ├── isatty_bsd.go
│ │ ├── isatty_others.go
│ │ ├── isatty_plan9.go
│ │ ├── isatty_solaris.go
│ │ ├── isatty_tcgets.go
│ │ └── isatty_windows.go
│ ├── microcosm-cc/
│ │ └── bluemonday/
│ │ ├── CONTRIBUTING.md
│ │ ├── CREDITS.md
│ │ ├── LICENSE.md
│ │ ├── README.md
│ │ ├── SECURITY.md
│ │ ├── css/
│ │ │ └── handlers.go
│ │ ├── doc.go
│ │ ├── helpers.go
│ │ ├── policies.go
│ │ ├── policy.go
│ │ └── sanitize.go
│ ├── ncruces/
│ │ └── go-strftime/
│ │ ├── .gitignore
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── parser.go
│ │ ├── pkg.go
│ │ ├── specifiers.go
│ │ └── strftime.go
│ ├── pmezard/
│ │ └── go-difflib/
│ │ ├── LICENSE
│ │ └── difflib/
│ │ └── difflib.go
│ ├── remyoudompheng/
│ │ └── bigfft/
│ │ ├── LICENSE
│ │ ├── README
│ │ ├── arith_decl.go
│ │ ├── fermat.go
│ │ ├── fft.go
│ │ └── scan.go
│ ├── stretchr/
│ │ └── testify/
│ │ ├── LICENSE
│ │ ├── assert/
│ │ │ ├── assertion_compare.go
│ │ │ ├── assertion_format.go
│ │ │ ├── assertion_format.go.tmpl
│ │ │ ├── assertion_forward.go
│ │ │ ├── assertion_forward.go.tmpl
│ │ │ ├── assertion_order.go
│ │ │ ├── assertions.go
│ │ │ ├── doc.go
│ │ │ ├── errors.go
│ │ │ ├── forward_assertions.go
│ │ │ ├── http_assertions.go
│ │ │ └── yaml/
│ │ │ ├── yaml_custom.go
│ │ │ ├── yaml_default.go
│ │ │ └── yaml_fail.go
│ │ └── require/
│ │ ├── doc.go
│ │ ├── forward_requirements.go
│ │ ├── require.go
│ │ ├── require.go.tmpl
│ │ ├── require_forward.go
│ │ ├── require_forward.go.tmpl
│ │ └── requirements.go
│ └── umputun/
│ └── go-flags/
│ ├── .travis.yml
│ ├── LICENSE
│ ├── README.md
│ ├── arg.go
│ ├── check_crosscompile.sh
│ ├── closest.go
│ ├── command.go
│ ├── completion.go
│ ├── convert.go
│ ├── error.go
│ ├── flags.go
│ ├── group.go
│ ├── help.go
│ ├── ini.go
│ ├── man.go
│ ├── multitag.go
│ ├── option.go
│ ├── optstyle_other.go
│ ├── optstyle_windows.go
│ ├── parser.go
│ ├── termsize.go
│ ├── termsize_nosysioctl.go
│ ├── termsize_windows.go
│ ├── tiocgwinsz_bsdish.go
│ ├── tiocgwinsz_linux.go
│ └── tiocgwinsz_other.go
├── golang.org/
│ └── x/
│ ├── crypto/
│ │ ├── LICENSE
│ │ ├── PATENTS
│ │ ├── argon2/
│ │ │ ├── argon2.go
│ │ │ ├── blake2b.go
│ │ │ ├── blamka_amd64.go
│ │ │ ├── blamka_amd64.s
│ │ │ ├── blamka_generic.go
│ │ │ └── blamka_ref.go
│ │ ├── bcrypt/
│ │ │ ├── base64.go
│ │ │ └── bcrypt.go
│ │ ├── blake2b/
│ │ │ ├── blake2b.go
│ │ │ ├── blake2bAVX2_amd64.go
│ │ │ ├── blake2bAVX2_amd64.s
│ │ │ ├── blake2b_amd64.s
│ │ │ ├── blake2b_generic.go
│ │ │ ├── blake2b_ref.go
│ │ │ ├── blake2x.go
│ │ │ ├── go125.go
│ │ │ └── register.go
│ │ ├── blowfish/
│ │ │ ├── block.go
│ │ │ ├── cipher.go
│ │ │ └── const.go
│ │ ├── internal/
│ │ │ ├── alias/
│ │ │ │ ├── alias.go
│ │ │ │ └── alias_purego.go
│ │ │ └── poly1305/
│ │ │ ├── mac_noasm.go
│ │ │ ├── poly1305.go
│ │ │ ├── sum_amd64.s
│ │ │ ├── sum_asm.go
│ │ │ ├── sum_generic.go
│ │ │ ├── sum_loong64.s
│ │ │ ├── sum_ppc64x.s
│ │ │ ├── sum_s390x.go
│ │ │ └── sum_s390x.s
│ │ ├── nacl/
│ │ │ └── secretbox/
│ │ │ └── secretbox.go
│ │ └── salsa20/
│ │ └── salsa/
│ │ ├── hsalsa20.go
│ │ ├── salsa208.go
│ │ ├── salsa20_amd64.go
│ │ ├── salsa20_amd64.s
│ │ ├── salsa20_noasm.go
│ │ └── salsa20_ref.go
│ ├── net/
│ │ ├── LICENSE
│ │ ├── PATENTS
│ │ └── html/
│ │ ├── atom/
│ │ │ ├── atom.go
│ │ │ └── table.go
│ │ ├── const.go
│ │ ├── doc.go
│ │ ├── doctype.go
│ │ ├── entity.go
│ │ ├── escape.go
│ │ ├── foreign.go
│ │ ├── iter.go
│ │ ├── node.go
│ │ ├── nodetype_string.go
│ │ ├── parse.go
│ │ ├── render.go
│ │ └── token.go
│ └── sys/
│ ├── LICENSE
│ ├── PATENTS
│ ├── cpu/
│ │ ├── asm_aix_ppc64.s
│ │ ├── asm_darwin_arm64_gc.s
│ │ ├── asm_darwin_x86_gc.s
│ │ ├── byteorder.go
│ │ ├── cpu.go
│ │ ├── cpu_aix.go
│ │ ├── cpu_arm.go
│ │ ├── cpu_arm64.go
│ │ ├── cpu_arm64.s
│ │ ├── cpu_darwin_arm64.go
│ │ ├── cpu_darwin_arm64_other.go
│ │ ├── cpu_darwin_x86.go
│ │ ├── cpu_gc_arm64.go
│ │ ├── cpu_gc_s390x.go
│ │ ├── cpu_gc_x86.go
│ │ ├── cpu_gc_x86.s
│ │ ├── cpu_gccgo_arm64.go
│ │ ├── cpu_gccgo_s390x.go
│ │ ├── cpu_gccgo_x86.c
│ │ ├── cpu_gccgo_x86.go
│ │ ├── cpu_linux.go
│ │ ├── cpu_linux_arm.go
│ │ ├── cpu_linux_arm64.go
│ │ ├── cpu_linux_loong64.go
│ │ ├── cpu_linux_mips64x.go
│ │ ├── cpu_linux_noinit.go
│ │ ├── cpu_linux_ppc64x.go
│ │ ├── cpu_linux_riscv64.go
│ │ ├── cpu_linux_s390x.go
│ │ ├── cpu_loong64.go
│ │ ├── cpu_loong64.s
│ │ ├── cpu_mips64x.go
│ │ ├── cpu_mipsx.go
│ │ ├── cpu_netbsd_arm64.go
│ │ ├── cpu_openbsd_arm64.go
│ │ ├── cpu_openbsd_arm64.s
│ │ ├── cpu_other_arm.go
│ │ ├── cpu_other_arm64.go
│ │ ├── cpu_other_mips64x.go
│ │ ├── cpu_other_ppc64x.go
│ │ ├── cpu_other_riscv64.go
│ │ ├── cpu_other_x86.go
│ │ ├── cpu_ppc64x.go
│ │ ├── cpu_riscv64.go
│ │ ├── cpu_s390x.go
│ │ ├── cpu_s390x.s
│ │ ├── cpu_wasm.go
│ │ ├── cpu_windows_arm64.go
│ │ ├── cpu_x86.go
│ │ ├── cpu_zos.go
│ │ ├── cpu_zos_s390x.go
│ │ ├── endian_big.go
│ │ ├── endian_little.go
│ │ ├── hwcap_linux.go
│ │ ├── parse.go
│ │ ├── proc_cpuinfo_linux.go
│ │ ├── runtime_auxv.go
│ │ ├── runtime_auxv_go121.go
│ │ ├── syscall_aix_gccgo.go
│ │ ├── syscall_aix_ppc64_gc.go
│ │ ├── syscall_darwin_arm64_gc.go
│ │ └── syscall_darwin_x86_gc.go
│ ├── unix/
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── affinity_linux.go
│ │ ├── aliases.go
│ │ ├── asm_aix_ppc64.s
│ │ ├── asm_bsd_386.s
│ │ ├── asm_bsd_amd64.s
│ │ ├── asm_bsd_arm.s
│ │ ├── asm_bsd_arm64.s
│ │ ├── asm_bsd_ppc64.s
│ │ ├── asm_bsd_riscv64.s
│ │ ├── asm_linux_386.s
│ │ ├── asm_linux_amd64.s
│ │ ├── asm_linux_arm.s
│ │ ├── asm_linux_arm64.s
│ │ ├── asm_linux_loong64.s
│ │ ├── asm_linux_mips64x.s
│ │ ├── asm_linux_mipsx.s
│ │ ├── asm_linux_ppc64x.s
│ │ ├── asm_linux_riscv64.s
│ │ ├── asm_linux_s390x.s
│ │ ├── asm_openbsd_mips64.s
│ │ ├── asm_solaris_amd64.s
│ │ ├── asm_zos_s390x.s
│ │ ├── auxv.go
│ │ ├── auxv_unsupported.go
│ │ ├── bluetooth_linux.go
│ │ ├── bpxsvc_zos.go
│ │ ├── bpxsvc_zos.s
│ │ ├── cap_freebsd.go
│ │ ├── constants.go
│ │ ├── dev_aix_ppc.go
│ │ ├── dev_aix_ppc64.go
│ │ ├── dev_darwin.go
│ │ ├── dev_dragonfly.go
│ │ ├── dev_freebsd.go
│ │ ├── dev_linux.go
│ │ ├── dev_netbsd.go
│ │ ├── dev_openbsd.go
│ │ ├── dev_zos.go
│ │ ├── dirent.go
│ │ ├── endian_big.go
│ │ ├── endian_little.go
│ │ ├── env_unix.go
│ │ ├── fcntl.go
│ │ ├── fcntl_darwin.go
│ │ ├── fcntl_linux_32bit.go
│ │ ├── fdset.go
│ │ ├── gccgo.go
│ │ ├── gccgo_c.c
│ │ ├── gccgo_linux_amd64.go
│ │ ├── ifreq_linux.go
│ │ ├── ioctl_linux.go
│ │ ├── ioctl_signed.go
│ │ ├── ioctl_unsigned.go
│ │ ├── ioctl_zos.go
│ │ ├── mkall.sh
│ │ ├── mkerrors.sh
│ │ ├── mmap_nomremap.go
│ │ ├── mremap.go
│ │ ├── pagesize_unix.go
│ │ ├── pledge_openbsd.go
│ │ ├── ptrace_darwin.go
│ │ ├── ptrace_ios.go
│ │ ├── race.go
│ │ ├── race0.go
│ │ ├── readdirent_getdents.go
│ │ ├── readdirent_getdirentries.go
│ │ ├── sockcmsg_dragonfly.go
│ │ ├── sockcmsg_linux.go
│ │ ├── sockcmsg_unix.go
│ │ ├── sockcmsg_unix_other.go
│ │ ├── sockcmsg_zos.go
│ │ ├── symaddr_zos_s390x.s
│ │ ├── syscall.go
│ │ ├── syscall_aix.go
│ │ ├── syscall_aix_ppc.go
│ │ ├── syscall_aix_ppc64.go
│ │ ├── syscall_bsd.go
│ │ ├── syscall_darwin.go
│ │ ├── syscall_darwin_amd64.go
│ │ ├── syscall_darwin_arm64.go
│ │ ├── syscall_darwin_libSystem.go
│ │ ├── syscall_dragonfly.go
│ │ ├── syscall_dragonfly_amd64.go
│ │ ├── syscall_freebsd.go
│ │ ├── syscall_freebsd_386.go
│ │ ├── syscall_freebsd_amd64.go
│ │ ├── syscall_freebsd_arm.go
│ │ ├── syscall_freebsd_arm64.go
│ │ ├── syscall_freebsd_riscv64.go
│ │ ├── syscall_hurd.go
│ │ ├── syscall_hurd_386.go
│ │ ├── syscall_illumos.go
│ │ ├── syscall_linux.go
│ │ ├── syscall_linux_386.go
│ │ ├── syscall_linux_alarm.go
│ │ ├── syscall_linux_amd64.go
│ │ ├── syscall_linux_amd64_gc.go
│ │ ├── syscall_linux_arm.go
│ │ ├── syscall_linux_arm64.go
│ │ ├── syscall_linux_gc.go
│ │ ├── syscall_linux_gc_386.go
│ │ ├── syscall_linux_gc_arm.go
│ │ ├── syscall_linux_gccgo_386.go
│ │ ├── syscall_linux_gccgo_arm.go
│ │ ├── syscall_linux_loong64.go
│ │ ├── syscall_linux_mips64x.go
│ │ ├── syscall_linux_mipsx.go
│ │ ├── syscall_linux_ppc.go
│ │ ├── syscall_linux_ppc64x.go
│ │ ├── syscall_linux_riscv64.go
│ │ ├── syscall_linux_s390x.go
│ │ ├── syscall_linux_sparc64.go
│ │ ├── syscall_netbsd.go
│ │ ├── syscall_netbsd_386.go
│ │ ├── syscall_netbsd_amd64.go
│ │ ├── syscall_netbsd_arm.go
│ │ ├── syscall_netbsd_arm64.go
│ │ ├── syscall_openbsd.go
│ │ ├── syscall_openbsd_386.go
│ │ ├── syscall_openbsd_amd64.go
│ │ ├── syscall_openbsd_arm.go
│ │ ├── syscall_openbsd_arm64.go
│ │ ├── syscall_openbsd_libc.go
│ │ ├── syscall_openbsd_mips64.go
│ │ ├── syscall_openbsd_ppc64.go
│ │ ├── syscall_openbsd_riscv64.go
│ │ ├── syscall_solaris.go
│ │ ├── syscall_solaris_amd64.go
│ │ ├── syscall_unix.go
│ │ ├── syscall_unix_gc.go
│ │ ├── syscall_unix_gc_ppc64x.go
│ │ ├── syscall_zos_s390x.go
│ │ ├── sysvshm_linux.go
│ │ ├── sysvshm_unix.go
│ │ ├── sysvshm_unix_other.go
│ │ ├── timestruct.go
│ │ ├── unveil_openbsd.go
│ │ ├── vgetrandom_linux.go
│ │ ├── vgetrandom_unsupported.go
│ │ ├── xattr_bsd.go
│ │ ├── zerrors_aix_ppc.go
│ │ ├── zerrors_aix_ppc64.go
│ │ ├── zerrors_darwin_amd64.go
│ │ ├── zerrors_darwin_arm64.go
│ │ ├── zerrors_dragonfly_amd64.go
│ │ ├── zerrors_freebsd_386.go
│ │ ├── zerrors_freebsd_amd64.go
│ │ ├── zerrors_freebsd_arm.go
│ │ ├── zerrors_freebsd_arm64.go
│ │ ├── zerrors_freebsd_riscv64.go
│ │ ├── zerrors_linux.go
│ │ ├── zerrors_linux_386.go
│ │ ├── zerrors_linux_amd64.go
│ │ ├── zerrors_linux_arm.go
│ │ ├── zerrors_linux_arm64.go
│ │ ├── zerrors_linux_loong64.go
│ │ ├── zerrors_linux_mips.go
│ │ ├── zerrors_linux_mips64.go
│ │ ├── zerrors_linux_mips64le.go
│ │ ├── zerrors_linux_mipsle.go
│ │ ├── zerrors_linux_ppc.go
│ │ ├── zerrors_linux_ppc64.go
│ │ ├── zerrors_linux_ppc64le.go
│ │ ├── zerrors_linux_riscv64.go
│ │ ├── zerrors_linux_s390x.go
│ │ ├── zerrors_linux_sparc64.go
│ │ ├── zerrors_netbsd_386.go
│ │ ├── zerrors_netbsd_amd64.go
│ │ ├── zerrors_netbsd_arm.go
│ │ ├── zerrors_netbsd_arm64.go
│ │ ├── zerrors_openbsd_386.go
│ │ ├── zerrors_openbsd_amd64.go
│ │ ├── zerrors_openbsd_arm.go
│ │ ├── zerrors_openbsd_arm64.go
│ │ ├── zerrors_openbsd_mips64.go
│ │ ├── zerrors_openbsd_ppc64.go
│ │ ├── zerrors_openbsd_riscv64.go
│ │ ├── zerrors_solaris_amd64.go
│ │ ├── zerrors_zos_s390x.go
│ │ ├── zptrace_armnn_linux.go
│ │ ├── zptrace_linux_arm64.go
│ │ ├── zptrace_mipsnn_linux.go
│ │ ├── zptrace_mipsnnle_linux.go
│ │ ├── zptrace_x86_linux.go
│ │ ├── zsymaddr_zos_s390x.s
│ │ ├── zsyscall_aix_ppc.go
│ │ ├── zsyscall_aix_ppc64.go
│ │ ├── zsyscall_aix_ppc64_gc.go
│ │ ├── zsyscall_aix_ppc64_gccgo.go
│ │ ├── zsyscall_darwin_amd64.go
│ │ ├── zsyscall_darwin_amd64.s
│ │ ├── zsyscall_darwin_arm64.go
│ │ ├── zsyscall_darwin_arm64.s
│ │ ├── zsyscall_dragonfly_amd64.go
│ │ ├── zsyscall_freebsd_386.go
│ │ ├── zsyscall_freebsd_amd64.go
│ │ ├── zsyscall_freebsd_arm.go
│ │ ├── zsyscall_freebsd_arm64.go
│ │ ├── zsyscall_freebsd_riscv64.go
│ │ ├── zsyscall_illumos_amd64.go
│ │ ├── zsyscall_linux.go
│ │ ├── zsyscall_linux_386.go
│ │ ├── zsyscall_linux_amd64.go
│ │ ├── zsyscall_linux_arm.go
│ │ ├── zsyscall_linux_arm64.go
│ │ ├── zsyscall_linux_loong64.go
│ │ ├── zsyscall_linux_mips.go
│ │ ├── zsyscall_linux_mips64.go
│ │ ├── zsyscall_linux_mips64le.go
│ │ ├── zsyscall_linux_mipsle.go
│ │ ├── zsyscall_linux_ppc.go
│ │ ├── zsyscall_linux_ppc64.go
│ │ ├── zsyscall_linux_ppc64le.go
│ │ ├── zsyscall_linux_riscv64.go
│ │ ├── zsyscall_linux_s390x.go
│ │ ├── zsyscall_linux_sparc64.go
│ │ ├── zsyscall_netbsd_386.go
│ │ ├── zsyscall_netbsd_amd64.go
│ │ ├── zsyscall_netbsd_arm.go
│ │ ├── zsyscall_netbsd_arm64.go
│ │ ├── zsyscall_openbsd_386.go
│ │ ├── zsyscall_openbsd_386.s
│ │ ├── zsyscall_openbsd_amd64.go
│ │ ├── zsyscall_openbsd_amd64.s
│ │ ├── zsyscall_openbsd_arm.go
│ │ ├── zsyscall_openbsd_arm.s
│ │ ├── zsyscall_openbsd_arm64.go
│ │ ├── zsyscall_openbsd_arm64.s
│ │ ├── zsyscall_openbsd_mips64.go
│ │ ├── zsyscall_openbsd_mips64.s
│ │ ├── zsyscall_openbsd_ppc64.go
│ │ ├── zsyscall_openbsd_ppc64.s
│ │ ├── zsyscall_openbsd_riscv64.go
│ │ ├── zsyscall_openbsd_riscv64.s
│ │ ├── zsyscall_solaris_amd64.go
│ │ ├── zsyscall_zos_s390x.go
│ │ ├── zsysctl_openbsd_386.go
│ │ ├── zsysctl_openbsd_amd64.go
│ │ ├── zsysctl_openbsd_arm.go
│ │ ├── zsysctl_openbsd_arm64.go
│ │ ├── zsysctl_openbsd_mips64.go
│ │ ├── zsysctl_openbsd_ppc64.go
│ │ ├── zsysctl_openbsd_riscv64.go
│ │ ├── zsysnum_darwin_amd64.go
│ │ ├── zsysnum_darwin_arm64.go
│ │ ├── zsysnum_dragonfly_amd64.go
│ │ ├── zsysnum_freebsd_386.go
│ │ ├── zsysnum_freebsd_amd64.go
│ │ ├── zsysnum_freebsd_arm.go
│ │ ├── zsysnum_freebsd_arm64.go
│ │ ├── zsysnum_freebsd_riscv64.go
│ │ ├── zsysnum_linux_386.go
│ │ ├── zsysnum_linux_amd64.go
│ │ ├── zsysnum_linux_arm.go
│ │ ├── zsysnum_linux_arm64.go
│ │ ├── zsysnum_linux_loong64.go
│ │ ├── zsysnum_linux_mips.go
│ │ ├── zsysnum_linux_mips64.go
│ │ ├── zsysnum_linux_mips64le.go
│ │ ├── zsysnum_linux_mipsle.go
│ │ ├── zsysnum_linux_ppc.go
│ │ ├── zsysnum_linux_ppc64.go
│ │ ├── zsysnum_linux_ppc64le.go
│ │ ├── zsysnum_linux_riscv64.go
│ │ ├── zsysnum_linux_s390x.go
│ │ ├── zsysnum_linux_sparc64.go
│ │ ├── zsysnum_netbsd_386.go
│ │ ├── zsysnum_netbsd_amd64.go
│ │ ├── zsysnum_netbsd_arm.go
│ │ ├── zsysnum_netbsd_arm64.go
│ │ ├── zsysnum_openbsd_386.go
│ │ ├── zsysnum_openbsd_amd64.go
│ │ ├── zsysnum_openbsd_arm.go
│ │ ├── zsysnum_openbsd_arm64.go
│ │ ├── zsysnum_openbsd_mips64.go
│ │ ├── zsysnum_openbsd_ppc64.go
│ │ ├── zsysnum_openbsd_riscv64.go
│ │ ├── zsysnum_zos_s390x.go
│ │ ├── ztypes_aix_ppc.go
│ │ ├── ztypes_aix_ppc64.go
│ │ ├── ztypes_darwin_amd64.go
│ │ ├── ztypes_darwin_arm64.go
│ │ ├── ztypes_dragonfly_amd64.go
│ │ ├── ztypes_freebsd_386.go
│ │ ├── ztypes_freebsd_amd64.go
│ │ ├── ztypes_freebsd_arm.go
│ │ ├── ztypes_freebsd_arm64.go
│ │ ├── ztypes_freebsd_riscv64.go
│ │ ├── ztypes_linux.go
│ │ ├── ztypes_linux_386.go
│ │ ├── ztypes_linux_amd64.go
│ │ ├── ztypes_linux_arm.go
│ │ ├── ztypes_linux_arm64.go
│ │ ├── ztypes_linux_loong64.go
│ │ ├── ztypes_linux_mips.go
│ │ ├── ztypes_linux_mips64.go
│ │ ├── ztypes_linux_mips64le.go
│ │ ├── ztypes_linux_mipsle.go
│ │ ├── ztypes_linux_ppc.go
│ │ ├── ztypes_linux_ppc64.go
│ │ ├── ztypes_linux_ppc64le.go
│ │ ├── ztypes_linux_riscv64.go
│ │ ├── ztypes_linux_s390x.go
│ │ ├── ztypes_linux_sparc64.go
│ │ ├── ztypes_netbsd_386.go
│ │ ├── ztypes_netbsd_amd64.go
│ │ ├── ztypes_netbsd_arm.go
│ │ ├── ztypes_netbsd_arm64.go
│ │ ├── ztypes_openbsd_386.go
│ │ ├── ztypes_openbsd_amd64.go
│ │ ├── ztypes_openbsd_arm.go
│ │ ├── ztypes_openbsd_arm64.go
│ │ ├── ztypes_openbsd_mips64.go
│ │ ├── ztypes_openbsd_ppc64.go
│ │ ├── ztypes_openbsd_riscv64.go
│ │ ├── ztypes_solaris_amd64.go
│ │ └── ztypes_zos_s390x.go
│ └── windows/
│ ├── aliases.go
│ ├── dll_windows.go
│ ├── env_windows.go
│ ├── eventlog.go
│ ├── exec_windows.go
│ ├── memory_windows.go
│ ├── mkerrors.bash
│ ├── mkknownfolderids.bash
│ ├── mksyscall.go
│ ├── race.go
│ ├── race0.go
│ ├── security_windows.go
│ ├── service.go
│ ├── setupapi_windows.go
│ ├── str.go
│ ├── syscall.go
│ ├── syscall_windows.go
│ ├── types_windows.go
│ ├── types_windows_386.go
│ ├── types_windows_amd64.go
│ ├── types_windows_arm.go
│ ├── types_windows_arm64.go
│ ├── zerrors_windows.go
│ ├── zknownfolderids_windows.go
│ └── zsyscall_windows.go
├── gopkg.in/
│ └── yaml.v3/
│ ├── LICENSE
│ ├── NOTICE
│ ├── README.md
│ ├── apic.go
│ ├── decode.go
│ ├── emitterc.go
│ ├── encode.go
│ ├── parserc.go
│ ├── readerc.go
│ ├── resolve.go
│ ├── scannerc.go
│ ├── sorter.go
│ ├── writerc.go
│ ├── yaml.go
│ ├── yamlh.go
│ └── yamlprivateh.go
├── modernc.org/
│ ├── libc/
│ │ ├── .gitignore
│ │ ├── AUTHORS
│ │ ├── CONTRIBUTING.md
│ │ ├── CONTRIBUTORS
│ │ ├── LICENSE
│ │ ├── LICENSE-3RD-PARTY.md
│ │ ├── Makefile
│ │ ├── README.md
│ │ ├── abi0_linux_amd64.go
│ │ ├── abi0_linux_amd64.s
│ │ ├── aliases.go
│ │ ├── asm_386.s
│ │ ├── atomic.go
│ │ ├── atomic32.go
│ │ ├── atomic64.go
│ │ ├── build_all_targets.sh
│ │ ├── builder.json
│ │ ├── builtin.go
│ │ ├── builtin32.go
│ │ ├── builtin64.go
│ │ ├── builtin_all.go
│ │ ├── capi_darwin_amd64.go
│ │ ├── capi_darwin_arm64.go
│ │ ├── capi_freebsd_386.go
│ │ ├── capi_freebsd_amd64.go
│ │ ├── capi_freebsd_arm.go
│ │ ├── capi_freebsd_arm64.go
│ │ ├── capi_illumos_amd64.go
│ │ ├── capi_linux_386.go
│ │ ├── capi_linux_amd64.go
│ │ ├── capi_linux_arm.go
│ │ ├── capi_linux_arm64.go
│ │ ├── capi_linux_loong64.go
│ │ ├── capi_linux_mips64le.go
│ │ ├── capi_linux_ppc64le.go
│ │ ├── capi_linux_riscv64.go
│ │ ├── capi_linux_s390x.go
│ │ ├── capi_netbsd_amd64.go
│ │ ├── capi_netbsd_arm.go
│ │ ├── capi_openbsd_386.go
│ │ ├── capi_openbsd_amd64.go
│ │ ├── capi_openbsd_arm64.go
│ │ ├── capi_windows_386.go
│ │ ├── capi_windows_amd64.go
│ │ ├── capi_windows_arm64.go
│ │ ├── ccgo.go
│ │ ├── ccgo_linux_386.go
│ │ ├── ccgo_linux_amd64.go
│ │ ├── ccgo_linux_arm.go
│ │ ├── ccgo_linux_arm64.go
│ │ ├── ccgo_linux_loong64.go
│ │ ├── ccgo_linux_ppc64le.go
│ │ ├── ccgo_linux_riscv64.go
│ │ ├── ccgo_linux_s390x.go
│ │ ├── dmesg.go
│ │ ├── errno/
│ │ │ ├── capi_darwin_amd64.go
│ │ │ ├── capi_darwin_arm64.go
│ │ │ ├── capi_freebsd_386.go
│ │ │ ├── capi_freebsd_amd64.go
│ │ │ ├── capi_freebsd_arm.go
│ │ │ ├── capi_freebsd_arm64.go
│ │ │ ├── capi_illumos_amd64.go
│ │ │ ├── capi_linux_386.go
│ │ │ ├── capi_linux_amd64.go
│ │ │ ├── capi_linux_arm.go
│ │ │ ├── capi_linux_arm64.go
│ │ │ ├── capi_linux_loong64.go
│ │ │ ├── capi_linux_mips64le.go
│ │ │ ├── capi_linux_ppc64le.go
│ │ │ ├── capi_linux_riscv64.go
│ │ │ ├── capi_linux_s390x.go
│ │ │ ├── capi_netbsd_amd64.go
│ │ │ ├── capi_netbsd_arm.go
│ │ │ ├── capi_openbsd_386.go
│ │ │ ├── capi_openbsd_amd64.go
│ │ │ ├── capi_openbsd_arm64.go
│ │ │ ├── capi_windows_386.go
│ │ │ ├── capi_windows_amd64.go
│ │ │ ├── capi_windows_arm64.go
│ │ │ ├── errno_darwin_amd64.go
│ │ │ ├── errno_darwin_arm64.go
│ │ │ ├── errno_freebsd_386.go
│ │ │ ├── errno_freebsd_amd64.go
│ │ │ ├── errno_freebsd_arm.go
│ │ │ ├── errno_freebsd_arm64.go
│ │ │ ├── errno_illumos_amd64.go
│ │ │ ├── errno_linux_386.go
│ │ │ ├── errno_linux_amd64.go
│ │ │ ├── errno_linux_arm.go
│ │ │ ├── errno_linux_arm64.go
│ │ │ ├── errno_linux_loong64.go
│ │ │ ├── errno_linux_mips64le.go
│ │ │ ├── errno_linux_ppc64le.go
│ │ │ ├── errno_linux_riscv64.go
│ │ │ ├── errno_linux_s390x.go
│ │ │ ├── errno_netbsd_amd64.go
│ │ │ ├── errno_netbsd_arm.go
│ │ │ ├── errno_openbsd_386.go
│ │ │ ├── errno_openbsd_amd64.go
│ │ │ ├── errno_openbsd_arm64.go
│ │ │ ├── errno_windows_386.go
│ │ │ ├── errno_windows_amd64.go
│ │ │ └── errno_windows_arm64.go
│ │ ├── etc.go
│ │ ├── etc_musl.go
│ │ ├── fcntl/
│ │ │ ├── capi_darwin_amd64.go
│ │ │ ├── capi_darwin_arm64.go
│ │ │ ├── capi_freebsd_386.go
│ │ │ ├── capi_freebsd_amd64.go
│ │ │ ├── capi_freebsd_arm.go
│ │ │ ├── capi_freebsd_arm64.go
│ │ │ ├── capi_illumos_amd64.go
│ │ │ ├── capi_linux_386.go
│ │ │ ├── capi_linux_amd64.go
│ │ │ ├── capi_linux_arm.go
│ │ │ ├── capi_linux_arm64.go
│ │ │ ├── capi_linux_loong64.go
│ │ │ ├── capi_linux_mips64le.go
│ │ │ ├── capi_linux_ppc64le.go
│ │ │ ├── capi_linux_riscv64.go
│ │ │ ├── capi_linux_s390x.go
│ │ │ ├── capi_netbsd_amd64.go
│ │ │ ├── capi_netbsd_arm.go
│ │ │ ├── capi_openbsd_386.go
│ │ │ ├── capi_openbsd_amd64.go
│ │ │ ├── capi_openbsd_arm64.go
│ │ │ ├── capi_windows_386.go
│ │ │ ├── capi_windows_amd64.go
│ │ │ ├── capi_windows_arm64.go
│ │ │ ├── fcntl_darwin_amd64.go
│ │ │ ├── fcntl_darwin_arm64.go
│ │ │ ├── fcntl_freebsd_386.go
│ │ │ ├── fcntl_freebsd_amd64.go
│ │ │ ├── fcntl_freebsd_arm.go
│ │ │ ├── fcntl_freebsd_arm64.go
│ │ │ ├── fcntl_illumos_amd64.go
│ │ │ ├── fcntl_linux_386.go
│ │ │ ├── fcntl_linux_amd64.go
│ │ │ ├── fcntl_linux_arm.go
│ │ │ ├── fcntl_linux_arm64.go
│ │ │ ├── fcntl_linux_loong64.go
│ │ │ ├── fcntl_linux_mips64le.go
│ │ │ ├── fcntl_linux_ppc64le.go
│ │ │ ├── fcntl_linux_riscv64.go
│ │ │ ├── fcntl_linux_s390x.go
│ │ │ ├── fcntl_netbsd_amd64.go
│ │ │ ├── fcntl_netbsd_arm.go
│ │ │ ├── fcntl_openbsd_386.go
│ │ │ ├── fcntl_openbsd_amd64.go
│ │ │ ├── fcntl_openbsd_arm64.go
│ │ │ ├── fcntl_windows_386.go
│ │ │ ├── fcntl_windows_amd64.go
│ │ │ └── fcntl_windows_arm64.go
│ │ ├── fsync.go
│ │ ├── fts/
│ │ │ ├── capi_darwin_amd64.go
│ │ │ ├── capi_darwin_arm64.go
│ │ │ ├── capi_freebsd_386.go
│ │ │ ├── capi_freebsd_amd64.go
│ │ │ ├── capi_freebsd_arm.go
│ │ │ ├── capi_freebsd_arm64.go
│ │ │ ├── capi_illumos_amd64.go
│ │ │ ├── capi_linux_386.go
│ │ │ ├── capi_linux_amd64.go
│ │ │ ├── capi_linux_arm.go
│ │ │ ├── capi_linux_arm64.go
│ │ │ ├── capi_linux_loong64.go
│ │ │ ├── capi_linux_mips64le.go
│ │ │ ├── capi_linux_ppc64le.go
│ │ │ ├── capi_linux_riscv64.go
│ │ │ ├── capi_linux_s390x.go
│ │ │ ├── capi_netbsd_amd64.go
│ │ │ ├── capi_netbsd_arm.go
│ │ │ ├── capi_openbsd_386.go
│ │ │ ├── capi_openbsd_amd64.go
│ │ │ ├── capi_openbsd_arm64.go
│ │ │ ├── fts_darwin_amd64.go
│ │ │ ├── fts_darwin_arm64.go
│ │ │ ├── fts_freebsd_386.go
│ │ │ ├── fts_freebsd_amd64.go
│ │ │ ├── fts_freebsd_arm.go
│ │ │ ├── fts_freebsd_arm64.go
│ │ │ ├── fts_illumos_amd64.go
│ │ │ ├── fts_linux_386.go
│ │ │ ├── fts_linux_amd64.go
│ │ │ ├── fts_linux_arm.go
│ │ │ ├── fts_linux_arm64.go
│ │ │ ├── fts_linux_loong64.go
│ │ │ ├── fts_linux_mips64le.go
│ │ │ ├── fts_linux_ppc64le.go
│ │ │ ├── fts_linux_riscv64.go
│ │ │ ├── fts_linux_s390x.go
│ │ │ ├── fts_netbsd_amd64.go
│ │ │ ├── fts_netbsd_arm.go
│ │ │ ├── fts_openbsd_386.go
│ │ │ ├── fts_openbsd_amd64.go
│ │ │ └── fts_openbsd_arm64.go
│ │ ├── grp/
│ │ │ ├── capi_darwin_amd64.go
│ │ │ ├── capi_darwin_arm64.go
│ │ │ ├── capi_freebsd_386.go
│ │ │ ├── capi_freebsd_amd64.go
│ │ │ ├── capi_freebsd_arm.go
│ │ │ ├── capi_freebsd_arm64.go
│ │ │ ├── capi_illumos_amd64.go
│ │ │ ├── capi_linux_386.go
│ │ │ ├── capi_linux_amd64.go
│ │ │ ├── capi_linux_arm.go
│ │ │ ├── capi_linux_arm64.go
│ │ │ ├── capi_linux_loong64.go
│ │ │ ├── capi_linux_mips64le.go
│ │ │ ├── capi_linux_ppc64le.go
│ │ │ ├── capi_linux_riscv64.go
│ │ │ ├── capi_linux_s390x.go
│ │ │ ├── capi_netbsd_amd64.go
│ │ │ ├── capi_netbsd_arm.go
│ │ │ ├── capi_openbsd_386.go
│ │ │ ├── capi_openbsd_amd64.go
│ │ │ ├── capi_openbsd_arm64.go
│ │ │ ├── grp_darwin_amd64.go
│ │ │ ├── grp_darwin_arm64.go
│ │ │ ├── grp_freebsd_386.go
│ │ │ ├── grp_freebsd_amd64.go
│ │ │ ├── grp_freebsd_arm.go
│ │ │ ├── grp_freebsd_arm64.go
│ │ │ ├── grp_illumos_amd64.go
│ │ │ ├── grp_linux_386.go
│ │ │ ├── grp_linux_amd64.go
│ │ │ ├── grp_linux_arm.go
│ │ │ ├── grp_linux_arm64.go
│ │ │ ├── grp_linux_loong64.go
│ │ │ ├── grp_linux_mips64le.go
│ │ │ ├── grp_linux_ppc64le.go
│ │ │ ├── grp_linux_riscv64.go
│ │ │ ├── grp_linux_s390x.go
│ │ │ ├── grp_netbsd_amd64.go
│ │ │ ├── grp_netbsd_arm.go
│ │ │ ├── grp_openbsd_386.go
│ │ │ ├── grp_openbsd_amd64.go
│ │ │ └── grp_openbsd_arm64.go
│ │ ├── honnef.co/
│ │ │ └── go/
│ │ │ └── netdb/
│ │ │ ├── README.md
│ │ │ └── netdb.go
│ │ ├── int128.go
│ │ ├── ioutil_darwin.go
│ │ ├── ioutil_freebsd.go
│ │ ├── ioutil_illumos.go
│ │ ├── ioutil_linux.go
│ │ ├── ioutil_netbsd.go
│ │ ├── ioutil_openbsd.go
│ │ ├── langinfo/
│ │ │ ├── capi_darwin_amd64.go
│ │ │ ├── capi_darwin_arm64.go
│ │ │ ├── capi_freebsd_386.go
│ │ │ ├── capi_freebsd_amd64.go
│ │ │ ├── capi_freebsd_arm.go
│ │ │ ├── capi_freebsd_arm64.go
│ │ │ ├── capi_illumos_amd64.go
│ │ │ ├── capi_linux_386.go
│ │ │ ├── capi_linux_amd64.go
│ │ │ ├── capi_linux_arm.go
│ │ │ ├── capi_linux_arm64.go
│ │ │ ├── capi_linux_loong64.go
│ │ │ ├── capi_linux_mips64le.go
│ │ │ ├── capi_linux_ppc64le.go
│ │ │ ├── capi_linux_riscv64.go
│ │ │ ├── capi_linux_s390x.go
│ │ │ ├── capi_netbsd_amd64.go
│ │ │ ├── capi_netbsd_arm.go
│ │ │ ├── capi_openbsd_386.go
│ │ │ ├── capi_openbsd_amd64.go
│ │ │ ├── capi_openbsd_arm64.go
│ │ │ ├── langinfo_darwin_amd64.go
│ │ │ ├── langinfo_darwin_arm64.go
│ │ │ ├── langinfo_freebsd_386.go
│ │ │ ├── langinfo_freebsd_amd64.go
│ │ │ ├── langinfo_freebsd_arm.go
│ │ │ ├── langinfo_freebsd_arm64.go
│ │ │ ├── langinfo_illumos_amd64.go
│ │ │ ├── langinfo_linux_386.go
│ │ │ ├── langinfo_linux_amd64.go
│ │ │ ├── langinfo_linux_arm.go
│ │ │ ├── langinfo_linux_arm64.go
│ │ │ ├── langinfo_linux_loong64.go
│ │ │ ├── langinfo_linux_mips64le.go
│ │ │ ├── langinfo_linux_ppc64le.go
│ │ │ ├── langinfo_linux_riscv64.go
│ │ │ ├── langinfo_linux_s390x.go
│ │ │ ├── langinfo_netbsd_amd64.go
│ │ │ ├── langinfo_netbsd_arm.go
│ │ │ ├── langinfo_openbsd_386.go
│ │ │ ├── langinfo_openbsd_amd64.go
│ │ │ └── langinfo_openbsd_arm64.go
│ │ ├── libc.go
│ │ ├── libc32.go
│ │ ├── libc64.go
│ │ ├── libc_386.go
│ │ ├── libc_all.go
│ │ ├── libc_amd64.go
│ │ ├── libc_arm.go
│ │ ├── libc_arm64.go
│ │ ├── libc_darwin.go
│ │ ├── libc_darwin_amd64.go
│ │ ├── libc_darwin_arm64.go
│ │ ├── libc_freebsd.go
│ │ ├── libc_freebsd_386.go
│ │ ├── libc_freebsd_amd64.go
│ │ ├── libc_freebsd_arm.go
│ │ ├── libc_freebsd_arm64.go
│ │ ├── libc_illumos.go
│ │ ├── libc_illumos_amd64.go
│ │ ├── libc_linux.go
│ │ ├── libc_linux_amd64.go
│ │ ├── libc_linux_mips64le.go
│ │ ├── libc_mips64le.go
│ │ ├── libc_musl.go
│ │ ├── libc_musl_linux_386.go
│ │ ├── libc_musl_linux_amd64.go
│ │ ├── libc_musl_linux_arm.go
│ │ ├── libc_musl_linux_arm64.go
│ │ ├── libc_musl_linux_loong64.go
│ │ ├── libc_musl_linux_ppc64le.go
│ │ ├── libc_musl_linux_riscv64.go
│ │ ├── libc_musl_linux_s390x.go
│ │ ├── libc_netbsd.go
│ │ ├── libc_netbsd_amd64.go
│ │ ├── libc_netbsd_arm.go
│ │ ├── libc_openbsd.go
│ │ ├── libc_openbsd_386.go
│ │ ├── libc_openbsd_amd64.go
│ │ ├── libc_openbsd_arm64.go
│ │ ├── libc_unix.go
│ │ ├── libc_unix1.go
│ │ ├── libc_unix2.go
│ │ ├── libc_unix3.go
│ │ ├── libc_windows.go
│ │ ├── libc_windows_386.go
│ │ ├── libc_windows_386.s
│ │ ├── libc_windows_amd64.go
│ │ ├── libc_windows_arm64.go
│ │ ├── libc_windows_arm64.s
│ │ ├── limits/
│ │ │ ├── capi_darwin_amd64.go
│ │ │ ├── capi_darwin_arm64.go
│ │ │ ├── capi_freebsd_386.go
│ │ │ ├── capi_freebsd_amd64.go
│ │ │ ├── capi_freebsd_arm.go
│ │ │ ├── capi_freebsd_arm64.go
│ │ │ ├── capi_illumos_amd64.go
│ │ │ ├── capi_linux_386.go
│ │ │ ├── capi_linux_amd64.go
│ │ │ ├── capi_linux_arm.go
│ │ │ ├── capi_linux_arm64.go
│ │ │ ├── capi_linux_loong64.go
│ │ │ ├── capi_linux_mips64le.go
│ │ │ ├── capi_linux_ppc64le.go
│ │ │ ├── capi_linux_riscv64.go
│ │ │ ├── capi_linux_s390x.go
│ │ │ ├── capi_netbsd_amd64.go
│ │ │ ├── capi_netbsd_arm.go
│ │ │ ├── capi_openbsd_386.go
│ │ │ ├── capi_openbsd_amd64.go
│ │ │ ├── capi_openbsd_arm64.go
│ │ │ ├── capi_windows_386.go
│ │ │ ├── capi_windows_amd64.go
│ │ │ ├── capi_windows_arm64.go
│ │ │ ├── limits_darwin_amd64.go
│ │ │ ├── limits_darwin_arm64.go
│ │ │ ├── limits_freebsd_386.go
│ │ │ ├── limits_freebsd_amd64.go
│ │ │ ├── limits_freebsd_arm.go
│ │ │ ├── limits_freebsd_arm64.go
│ │ │ ├── limits_illumos_amd64.go
│ │ │ ├── limits_linux_386.go
│ │ │ ├── limits_linux_amd64.go
│ │ │ ├── limits_linux_arm.go
│ │ │ ├── limits_linux_arm64.go
│ │ │ ├── limits_linux_loong64.go
│ │ │ ├── limits_linux_mips64le.go
│ │ │ ├── limits_linux_ppc64le.go
│ │ │ ├── limits_linux_riscv64.go
│ │ │ ├── limits_linux_s390x.go
│ │ │ ├── limits_netbsd_amd64.go
│ │ │ ├── limits_netbsd_arm.go
│ │ │ ├── limits_openbsd_386.go
│ │ │ ├── limits_openbsd_amd64.go
│ │ │ ├── limits_openbsd_arm64.go
│ │ │ ├── limits_windows_386.go
│ │ │ ├── limits_windows_amd64.go
│ │ │ └── limits_windows_arm64.go
│ │ ├── mem.go
│ │ ├── mem_brk.go
│ │ ├── mem_brk_musl.go
│ │ ├── mem_expvar.go
│ │ ├── mem_musl.go
│ │ ├── memgrind.go
│ │ ├── memgrind_musl.go
│ │ ├── musl_darwin_amd64.go
│ │ ├── musl_darwin_arm64.go
│ │ ├── musl_freebsd_386.go
│ │ ├── musl_freebsd_amd64.go
│ │ ├── musl_freebsd_arm.go
│ │ ├── musl_freebsd_arm64.go
│ │ ├── musl_illumos_amd64.go
│ │ ├── musl_linux_mips64le.go
│ │ ├── musl_netbsd_amd64.go
│ │ ├── musl_netbsd_arm.go
│ │ ├── musl_openbsd_386.go
│ │ ├── musl_openbsd_amd64.go
│ │ ├── musl_openbsd_arm64.go
│ │ ├── musl_windows_386.go
│ │ ├── musl_windows_amd64.go
│ │ ├── musl_windows_arm64.go
│ │ ├── netdb/
│ │ │ ├── capi_darwin_amd64.go
│ │ │ ├── capi_darwin_arm64.go
│ │ │ ├── capi_freebsd_386.go
│ │ │ ├── capi_freebsd_amd64.go
│ │ │ ├── capi_freebsd_arm.go
│ │ │ ├── capi_freebsd_arm64.go
│ │ │ ├── capi_illumos_amd64.go
│ │ │ ├── capi_linux_386.go
│ │ │ ├── capi_linux_amd64.go
│ │ │ ├── capi_linux_arm.go
│ │ │ ├── capi_linux_arm64.go
│ │ │ ├── capi_linux_loong64.go
│ │ │ ├── capi_linux_mips64le.go
│ │ │ ├── capi_linux_ppc64le.go
│ │ │ ├── capi_linux_riscv64.go
│ │ │ ├── capi_linux_s390x.go
│ │ │ ├── capi_netbsd_amd64.go
│ │ │ ├── capi_netbsd_arm.go
│ │ │ ├── capi_openbsd_386.go
│ │ │ ├── capi_openbsd_amd64.go
│ │ │ ├── capi_openbsd_arm64.go
│ │ │ ├── netdb_darwin_amd64.go
│ │ │ ├── netdb_darwin_arm64.go
│ │ │ ├── netdb_freebsd_386.go
│ │ │ ├── netdb_freebsd_amd64.go
│ │ │ ├── netdb_freebsd_arm.go
│ │ │ ├── netdb_freebsd_arm64.go
│ │ │ ├── netdb_illumos_amd64.go
│ │ │ ├── netdb_linux_386.go
│ │ │ ├── netdb_linux_amd64.go
│ │ │ ├── netdb_linux_arm.go
│ │ │ ├── netdb_linux_arm64.go
│ │ │ ├── netdb_linux_loong64.go
│ │ │ ├── netdb_linux_mips64le.go
│ │ │ ├── netdb_linux_ppc64le.go
│ │ │ ├── netdb_linux_riscv64.go
│ │ │ ├── netdb_linux_s390x.go
│ │ │ ├── netdb_netbsd_amd64.go
│ │ │ ├── netdb_netbsd_arm.go
│ │ │ ├── netdb_openbsd_386.go
│ │ │ ├── netdb_openbsd_amd64.go
│ │ │ └── netdb_openbsd_arm64.go
│ │ ├── netinet/
│ │ │ └── in/
│ │ │ ├── capi_darwin_amd64.go
│ │ │ ├── capi_darwin_arm64.go
│ │ │ ├── capi_freebsd_386.go
│ │ │ ├── capi_freebsd_amd64.go
│ │ │ ├── capi_freebsd_arm.go
│ │ │ ├── capi_freebsd_arm64.go
│ │ │ ├── capi_illumos_amd64.go
│ │ │ ├── capi_linux_386.go
│ │ │ ├── capi_linux_amd64.go
│ │ │ ├── capi_linux_arm.go
│ │ │ ├── capi_linux_arm64.go
│ │ │ ├── capi_linux_loong64.go
│ │ │ ├── capi_linux_mips64le.go
│ │ │ ├── capi_linux_ppc64le.go
│ │ │ ├── capi_linux_riscv64.go
│ │ │ ├── capi_linux_s390x.go
│ │ │ ├── capi_netbsd_amd64.go
│ │ │ ├── capi_netbsd_arm.go
│ │ │ ├── capi_openbsd_386.go
│ │ │ ├── capi_openbsd_amd64.go
│ │ │ ├── capi_openbsd_arm64.go
│ │ │ ├── in_darwin_amd64.go
│ │ │ ├── in_darwin_arm64.go
│ │ │ ├── in_freebsd_386.go
│ │ │ ├── in_freebsd_amd64.go
│ │ │ ├── in_freebsd_arm.go
│ │ │ ├── in_freebsd_arm64.go
│ │ │ ├── in_illumos_amd64.go
│ │ │ ├── in_linux_386.go
│ │ │ ├── in_linux_amd64.go
│ │ │ ├── in_linux_arm.go
│ │ │ ├── in_linux_arm64.go
│ │ │ ├── in_linux_loong64.go
│ │ │ ├── in_linux_mips64le.go
│ │ │ ├── in_linux_ppc64le.go
│ │ │ ├── in_linux_riscv64.go
│ │ │ ├── in_linux_s390x.go
│ │ │ ├── in_netbsd_amd64.go
│ │ │ ├── in_netbsd_arm.go
│ │ │ ├── in_openbsd_386.go
│ │ │ ├── in_openbsd_amd64.go
│ │ │ └── in_openbsd_arm64.go
│ │ ├── nodmesg.go
│ │ ├── nofsync.go
│ │ ├── poll/
│ │ │ ├── capi_darwin_amd64.go
│ │ │ ├── capi_darwin_arm64.go
│ │ │ ├── capi_freebsd_386.go
│ │ │ ├── capi_freebsd_amd64.go
│ │ │ ├── capi_freebsd_arm.go
│ │ │ ├── capi_freebsd_arm64.go
│ │ │ ├── capi_illumos_amd64.go
│ │ │ ├── capi_linux_386.go
│ │ │ ├── capi_linux_amd64.go
│ │ │ ├── capi_linux_arm.go
│ │ │ ├── capi_linux_arm64.go
│ │ │ ├── capi_linux_loong64.go
│ │ │ ├── capi_linux_mips64le.go
│ │ │ ├── capi_linux_ppc64le.go
│ │ │ ├── capi_linux_riscv64.go
│ │ │ ├── capi_linux_s390x.go
│ │ │ ├── capi_netbsd_amd64.go
│ │ │ ├── capi_netbsd_arm.go
│ │ │ ├── capi_openbsd_386.go
│ │ │ ├── capi_openbsd_amd64.go
│ │ │ ├── capi_openbsd_arm64.go
│ │ │ ├── poll_darwin_amd64.go
│ │ │ ├── poll_darwin_arm64.go
│ │ │ ├── poll_freebsd_386.go
│ │ │ ├── poll_freebsd_amd64.go
│ │ │ ├── poll_freebsd_arm.go
│ │ │ ├── poll_freebsd_arm64.go
│ │ │ ├── poll_illumos_amd64.go
│ │ │ ├── poll_linux_386.go
│ │ │ ├── poll_linux_amd64.go
│ │ │ ├── poll_linux_arm.go
│ │ │ ├── poll_linux_arm64.go
│ │ │ ├── poll_linux_loong64.go
│ │ │ ├── poll_linux_mips64le.go
│ │ │ ├── poll_linux_ppc64le.go
│ │ │ ├── poll_linux_riscv64.go
│ │ │ ├── poll_linux_s390x.go
│ │ │ ├── poll_netbsd_amd64.go
│ │ │ ├── poll_netbsd_arm.go
│ │ │ ├── poll_openbsd_386.go
│ │ │ ├── poll_openbsd_amd64.go
│ │ │ └── poll_openbsd_arm64.go
│ │ ├── printf.go
│ │ ├── probes.go
│ │ ├── pthread/
│ │ │ ├── capi_darwin_amd64.go
│ │ │ ├── capi_darwin_arm64.go
│ │ │ ├── capi_freebsd_386.go
│ │ │ ├── capi_freebsd_amd64.go
│ │ │ ├── capi_freebsd_arm.go
│ │ │ ├── capi_freebsd_arm64.go
│ │ │ ├── capi_illumos_amd64.go
│ │ │ ├── capi_linux_386.go
│ │ │ ├── capi_linux_amd64.go
│ │ │ ├── capi_linux_arm.go
│ │ │ ├── capi_linux_arm64.go
│ │ │ ├── capi_linux_loong64.go
│ │ │ ├── capi_linux_mips64le.go
│ │ │ ├── capi_linux_ppc64le.go
│ │ │ ├── capi_linux_riscv64.go
│ │ │ ├── capi_linux_s390x.go
│ │ │ ├── capi_netbsd_amd64.go
│ │ │ ├── capi_netbsd_arm.go
│ │ │ ├── capi_openbsd_386.go
│ │ │ ├── capi_openbsd_amd64.go
│ │ │ ├── capi_openbsd_arm64.go
│ │ │ ├── capi_windows_386.go
│ │ │ ├── capi_windows_amd64.go
│ │ │ ├── capi_windows_arm64.go
│ │ │ ├── pthread_darwin_amd64.go
│ │ │ ├── pthread_darwin_arm64.go
│ │ │ ├── pthread_freebsd_386.go
│ │ │ ├── pthread_freebsd_amd64.go
│ │ │ ├── pthread_freebsd_arm.go
│ │ │ ├── pthread_freebsd_arm64.go
│ │ │ ├── pthread_illumos_amd64.go
│ │ │ ├── pthread_linux_386.go
│ │ │ ├── pthread_linux_amd64.go
│ │ │ ├── pthread_linux_arm.go
│ │ │ ├── pthread_linux_arm64.go
│ │ │ ├── pthread_linux_loong64.go
│ │ │ ├── pthread_linux_mips64le.go
│ │ │ ├── pthread_linux_ppc64le.go
│ │ │ ├── pthread_linux_riscv64.go
│ │ │ ├── pthread_linux_s390x.go
│ │ │ ├── pthread_netbsd_amd64.go
│ │ │ ├── pthread_netbsd_arm.go
│ │ │ ├── pthread_openbsd_386.go
│ │ │ ├── pthread_openbsd_amd64.go
│ │ │ ├── pthread_openbsd_arm64.go
│ │ │ ├── pthread_windows_386.go
│ │ │ ├── pthread_windows_amd64.go
│ │ │ └── pthread_windows_arm64.go
│ │ ├── pthread.go
│ │ ├── pthread_all.go
│ │ ├── pthread_musl.go
│ │ ├── pwd/
│ │ │ ├── capi_darwin_amd64.go
│ │ │ ├── capi_darwin_arm64.go
│ │ │ ├── capi_freebsd_386.go
│ │ │ ├── capi_freebsd_amd64.go
│ │ │ ├── capi_freebsd_arm.go
│ │ │ ├── capi_freebsd_arm64.go
│ │ │ ├── capi_illumos_amd64.go
│ │ │ ├── capi_linux_386.go
│ │ │ ├── capi_linux_amd64.go
│ │ │ ├── capi_linux_arm.go
│ │ │ ├── capi_linux_arm64.go
│ │ │ ├── capi_linux_loong64.go
│ │ │ ├── capi_linux_mips64le.go
│ │ │ ├── capi_linux_ppc64le.go
│ │ │ ├── capi_linux_riscv64.go
│ │ │ ├── capi_linux_s390x.go
│ │ │ ├── capi_netbsd_amd64.go
│ │ │ ├── capi_netbsd_arm.go
│ │ │ ├── capi_openbsd_386.go
│ │ │ ├── capi_openbsd_amd64.go
│ │ │ ├── capi_openbsd_arm64.go
│ │ │ ├── pwd_darwin_amd64.go
│ │ │ ├── pwd_darwin_arm64.go
│ │ │ ├── pwd_freebsd_386.go
│ │ │ ├── pwd_freebsd_amd64.go
│ │ │ ├── pwd_freebsd_arm.go
│ │ │ ├── pwd_freebsd_arm64.go
│ │ │ ├── pwd_illumos_amd64.go
│ │ │ ├── pwd_linux_386.go
│ │ │ ├── pwd_linux_amd64.go
│ │ │ ├── pwd_linux_arm.go
│ │ │ ├── pwd_linux_arm64.go
│ │ │ ├── pwd_linux_loong64.go
│ │ │ ├── pwd_linux_mips64le.go
│ │ │ ├── pwd_linux_ppc64le.go
│ │ │ ├── pwd_linux_riscv64.go
│ │ │ ├── pwd_linux_s390x.go
│ │ │ ├── pwd_netbsd_amd64.go
│ │ │ ├── pwd_netbsd_arm.go
│ │ │ ├── pwd_openbsd_386.go
│ │ │ ├── pwd_openbsd_amd64.go
│ │ │ └── pwd_openbsd_arm64.go
│ │ ├── rtl.go
│ │ ├── scanf.go
│ │ ├── signal/
│ │ │ ├── capi_darwin_amd64.go
│ │ │ ├── capi_darwin_arm64.go
│ │ │ ├── capi_freebsd_386.go
│ │ │ ├── capi_freebsd_amd64.go
│ │ │ ├── capi_freebsd_arm.go
│ │ │ ├── capi_freebsd_arm64.go
│ │ │ ├── capi_illumos_amd64.go
│ │ │ ├── capi_linux_386.go
│ │ │ ├── capi_linux_amd64.go
│ │ │ ├── capi_linux_arm.go
│ │ │ ├── capi_linux_arm64.go
│ │ │ ├── capi_linux_loong64.go
│ │ │ ├── capi_linux_mips64le.go
│ │ │ ├── capi_linux_ppc64le.go
│ │ │ ├── capi_linux_riscv64.go
│ │ │ ├── capi_linux_s390x.go
│ │ │ ├── capi_netbsd_amd64.go
│ │ │ ├── capi_netbsd_arm.go
│ │ │ ├── capi_openbsd_386.go
│ │ │ ├── capi_openbsd_amd64.go
│ │ │ ├── capi_openbsd_arm64.go
│ │ │ ├── capi_windows_386.go
│ │ │ ├── capi_windows_amd64.go
│ │ │ ├── capi_windows_arm64.go
│ │ │ ├── more_darwin_amd64.go
│ │ │ ├── more_darwin_arm64.go
│ │ │ ├── more_freebsd_386.go
│ │ │ ├── more_freebsd_amd64.go
│ │ │ ├── more_freebsd_arm.go
│ │ │ ├── more_freebsd_arm64.go
│ │ │ ├── more_illumos_amd64.go
│ │ │ ├── more_linux_386.go
│ │ │ ├── more_linux_amd64.go
│ │ │ ├── more_linux_arm.go
│ │ │ ├── more_linux_arm64.go
│ │ │ ├── more_linux_loong64.go
│ │ │ ├── more_linux_mips64le.go
│ │ │ ├── more_linux_ppc64le.go
│ │ │ ├── more_linux_riscv64.go
│ │ │ ├── more_linux_s390x.go
│ │ │ ├── more_netbsd_amd64.go
│ │ │ ├── more_netbsd_arm.go
│ │ │ ├── more_openbsd_386.go
│ │ │ ├── more_openbsd_amd64.go
│ │ │ ├── more_openbsd_arm64.go
│ │ │ ├── signal_darwin_amd64.go
│ │ │ ├── signal_darwin_arm64.go
│ │ │ ├── signal_freebsd_386.go
│ │ │ ├── signal_freebsd_amd64.go
│ │ │ ├── signal_freebsd_arm.go
│ │ │ ├── signal_freebsd_arm64.go
│ │ │ ├── signal_illumos_amd64.go
│ │ │ ├── signal_linux_386.go
│ │ │ ├── signal_linux_amd64.go
│ │ │ ├── signal_linux_arm.go
│ │ │ ├── signal_linux_arm64.go
│ │ │ ├── signal_linux_loong64.go
│ │ │ ├── signal_linux_mips64le.go
│ │ │ ├── signal_linux_ppc64le.go
│ │ │ ├── signal_linux_riscv64.go
│ │ │ ├── signal_linux_s390x.go
│ │ │ ├── signal_netbsd_amd64.go
│ │ │ ├── signal_netbsd_arm.go
│ │ │ ├── signal_openbsd_386.go
│ │ │ ├── signal_openbsd_amd64.go
│ │ │ ├── signal_openbsd_arm64.go
│ │ │ ├── signal_windows_386.go
│ │ │ ├── signal_windows_amd64.go
│ │ │ └── signal_windows_arm64.go
│ │ ├── stdatomic.go
│ │ ├── stdio/
│ │ │ ├── capi_darwin_amd64.go
│ │ │ ├── capi_darwin_arm64.go
│ │ │ ├── capi_freebsd_386.go
│ │ │ ├── capi_freebsd_amd64.go
│ │ │ ├── capi_freebsd_arm.go
│ │ │ ├── capi_freebsd_arm64.go
│ │ │ ├── capi_illumos_amd64.go
│ │ │ ├── capi_linux_386.go
│ │ │ ├── capi_linux_amd64.go
│ │ │ ├── capi_linux_arm.go
│ │ │ ├── capi_linux_arm64.go
│ │ │ ├── capi_linux_loong64.go
│ │ │ ├── capi_linux_mips64le.go
│ │ │ ├── capi_linux_ppc64le.go
│ │ │ ├── capi_linux_riscv64.go
│ │ │ ├── capi_linux_s390x.go
│ │ │ ├── capi_netbsd_amd64.go
│ │ │ ├── capi_netbsd_arm.go
│ │ │ ├── capi_openbsd_386.go
│ │ │ ├── capi_openbsd_amd64.go
│ │ │ ├── capi_openbsd_arm64.go
│ │ │ ├── capi_windows_386.go
│ │ │ ├── capi_windows_amd64.go
│ │ │ ├── capi_windows_arm64.go
│ │ │ ├── stdio_darwin_amd64.go
│ │ │ ├── stdio_darwin_arm64.go
│ │ │ ├── stdio_freebsd_386.go
│ │ │ ├── stdio_freebsd_amd64.go
│ │ │ ├── stdio_freebsd_arm.go
│ │ │ ├── stdio_freebsd_arm64.go
│ │ │ ├── stdio_illumos_amd64.go
│ │ │ ├── stdio_linux_386.go
│ │ │ ├── stdio_linux_amd64.go
│ │ │ ├── stdio_linux_arm.go
│ │ │ ├── stdio_linux_arm64.go
│ │ │ ├── stdio_linux_loong64.go
│ │ │ ├── stdio_linux_mips64le.go
│ │ │ ├── stdio_linux_ppc64le.go
│ │ │ ├── stdio_linux_riscv64.go
│ │ │ ├── stdio_linux_s390x.go
│ │ │ ├── stdio_netbsd_amd64.go
│ │ │ ├── stdio_netbsd_arm.go
│ │ │ ├── stdio_openbsd_386.go
│ │ │ ├── stdio_openbsd_amd64.go
│ │ │ ├── stdio_openbsd_arm64.go
│ │ │ ├── stdio_windows_386.go
│ │ │ ├── stdio_windows_amd64.go
│ │ │ └── stdio_windows_arm64.go
│ │ ├── stdlib/
│ │ │ ├── capi_darwin_amd64.go
│ │ │ ├── capi_darwin_arm64.go
│ │ │ ├── capi_freebsd_386.go
│ │ │ ├── capi_freebsd_amd64.go
│ │ │ ├── capi_freebsd_arm.go
│ │ │ ├── capi_freebsd_arm64.go
│ │ │ ├── capi_illumos_amd64.go
│ │ │ ├── capi_linux_386.go
│ │ │ ├── capi_linux_amd64.go
│ │ │ ├── capi_linux_arm.go
│ │ │ ├── capi_linux_arm64.go
│ │ │ ├── capi_linux_loong64.go
│ │ │ ├── capi_linux_mips64le.go
│ │ │ ├── capi_linux_ppc64le.go
│ │ │ ├── capi_linux_riscv64.go
│ │ │ ├── capi_linux_s390x.go
│ │ │ ├── capi_netbsd_amd64.go
│ │ │ ├── capi_netbsd_arm.go
│ │ │ ├── capi_openbsd_386.go
│ │ │ ├── capi_openbsd_amd64.go
│ │ │ ├── capi_openbsd_arm64.go
│ │ │ ├── capi_windows_386.go
│ │ │ ├── capi_windows_amd64.go
│ │ │ ├── capi_windows_arm64.go
│ │ │ ├── stdlib_darwin_amd64.go
│ │ │ ├── stdlib_darwin_arm64.go
│ │ │ ├── stdlib_freebsd_386.go
│ │ │ ├── stdlib_freebsd_amd64.go
│ │ │ ├── stdlib_freebsd_arm.go
│ │ │ ├── stdlib_freebsd_arm64.go
│ │ │ ├── stdlib_illumos_amd64.go
│ │ │ ├── stdlib_linux_386.go
│ │ │ ├── stdlib_linux_amd64.go
│ │ │ ├── stdlib_linux_arm.go
│ │ │ ├── stdlib_linux_arm64.go
│ │ │ ├── stdlib_linux_loong64.go
│ │ │ ├── stdlib_linux_mips64le.go
│ │ │ ├── stdlib_linux_ppc64le.go
│ │ │ ├── stdlib_linux_riscv64.go
│ │ │ ├── stdlib_linux_s390x.go
│ │ │ ├── stdlib_netbsd_amd64.go
│ │ │ ├── stdlib_netbsd_arm.go
│ │ │ ├── stdlib_openbsd_386.go
│ │ │ ├── stdlib_openbsd_amd64.go
│ │ │ ├── stdlib_openbsd_arm64.go
│ │ │ ├── stdlib_windows_386.go
│ │ │ ├── stdlib_windows_amd64.go
│ │ │ └── stdlib_windows_arm64.go
│ │ ├── straceoff.go
│ │ ├── straceon.go
│ │ ├── surface.new
│ │ ├── surface.old
│ │ ├── sync.go
│ │ ├── sys/
│ │ │ ├── socket/
│ │ │ │ ├── capi_darwin_amd64.go
│ │ │ │ ├── capi_darwin_arm64.go
│ │ │ │ ├── capi_freebsd_386.go
│ │ │ │ ├── capi_freebsd_amd64.go
│ │ │ │ ├── capi_freebsd_arm.go
│ │ │ │ ├── capi_freebsd_arm64.go
│ │ │ │ ├── capi_illumos_amd64.go
│ │ │ │ ├── capi_linux_386.go
│ │ │ │ ├── capi_linux_amd64.go
│ │ │ │ ├── capi_linux_arm.go
│ │ │ │ ├── capi_linux_arm64.go
│ │ │ │ ├── capi_linux_loong64.go
│ │ │ │ ├── capi_linux_mips64le.go
│ │ │ │ ├── capi_linux_ppc64le.go
│ │ │ │ ├── capi_linux_riscv64.go
│ │ │ │ ├── capi_linux_s390x.go
│ │ │ │ ├── capi_netbsd_amd64.go
│ │ │ │ ├── capi_netbsd_arm.go
│ │ │ │ ├── capi_openbsd_386.go
│ │ │ │ ├── capi_openbsd_amd64.go
│ │ │ │ ├── capi_openbsd_arm64.go
│ │ │ │ ├── socket_darwin_amd64.go
│ │ │ │ ├── socket_darwin_arm64.go
│ │ │ │ ├── socket_freebsd_386.go
│ │ │ │ ├── socket_freebsd_amd64.go
│ │ │ │ ├── socket_freebsd_arm.go
│ │ │ │ ├── socket_freebsd_arm64.go
│ │ │ │ ├── socket_illumos_amd64.go
│ │ │ │ ├── socket_linux_386.go
│ │ │ │ ├── socket_linux_amd64.go
│ │ │ │ ├── socket_linux_arm.go
│ │ │ │ ├── socket_linux_arm64.go
│ │ │ │ ├── socket_linux_loong64.go
│ │ │ │ ├── socket_linux_mips64le.go
│ │ │ │ ├── socket_linux_ppc64le.go
│ │ │ │ ├── socket_linux_riscv64.go
│ │ │ │ ├── socket_linux_s390x.go
│ │ │ │ ├── socket_netbsd_amd64.go
│ │ │ │ ├── socket_netbsd_arm.go
│ │ │ │ ├── socket_openbsd_386.go
│ │ │ │ ├── socket_openbsd_amd64.go
│ │ │ │ └── socket_openbsd_arm64.go
│ │ │ ├── stat/
│ │ │ │ ├── capi_darwin_amd64.go
│ │ │ │ ├── capi_darwin_arm64.go
│ │ │ │ ├── capi_freebsd_386.go
│ │ │ │ ├── capi_freebsd_amd64.go
│ │ │ │ ├── capi_freebsd_arm.go
│ │ │ │ ├── capi_freebsd_arm64.go
│ │ │ │ ├── capi_illumos_amd64.go
│ │ │ │ ├── capi_linux_386.go
│ │ │ │ ├── capi_linux_amd64.go
│ │ │ │ ├── capi_linux_arm.go
│ │ │ │ ├── capi_linux_arm64.go
│ │ │ │ ├── capi_linux_loong64.go
│ │ │ │ ├── capi_linux_mips64le.go
│ │ │ │ ├── capi_linux_ppc64le.go
│ │ │ │ ├── capi_linux_riscv64.go
│ │ │ │ ├── capi_linux_s390x.go
│ │ │ │ ├── capi_netbsd_amd64.go
│ │ │ │ ├── capi_netbsd_arm.go
│ │ │ │ ├── capi_openbsd_386.go
│ │ │ │ ├── capi_openbsd_amd64.go
│ │ │ │ ├── capi_openbsd_arm64.go
│ │ │ │ ├── capi_windows_386.go
│ │ │ │ ├── capi_windows_amd64.go
│ │ │ │ ├── capi_windows_arm64.go
│ │ │ │ ├── stat_darwin_amd64.go
│ │ │ │ ├── stat_darwin_arm64.go
│ │ │ │ ├── stat_freebsd_386.go
│ │ │ │ ├── stat_freebsd_amd64.go
│ │ │ │ ├── stat_freebsd_arm.go
│ │ │ │ ├── stat_freebsd_arm64.go
│ │ │ │ ├── stat_illumos_amd64.go
│ │ │ │ ├── stat_linux_386.go
│ │ │ │ ├── stat_linux_amd64.go
│ │ │ │ ├── stat_linux_arm.go
│ │ │ │ ├── stat_linux_arm64.go
│ │ │ │ ├── stat_linux_loong64.go
│ │ │ │ ├── stat_linux_mips64le.go
│ │ │ │ ├── stat_linux_ppc64le.go
│ │ │ │ ├── stat_linux_riscv64.go
│ │ │ │ ├── stat_linux_s390x.go
│ │ │ │ ├── stat_netbsd_amd64.go
│ │ │ │ ├── stat_netbsd_arm.go
│ │ │ │ ├── stat_openbsd_386.go
│ │ │ │ ├── stat_openbsd_amd64.go
│ │ │ │ ├── stat_openbsd_arm64.go
│ │ │ │ ├── stat_windows_386.go
│ │ │ │ ├── stat_windows_amd64.go
│ │ │ │ └── stat_windows_arm64.go
│ │ │ └── types/
│ │ │ ├── capi_darwin_amd64.go
│ │ │ ├── capi_darwin_arm64.go
│ │ │ ├── capi_freebsd_386.go
│ │ │ ├── capi_freebsd_amd64.go
│ │ │ ├── capi_freebsd_arm.go
│ │ │ ├── capi_freebsd_arm64.go
│ │ │ ├── capi_illumos_amd64.go
│ │ │ ├── capi_linux_386.go
│ │ │ ├── capi_linux_amd64.go
│ │ │ ├── capi_linux_arm.go
│ │ │ ├── capi_linux_arm64.go
│ │ │ ├── capi_linux_loong64.go
│ │ │ ├── capi_linux_mips64le.go
│ │ │ ├── capi_linux_ppc64le.go
│ │ │ ├── capi_linux_riscv64.go
│ │ │ ├── capi_linux_s390x.go
│ │ │ ├── capi_netbsd_amd64.go
│ │ │ ├── capi_netbsd_arm.go
│ │ │ ├── capi_openbsd_386.go
│ │ │ ├── capi_openbsd_amd64.go
│ │ │ ├── capi_openbsd_arm64.go
│ │ │ ├── capi_windows_386.go
│ │ │ ├── capi_windows_amd64.go
│ │ │ ├── capi_windows_arm64.go
│ │ │ ├── types_darwin_amd64.go
│ │ │ ├── types_darwin_arm64.go
│ │ │ ├── types_freebsd_386.go
│ │ │ ├── types_freebsd_amd64.go
│ │ │ ├── types_freebsd_arm.go
│ │ │ ├── types_freebsd_arm64.go
│ │ │ ├── types_illumos_amd64.go
│ │ │ ├── types_linux_386.go
│ │ │ ├── types_linux_amd64.go
│ │ │ ├── types_linux_arm.go
│ │ │ ├── types_linux_arm64.go
│ │ │ ├── types_linux_loong64.go
│ │ │ ├── types_linux_mips64le.go
│ │ │ ├── types_linux_ppc64le.go
│ │ │ ├── types_linux_riscv64.go
│ │ │ ├── types_linux_s390x.go
│ │ │ ├── types_netbsd_amd64.go
│ │ │ ├── types_netbsd_arm.go
│ │ │ ├── types_openbsd_386.go
│ │ │ ├── types_openbsd_amd64.go
│ │ │ ├── types_openbsd_arm64.go
│ │ │ ├── types_windows_386.go
│ │ │ ├── types_windows_amd64.go
│ │ │ └── types_windows_arm64.go
│ │ ├── syscall_musl.go
│ │ ├── termios/
│ │ │ ├── capi_darwin_amd64.go
│ │ │ ├── capi_darwin_arm64.go
│ │ │ ├── capi_freebsd_386.go
│ │ │ ├── capi_freebsd_amd64.go
│ │ │ ├── capi_freebsd_arm.go
│ │ │ ├── capi_freebsd_arm64.go
│ │ │ ├── capi_illumos_amd64.go
│ │ │ ├── capi_linux_386.go
│ │ │ ├── capi_linux_amd64.go
│ │ │ ├── capi_linux_arm.go
│ │ │ ├── capi_linux_arm64.go
│ │ │ ├── capi_linux_loong64.go
│ │ │ ├── capi_linux_mips64le.go
│ │ │ ├── capi_linux_ppc64le.go
│ │ │ ├── capi_linux_riscv64.go
│ │ │ ├── capi_linux_s390x.go
│ │ │ ├── capi_netbsd_amd64.go
│ │ │ ├── capi_netbsd_arm.go
│ │ │ ├── capi_openbsd_386.go
│ │ │ ├── capi_openbsd_amd64.go
│ │ │ ├── capi_openbsd_arm64.go
│ │ │ ├── termios_darwin_amd64.go
│ │ │ ├── termios_darwin_arm64.go
│ │ │ ├── termios_freebsd_386.go
│ │ │ ├── termios_freebsd_amd64.go
│ │ │ ├── termios_freebsd_arm.go
│ │ │ ├── termios_freebsd_arm64.go
│ │ │ ├── termios_illumos_amd64.go
│ │ │ ├── termios_linux_386.go
│ │ │ ├── termios_linux_amd64.go
│ │ │ ├── termios_linux_arm.go
│ │ │ ├── termios_linux_arm64.go
│ │ │ ├── termios_linux_loong64.go
│ │ │ ├── termios_linux_mips64le.go
│ │ │ ├── termios_linux_ppc64le.go
│ │ │ ├── termios_linux_riscv64.go
│ │ │ ├── termios_linux_s390x.go
│ │ │ ├── termios_netbsd_amd64.go
│ │ │ ├── termios_netbsd_arm.go
│ │ │ ├── termios_openbsd_386.go
│ │ │ ├── termios_openbsd_amd64.go
│ │ │ └── termios_openbsd_arm64.go
│ │ ├── time/
│ │ │ ├── capi_darwin_amd64.go
│ │ │ ├── capi_darwin_arm64.go
│ │ │ ├── capi_freebsd_386.go
│ │ │ ├── capi_freebsd_amd64.go
│ │ │ ├── capi_freebsd_arm.go
│ │ │ ├── capi_freebsd_arm64.go
│ │ │ ├── capi_illumos_amd64.go
│ │ │ ├── capi_linux_386.go
│ │ │ ├── capi_linux_amd64.go
│ │ │ ├── capi_linux_arm.go
│ │ │ ├── capi_linux_arm64.go
│ │ │ ├── capi_linux_loong64.go
│ │ │ ├── capi_linux_mips64le.go
│ │ │ ├── capi_linux_ppc64le.go
│ │ │ ├── capi_linux_riscv64.go
│ │ │ ├── capi_linux_s390x.go
│ │ │ ├── capi_netbsd_amd64.go
│ │ │ ├── capi_netbsd_arm.go
│ │ │ ├── capi_openbsd_386.go
│ │ │ ├── capi_openbsd_amd64.go
│ │ │ ├── capi_openbsd_arm64.go
│ │ │ ├── capi_windows_386.go
│ │ │ ├── capi_windows_amd64.go
│ │ │ ├── capi_windows_arm64.go
│ │ │ ├── time_darwin_amd64.go
│ │ │ ├── time_darwin_arm64.go
│ │ │ ├── time_freebsd_386.go
│ │ │ ├── time_freebsd_amd64.go
│ │ │ ├── time_freebsd_arm.go
│ │ │ ├── time_freebsd_arm64.go
│ │ │ ├── time_illumos_amd64.go
│ │ │ ├── time_linux_386.go
│ │ │ ├── time_linux_amd64.go
│ │ │ ├── time_linux_arm.go
│ │ │ ├── time_linux_arm64.go
│ │ │ ├── time_linux_loong64.go
│ │ │ ├── time_linux_mips64le.go
│ │ │ ├── time_linux_ppc64le.go
│ │ │ ├── time_linux_riscv64.go
│ │ │ ├── time_linux_s390x.go
│ │ │ ├── time_netbsd_amd64.go
│ │ │ ├── time_netbsd_arm.go
│ │ │ ├── time_openbsd_386.go
│ │ │ ├── time_openbsd_amd64.go
│ │ │ ├── time_openbsd_arm64.go
│ │ │ ├── time_windows_386.go
│ │ │ ├── time_windows_amd64.go
│ │ │ └── time_windows_arm64.go
│ │ ├── tls_linux_amd64.go
│ │ ├── tls_linux_amd64.s
│ │ ├── unistd/
│ │ │ ├── capi_darwin_amd64.go
│ │ │ ├── capi_darwin_arm64.go
│ │ │ ├── capi_freebsd_386.go
│ │ │ ├── capi_freebsd_amd64.go
│ │ │ ├── capi_freebsd_arm.go
│ │ │ ├── capi_freebsd_arm64.go
│ │ │ ├── capi_illumos_amd64.go
│ │ │ ├── capi_linux_386.go
│ │ │ ├── capi_linux_amd64.go
│ │ │ ├── capi_linux_arm.go
│ │ │ ├── capi_linux_arm64.go
│ │ │ ├── capi_linux_loong64.go
│ │ │ ├── capi_linux_mips64le.go
│ │ │ ├── capi_linux_ppc64le.go
│ │ │ ├── capi_linux_riscv64.go
│ │ │ ├── capi_linux_s390x.go
│ │ │ ├── capi_netbsd_amd64.go
│ │ │ ├── capi_netbsd_arm.go
│ │ │ ├── capi_openbsd_386.go
│ │ │ ├── capi_openbsd_amd64.go
│ │ │ ├── capi_openbsd_arm64.go
│ │ │ ├── capi_windows_386.go
│ │ │ ├── capi_windows_amd64.go
│ │ │ ├── capi_windows_arm64.go
│ │ │ ├── unistd_darwin_amd64.go
│ │ │ ├── unistd_darwin_arm64.go
│ │ │ ├── unistd_freebsd_386.go
│ │ │ ├── unistd_freebsd_amd64.go
│ │ │ ├── unistd_freebsd_arm.go
│ │ │ ├── unistd_freebsd_arm64.go
│ │ │ ├── unistd_illumos_amd64.go
│ │ │ ├── unistd_linux_386.go
│ │ │ ├── unistd_linux_amd64.go
│ │ │ ├── unistd_linux_arm.go
│ │ │ ├── unistd_linux_arm64.go
│ │ │ ├── unistd_linux_loong64.go
│ │ │ ├── unistd_linux_mips64le.go
│ │ │ ├── unistd_linux_ppc64le.go
│ │ │ ├── unistd_linux_riscv64.go
│ │ │ ├── unistd_linux_s390x.go
│ │ │ ├── unistd_netbsd_amd64.go
│ │ │ ├── unistd_netbsd_arm.go
│ │ │ ├── unistd_openbsd_386.go
│ │ │ ├── unistd_openbsd_amd64.go
│ │ │ ├── unistd_openbsd_arm64.go
│ │ │ ├── unistd_windows_386.go
│ │ │ ├── unistd_windows_amd64.go
│ │ │ └── unistd_windows_arm64.go
│ │ ├── utime/
│ │ │ ├── capi_darwin_amd64.go
│ │ │ ├── capi_darwin_arm64.go
│ │ │ ├── capi_freebsd_386.go
│ │ │ ├── capi_freebsd_amd64.go
│ │ │ ├── capi_freebsd_arm.go
│ │ │ ├── capi_freebsd_arm64.go
│ │ │ ├── capi_illumos_amd64.go
│ │ │ ├── capi_linux_386.go
│ │ │ ├── capi_linux_amd64.go
│ │ │ ├── capi_linux_arm.go
│ │ │ ├── capi_linux_arm64.go
│ │ │ ├── capi_linux_loong64.go
│ │ │ ├── capi_linux_mips64le.go
│ │ │ ├── capi_linux_ppc64le.go
│ │ │ ├── capi_linux_riscv64.go
│ │ │ ├── capi_linux_s390x.go
│ │ │ ├── capi_netbsd_amd64.go
│ │ │ ├── capi_netbsd_arm.go
│ │ │ ├── capi_openbsd_386.go
│ │ │ ├── capi_openbsd_amd64.go
│ │ │ ├── capi_openbsd_arm64.go
│ │ │ ├── capi_windows_386.go
│ │ │ ├── capi_windows_amd64.go
│ │ │ ├── capi_windows_arm64.go
│ │ │ ├── utime_darwin_amd64.go
│ │ │ ├── utime_darwin_arm64.go
│ │ │ ├── utime_freebsd_386.go
│ │ │ ├── utime_freebsd_amd64.go
│ │ │ ├── utime_freebsd_arm.go
│ │ │ ├── utime_freebsd_arm64.go
│ │ │ ├── utime_illumos_amd64.go
│ │ │ ├── utime_linux_386.go
│ │ │ ├── utime_linux_amd64.go
│ │ │ ├── utime_linux_arm.go
│ │ │ ├── utime_linux_arm64.go
│ │ │ ├── utime_linux_loong64.go
│ │ │ ├── utime_linux_mips64le.go
│ │ │ ├── utime_linux_ppc64le.go
│ │ │ ├── utime_linux_riscv64.go
│ │ │ ├── utime_linux_s390x.go
│ │ │ ├── utime_netbsd_amd64.go
│ │ │ ├── utime_netbsd_arm.go
│ │ │ ├── utime_openbsd_386.go
│ │ │ ├── utime_openbsd_amd64.go
│ │ │ ├── utime_openbsd_arm64.go
│ │ │ ├── utime_windows_386.go
│ │ │ ├── utime_windows_amd64.go
│ │ │ └── utime_windows_arm64.go
│ │ ├── uuid/
│ │ │ ├── capi_freebsd_386.go
│ │ │ ├── capi_freebsd_amd64.go
│ │ │ ├── capi_freebsd_arm.go
│ │ │ ├── capi_freebsd_arm64.go
│ │ │ ├── capi_netbsd_amd64.go
│ │ │ ├── capi_netbsd_arm.go
│ │ │ ├── capi_openbsd_386.go
│ │ │ ├── capi_openbsd_amd64.go
│ │ │ ├── capi_openbsd_arm64.go
│ │ │ ├── uuid/
│ │ │ │ ├── capi_darwin_amd64.go
│ │ │ │ ├── capi_darwin_arm64.go
│ │ │ │ ├── capi_illumos_amd64.go
│ │ │ │ ├── capi_linux_386.go
│ │ │ │ ├── capi_linux_amd64.go
│ │ │ │ ├── capi_linux_arm.go
│ │ │ │ ├── capi_linux_arm64.go
│ │ │ │ ├── capi_linux_loong64.go
│ │ │ │ ├── capi_linux_mips64le.go
│ │ │ │ ├── capi_linux_ppc64le.go
│ │ │ │ ├── capi_linux_riscv64.go
│ │ │ │ ├── capi_linux_s390x.go
│ │ │ │ ├── uuid_darwin_amd64.go
│ │ │ │ ├── uuid_darwin_arm64.go
│ │ │ │ ├── uuid_illumos_amd64.go
│ │ │ │ ├── uuid_linux_386.go
│ │ │ │ ├── uuid_linux_amd64.go
│ │ │ │ ├── uuid_linux_arm.go
│ │ │ │ ├── uuid_linux_arm64.go
│ │ │ │ ├── uuid_linux_loong64.go
│ │ │ │ ├── uuid_linux_mips64le.go
│ │ │ │ ├── uuid_linux_ppc64le.go
│ │ │ │ ├── uuid_linux_riscv64.go
│ │ │ │ └── uuid_linux_s390x.go
│ │ │ ├── uuid_freebsd_386.go
│ │ │ ├── uuid_freebsd_amd64.go
│ │ │ ├── uuid_freebsd_arm.go
│ │ │ ├── uuid_freebsd_arm64.go
│ │ │ ├── uuid_netbsd_amd64.go
│ │ │ ├── uuid_netbsd_arm.go
│ │ │ ├── uuid_openbsd_386.go
│ │ │ ├── uuid_openbsd_amd64.go
│ │ │ └── uuid_openbsd_arm64.go
│ │ ├── watch.go
│ │ └── wctype/
│ │ ├── capi_darwin_amd64.go
│ │ ├── capi_darwin_arm64.go
│ │ ├── capi_freebsd_386.go
│ │ ├── capi_freebsd_amd64.go
│ │ ├── capi_freebsd_arm.go
│ │ ├── capi_freebsd_arm64.go
│ │ ├── capi_illumos_amd64.go
│ │ ├── capi_linux_386.go
│ │ ├── capi_linux_amd64.go
│ │ ├── capi_linux_arm.go
│ │ ├── capi_linux_arm64.go
│ │ ├── capi_linux_loong64.go
│ │ ├── capi_linux_mips64le.go
│ │ ├── capi_linux_ppc64le.go
│ │ ├── capi_linux_riscv64.go
│ │ ├── capi_linux_s390x.go
│ │ ├── capi_netbsd_amd64.go
│ │ ├── capi_netbsd_arm.go
│ │ ├── capi_openbsd_386.go
│ │ ├── capi_openbsd_amd64.go
│ │ ├── capi_openbsd_arm64.go
│ │ ├── capi_windows_386.go
│ │ ├── capi_windows_amd64.go
│ │ ├── capi_windows_arm64.go
│ │ ├── wctype_darwin_amd64.go
│ │ ├── wctype_darwin_arm64.go
│ │ ├── wctype_freebsd_386.go
│ │ ├── wctype_freebsd_amd64.go
│ │ ├── wctype_freebsd_arm.go
│ │ ├── wctype_freebsd_arm64.go
│ │ ├── wctype_illumos_amd64.go
│ │ ├── wctype_linux_386.go
│ │ ├── wctype_linux_amd64.go
│ │ ├── wctype_linux_arm.go
│ │ ├── wctype_linux_arm64.go
│ │ ├── wctype_linux_loong64.go
│ │ ├── wctype_linux_mips64le.go
│ │ ├── wctype_linux_ppc64le.go
│ │ ├── wctype_linux_riscv64.go
│ │ ├── wctype_linux_s390x.go
│ │ ├── wctype_netbsd_amd64.go
│ │ ├── wctype_netbsd_arm.go
│ │ ├── wctype_openbsd_386.go
│ │ ├── wctype_openbsd_amd64.go
│ │ ├── wctype_openbsd_arm64.go
│ │ ├── wctype_windows_386.go
│ │ ├── wctype_windows_amd64.go
│ │ └── wctype_windows_arm64.go
│ ├── mathutil/
│ │ ├── AUTHORS
│ │ ├── CONTRIBUTORS
│ │ ├── LICENSE
│ │ ├── Makefile
│ │ ├── README
│ │ ├── binarylog.go
│ │ ├── bits.go
│ │ ├── builder.json
│ │ ├── envelope.go
│ │ ├── int.go
│ │ ├── mathutil.go
│ │ ├── nist-sts-2-1-1-report
│ │ ├── permute.go
│ │ ├── poly.go
│ │ ├── primes.go
│ │ ├── rat.go
│ │ ├── rnd.go
│ │ ├── sqr.go
│ │ ├── sqr_std.go
│ │ ├── tables.go
│ │ └── test_deps.go
│ ├── memory/
│ │ ├── AUTHORS
│ │ ├── CONTRIBUTORS
│ │ ├── LICENSE
│ │ ├── LICENSE-GO
│ │ ├── LICENSE-LOGO
│ │ ├── LICENSE-MMAP-GO
│ │ ├── Makefile
│ │ ├── README.md
│ │ ├── builder.json
│ │ ├── counters.go
│ │ ├── memory.go
│ │ ├── memory32.go
│ │ ├── memory64.go
│ │ ├── mmap_unix.go
│ │ ├── mmap_windows.go
│ │ ├── nocounters.go
│ │ ├── trace_disabled.go
│ │ └── trace_enabled.go
│ └── sqlite/
│ ├── AUTHORS
│ ├── CHANGELOG.md
│ ├── CONTRIBUTORS
│ ├── GOVERNANCE.md
│ ├── HACKING.md
│ ├── LICENSE
│ ├── Makefile
│ ├── README.md
│ ├── SQLITE-LICENSE
│ ├── backup.go
│ ├── builder.json
│ ├── conn.go
│ ├── convert.go
│ ├── dmesg.go
│ ├── doc.go
│ ├── driver.go
│ ├── error.go
│ ├── fcntl.go
│ ├── issue120.diff
│ ├── lib/
│ │ ├── defs.go
│ │ ├── hooks.go
│ │ ├── hooks_linux_arm64.go
│ │ ├── mutex.go
│ │ ├── sqlite_darwin_amd64.go
│ │ ├── sqlite_darwin_arm64.go
│ │ ├── sqlite_freebsd_386.go
│ │ ├── sqlite_freebsd_amd64.go
│ │ ├── sqlite_freebsd_arm.go
│ │ ├── sqlite_freebsd_arm64.go
│ │ ├── sqlite_linux_386.go
│ │ ├── sqlite_linux_amd64.go
│ │ ├── sqlite_linux_arm.go
│ │ ├── sqlite_linux_arm64.go
│ │ ├── sqlite_linux_loong64.go
│ │ ├── sqlite_linux_ppc64le.go
│ │ ├── sqlite_linux_riscv64.go
│ │ ├── sqlite_linux_s390x.go
│ │ ├── sqlite_netbsd_amd64.go
│ │ ├── sqlite_openbsd_amd64.go
│ │ ├── sqlite_openbsd_arm64.go
│ │ ├── sqlite_windows.go
│ │ └── sqlite_windows_386.go
│ ├── mutex.go
│ ├── nodmesg.go
│ ├── norlimit.go
│ ├── pre_update_hook.go
│ ├── result.go
│ ├── rlimit.go
│ ├── rows.go
│ ├── rulimit.go
│ ├── sqlite.go
│ ├── stmt.go
│ ├── tpch.sh
│ ├── tx.go
│ ├── unconvert.sh
│ ├── vtab/
│ │ ├── doc.go
│ │ └── vtab.go
│ └── vtab.go
└── modules.txt
Copy disabled (too large)
Download .txt
Showing preview only (22,702K chars total). Download the full file to get everything.
SYMBOL INDEX (290148 symbols across 1271 files)
FILE: app/email/email.go
type Request (line 23) | type Request struct
type Notifier (line 33) | type Notifier interface
type Config (line 38) | type Config struct
type Sender (line 57) | type Sender struct
method Send (line 132) | func (s *Sender) Send(ctx context.Context, req Request) error {
method renderBody (line 148) | func (s *Sender) renderBody(link, fromName string) (string, error) {
method buildFromAddress (line 170) | func (s *Sender) buildFromAddress(displayName string) string {
method extractEmail (line 184) | func (s *Sender) extractEmail(from string) string {
method computeDefaultFromName (line 194) | func (s *Sender) computeDefaultFromName() string {
method GetDefaultFromName (line 203) | func (s *Sender) GetDefaultFromName() string {
method buildMailtoDestination (line 208) | func (s *Sender) buildMailtoDestination(recipient, subject, from strin...
function NewSender (line 68) | func NewSender(cfg Config) (*Sender, error) {
function IsValidEmail (line 226) | func IsValidEmail(email string) bool {
function MaskEmail (line 236) | func MaskEmail(email string) string {
FILE: app/email/email_test.go
function TestNewSender (line 15) | func TestNewSender(t *testing.T) {
function TestSender_renderBody (line 108) | func TestSender_renderBody(t *testing.T) {
function TestSender_extractEmail (line 128) | func TestSender_extractEmail(t *testing.T) {
function TestSender_computeDefaultFromName (line 150) | func TestSender_computeDefaultFromName(t *testing.T) {
function TestSender_buildFromAddress (line 172) | func TestSender_buildFromAddress(t *testing.T) {
function TestSender_buildMailtoDestination (line 193) | func TestSender_buildMailtoDestination(t *testing.T) {
function TestSender_GetDefaultFromName (line 210) | func TestSender_GetDefaultFromName(t *testing.T) {
function TestDefaultEmailTemplate (line 241) | func TestDefaultEmailTemplate(t *testing.T) {
function TestIsValidEmail (line 251) | func TestIsValidEmail(t *testing.T) {
function TestSender_Send (line 278) | func TestSender_Send(t *testing.T) {
function TestMaskEmail (line 389) | func TestMaskEmail(t *testing.T) {
FILE: app/email/mocks/notifier_mock.go
type NotifierMock (line 26) | type NotifierMock struct
method Send (line 46) | func (mock *NotifierMock) Send(ctx context.Context, destination string...
method SendCalls (line 69) | func (mock *NotifierMock) SendCalls() []struct {
FILE: app/main.go
function main (line 66) | func main() {
function getEngine (line 154) | func getEngine(engineType, sqliteFile string) messager.Engine {
function setupLog (line 167) | func setupLog(dbg bool) {
FILE: app/messager/crypt.go
type Crypt (line 17) | type Crypt struct
method Encrypt (line 28) | func (c Crypt) Encrypt(req Request) ([]byte, error) {
method Decrypt (line 47) | func (c Crypt) Decrypt(req Request) ([]byte, error) {
type Request (line 22) | type Request struct
function MakeSignKey (line 72) | func MakeSignKey(signKey string, pinSize int) (result string) {
FILE: app/messager/crypt_mock.go
type CrypterMock (line 32) | type CrypterMock struct
method Decrypt (line 57) | func (mock *CrypterMock) Decrypt(req Request) ([]byte, error) {
method DecryptCalls (line 76) | func (mock *CrypterMock) DecryptCalls() []struct {
method Encrypt (line 89) | func (mock *CrypterMock) Encrypt(req Request) ([]byte, error) {
method EncryptCalls (line 108) | func (mock *CrypterMock) EncryptCalls() []struct {
FILE: app/messager/crypt_test.go
function TestCrypt (line 12) | func TestCrypt(t *testing.T) {
function TestMakeSignKey (line 64) | func TestMakeSignKey(t *testing.T) {
FILE: app/messager/engine_mock.go
type EngineMock (line 44) | type EngineMock struct
method Close (line 102) | func (mock *EngineMock) Close() error {
method CloseCalls (line 118) | func (mock *EngineMock) CloseCalls() []struct {
method IncErr (line 129) | func (mock *EngineMock) IncErr(ctx context.Context, key string) (int, ...
method IncErrCalls (line 150) | func (mock *EngineMock) IncErrCalls() []struct {
method Load (line 165) | func (mock *EngineMock) Load(ctx context.Context, key string) (*store....
method LoadCalls (line 186) | func (mock *EngineMock) LoadCalls() []struct {
method Remove (line 201) | func (mock *EngineMock) Remove(ctx context.Context, key string) error {
method RemoveCalls (line 222) | func (mock *EngineMock) RemoveCalls() []struct {
method Save (line 237) | func (mock *EngineMock) Save(ctx context.Context, msg *store.Message) ...
method SaveCalls (line 258) | func (mock *EngineMock) SaveCalls() []struct {
FILE: app/messager/messager.go
constant filePrefix (line 39) | filePrefix = "!!FILE!!"
type MessageProc (line 42) | type MessageProc struct
method MakeMessage (line 111) | func (p MessageProc) MakeMessage(ctx context.Context, req MsgReq) (res...
method LoadMessage (line 159) | func (p MessageProc) LoadMessage(ctx context.Context, key, pin string)...
method checkHash (line 224) | func (p MessageProc) checkHash(msg *store.Message, pin string) bool {
method makeHash (line 235) | func (p MessageProc) makeHash(pin string) (result string, err error) {
method IsFile (line 246) | func (p MessageProc) IsFile(ctx context.Context, key string) bool {
method HasPin (line 260) | func (p MessageProc) HasPin(ctx context.Context, key string) (bool, er...
method MakeFileMessage (line 272) | func (p MessageProc) MakeFileMessage(ctx context.Context, req FileRequ...
method hasControlChars (line 372) | func (p MessageProc) hasControlChars(s string) bool {
type Params (line 49) | type Params struct
type MsgReq (line 56) | type MsgReq struct
type FileRequest (line 65) | type FileRequest struct
type Crypter (line 74) | type Crypter interface
type Engine (line 80) | type Engine interface
function New (line 89) | func New(engine Engine, crypter Crypter, params Params) *MessageProc {
function IsFileMessage (line 336) | func IsFileMessage(data []byte) bool {
function ParseFileHeader (line 342) | func ParseFileHeader(data []byte) (filename, contentType string, dataSta...
FILE: app/messager/messager_test.go
function TestMessageProc_NewDefault (line 16) | func TestMessageProc_NewDefault(t *testing.T) {
function TestMessageProc_MakeMessage (line 23) | func TestMessageProc_MakeMessage(t *testing.T) {
function TestMessageProc_MakeMessage_EmptyPinAllowed (line 47) | func TestMessageProc_MakeMessage_EmptyPinAllowed(t *testing.T) {
function TestMessageProc_MakeMessage_EmptyPinRejected (line 67) | func TestMessageProc_MakeMessage_EmptyPinRejected(t *testing.T) {
function TestMessageProc_MakeMessage_Errors (line 79) | func TestMessageProc_MakeMessage_Errors(t *testing.T) {
function TestMessageProc_MakeMessage_CrypterError (line 132) | func TestMessageProc_MakeMessage_CrypterError(t *testing.T) {
function TestMessageProc_LoadMessage_Err (line 149) | func TestMessageProc_LoadMessage_Err(t *testing.T) {
function TestMessageProc_LoadMessage_ExpiredErr (line 169) | func TestMessageProc_LoadMessage_ExpiredErr(t *testing.T) {
function TestMessageProc_LoadMessage_BadPin (line 197) | func TestMessageProc_LoadMessage_BadPin(t *testing.T) {
function TestMessageProc_LoadMessage_BadPin_MaxAttempts (line 226) | func TestMessageProc_LoadMessage_BadPin_MaxAttempts(t *testing.T) {
function TestMessageProc_LoadMessage_BadPinAttempt (line 258) | func TestMessageProc_LoadMessage_BadPinAttempt(t *testing.T) {
function TestMessageProc_LoadMessage_DecryptError (line 290) | func TestMessageProc_LoadMessage_DecryptError(t *testing.T) {
function TestMessageProc_LoadMessage (line 322) | func TestMessageProc_LoadMessage(t *testing.T) {
function TestMessageProc_LoadMessage_NoPinMessage (line 357) | func TestMessageProc_LoadMessage_NoPinMessage(t *testing.T) {
function TestMessageProc_LoadMessage_NoPinMessage_WithPinProvided (line 382) | func TestMessageProc_LoadMessage_NoPinMessage_WithPinProvided(t *testing...
function TestMessageProc_HasPin (line 403) | func TestMessageProc_HasPin(t *testing.T) {
function TestMessageProc_MakeFileMessage (line 438) | func TestMessageProc_MakeFileMessage(t *testing.T) {
function TestMessageProc_LoadFileMessage (line 477) | func TestMessageProc_LoadFileMessage(t *testing.T) {
function TestMessageProc_MakeFileMessage_Errors (line 521) | func TestMessageProc_MakeFileMessage_Errors(t *testing.T) {
function TestMessageProc_MakeFileMessage_CrypterError (line 558) | func TestMessageProc_MakeFileMessage_CrypterError(t *testing.T) {
function TestMessageProc_MakeFileMessage_SaveError (line 571) | func TestMessageProc_MakeFileMessage_SaveError(t *testing.T) {
function TestMessageProc_IsFile (line 586) | func TestMessageProc_IsFile(t *testing.T) {
function TestIsFileMessage (line 620) | func TestIsFileMessage(t *testing.T) {
function TestParseFileHeader (line 640) | func TestParseFileHeader(t *testing.T) {
function TestMessageProc_MakeMessage_ClientEnc (line 672) | func TestMessageProc_MakeMessage_ClientEnc(t *testing.T) {
function TestMessageProc_MakeMessage_ServerEnc (line 694) | func TestMessageProc_MakeMessage_ServerEnc(t *testing.T) {
function TestMessageProc_LoadMessage_ClientEnc (line 714) | func TestMessageProc_LoadMessage_ClientEnc(t *testing.T) {
function TestMessageProc_LoadMessage_ServerEnc (line 745) | func TestMessageProc_LoadMessage_ServerEnc(t *testing.T) {
FILE: app/server/assets/static/js/app.js
function getConfig (line 9) | function getConfig() {
function setupAutofocusObserver (line 20) | function setupAutofocusObserver() {
function setupPopupHandlers (line 41) | function setupPopupHandlers() {
function setupNumericInputHandler (line 60) | function setupNumericInputHandler() {
function setupExpireErrorHandler (line 80) | function setupExpireErrorHandler() {
function setupCopyHandlers (line 117) | function setupCopyHandlers() {
function setupFileUploadHandlers (line 200) | function setupFileUploadHandlers() {
function switchTab (line 220) | function switchTab(mode) {
function initDragDrop (line 268) | function initDragDrop() {
function setupEncryptionHandlers (line 355) | function setupEncryptionHandlers() {
function doClientEncryption (line 431) | async function doClientEncryption(form) {
function doEncryptionWork (line 448) | async function doEncryptionWork(form) {
function handleAfterSwap (line 508) | function handleAfterSwap(evt) {
function resetEncryptionState (line 531) | function resetEncryptionState() {
function clearFormFields (line 536) | function clearFormFields() {
function showEncryptionError (line 548) | function showEncryptionError(msg) {
function setupDecryptionHandlers (line 559) | function setupDecryptionHandlers() {
function setButtonLoading (line 611) | function setButtonLoading(btn, btnText, btnLoading, isLoading) {
function showPinError (line 617) | function showPinError(pinInput, pinError, msg) {
function showErrorCard (line 624) | function showErrorCard(title, message) {
function showSuccessCard (line 632) | function showSuccessCard(title, message) {
function handleClientDecryption (line 640) | async function handleClientDecryption(cryptoKey) {
function handleFileDownload (line 720) | async function handleFileDownload() {
function formatSize (line 786) | function formatSize(bytes) {
function escapeHtml (line 792) | function escapeHtml(text) {
FILE: app/server/assets/static/js/crypto.js
constant TYPE_TEXT (line 7) | const TYPE_TEXT = 0x00;
constant TYPE_FILE (line 8) | const TYPE_FILE = 0x01;
function base64urlEncode (line 11) | function base64urlEncode(bytes) {
function base64urlDecode (line 16) | function base64urlDecode(str) {
function checkCryptoAvailable (line 28) | function checkCryptoAvailable() {
function generateKey (line 33) | async function generateKey() {
function importKey (line 40) | async function importKey(keyStr) {
function encrypt (line 54) | async function encrypt(plaintext, keyStr) {
function decrypt (line 82) | async function decrypt(ciphertextStr, keyStr) {
function encryptFile (line 116) | async function encryptFile(data, filename, contentType, keyStr) {
function decryptFile (line 172) | async function decryptFile(ciphertextStr, keyStr) {
function decryptAuto (line 235) | async function decryptAuto(ciphertextStr, keyStr) {
FILE: app/server/assets/static/js/htmx-response-targets.js
function startsWith (line 8) | function startsWith(str, prefix) {
function getRespCodeTarget (line 17) | function getRespCodeTarget(elt, respCodeNumber) {
function handleErrorFlag (line 65) | function handleErrorFlag(evt) {
FILE: app/server/auth.go
constant authCookieName (line 19) | authCookieName = "secrets_session"
constant authUser (line 20) | authUser = "secrets"
method isAuthenticated (line 24) | func (s Server) isAuthenticated(r *http.Request) bool {
method checkBasicAuth (line 33) | func (s Server) checkBasicAuth(r *http.Request) bool {
method loginCtrl (line 54) | func (s Server) loginCtrl(w http.ResponseWriter, r *http.Request) {
method logoutCtrl (line 90) | func (s Server) logoutCtrl(w http.ResponseWriter, r *http.Request) {
method loginPopupCtrl (line 108) | func (s Server) loginPopupCtrl(w http.ResponseWriter, r *http.Request) {
method renderLoginPopup (line 112) | func (s Server) renderLoginPopup(w http.ResponseWriter, r *http.Request,...
method renderLoginPopupWithStatus (line 116) | func (s Server) renderLoginPopupWithStatus(w http.ResponseWriter, r *htt...
method generateSessionToken (line 129) | func (s Server) generateSessionToken() string {
method validateSessionToken (line 145) | func (s Server) validateSessionToken(token string) bool {
method sessionSecret (line 185) | func (s Server) sessionSecret() []byte {
FILE: app/server/auth_test.go
function testBcryptHash (line 23) | func testBcryptHash(t *testing.T, password string) string {
function TestServer_isAuthenticated (line 30) | func TestServer_isAuthenticated(t *testing.T) {
function TestServer_checkBasicAuth (line 95) | func TestServer_checkBasicAuth(t *testing.T) {
function TestServer_loginCtrl (line 139) | func TestServer_loginCtrl(t *testing.T) {
function TestServer_logoutCtrl (line 213) | func TestServer_logoutCtrl(t *testing.T) {
function TestServer_generateLinkCtrl_WithAuth (line 260) | func TestServer_generateLinkCtrl_WithAuth(t *testing.T) {
function TestServer_saveMessageCtrl_WithAuth (line 348) | func TestServer_saveMessageCtrl_WithAuth(t *testing.T) {
function TestServer_NoAuthWhenDisabled (line 417) | func TestServer_NoAuthWhenDisabled(t *testing.T) {
function TestServer_generateSessionToken (line 483) | func TestServer_generateSessionToken(t *testing.T) {
function TestServer_validateSessionToken (line 516) | func TestServer_validateSessionToken(t *testing.T) {
function TestServer_loginPopupCtrl (line 583) | func TestServer_loginPopupCtrl(t *testing.T) {
function TestServer_EmailEndpointsRequireAuth (line 616) | func TestServer_EmailEndpointsRequireAuth(t *testing.T) {
FILE: app/server/middleware.go
type ctxKey (line 17) | type ctxKey
constant hashedIPKey (line 19) | hashedIPKey ctxKey = "hashedIP"
function HashedIP (line 23) | func HashedIP(secret string) func(http.Handler) http.Handler {
function GetHashedIP (line 37) | func GetHashedIP(r *http.Request) string {
function Logger (line 46) | func Logger(l log.L) func(http.Handler) http.Handler {
function hashIP (line 85) | func hashIP(ip, secret string) string {
type statusWriter (line 92) | type statusWriter struct
method WriteHeader (line 97) | func (w *statusWriter) WriteHeader(status int) {
function SendErrorJSON (line 103) | func SendErrorJSON(w http.ResponseWriter, r *http.Request, l log.L, code...
function StripSlashes (line 113) | func StripSlashes(next http.Handler) http.Handler {
function Timeout (line 123) | func Timeout(timeout time.Duration) func(http.Handler) http.Handler {
function SecurityHeaders (line 131) | func SecurityHeaders(protocol string) func(http.Handler) http.Handler {
function RequireHTMX (line 167) | func RequireHTMX(next http.Handler) http.Handler {
FILE: app/server/middleware_test.go
function TestLogger (line 16) | func TestLogger(t *testing.T) {
function TestLoggerMasking (line 38) | func TestLoggerMasking(t *testing.T) {
function TestHashIP (line 60) | func TestHashIP(t *testing.T) {
function TestStripSlashes (line 76) | func TestStripSlashes(t *testing.T) {
function TestHashedIPMiddleware (line 108) | func TestHashedIPMiddleware(t *testing.T) {
function TestGetHashedIP (line 216) | func TestGetHashedIP(t *testing.T) {
function TestTimeout (line 227) | func TestTimeout(t *testing.T) {
function TestRequireHTMX_WithHeader (line 264) | func TestRequireHTMX_WithHeader(t *testing.T) {
function TestRequireHTMX_WithoutHeader (line 283) | func TestRequireHTMX_WithoutHeader(t *testing.T) {
function TestLoggerMaskingEdgeCases (line 303) | func TestLoggerMaskingEdgeCases(t *testing.T) {
function TestSecurityHeaders (line 343) | func TestSecurityHeaders(t *testing.T) {
function TestSendErrorJSON (line 447) | func TestSendErrorJSON(t *testing.T) {
FILE: app/server/mocks/email_sender_mock.go
type EmailSenderMock (line 31) | type EmailSenderMock struct
method GetDefaultFromName (line 56) | func (mock *EmailSenderMock) GetDefaultFromName() string {
method GetDefaultFromNameCalls (line 72) | func (mock *EmailSenderMock) GetDefaultFromNameCalls() []struct {
method Send (line 83) | func (mock *EmailSenderMock) Send(ctx context.Context, req email.Reque...
method SendCalls (line 104) | func (mock *EmailSenderMock) SendCalls() []struct {
FILE: app/server/server.go
type Config (line 29) | type Config struct
type EmailSender (line 58) | type EmailSender interface
type Server (line 64) | type Server struct
method WithEmail (line 98) | func (s Server) WithEmail(sender EmailSender) Server {
method newTemplateData (line 113) | func (s Server) newTemplateData(r *http.Request, form any) templateData {
method Run (line 138) | func (s Server) Run(ctx context.Context) error {
method routes (line 179) | func (s Server) routes() http.Handler {
method saveMessageCtrl (line 278) | func (s Server) saveMessageCtrl(w http.ResponseWriter, r *http.Request) {
method getMessageCtrl (line 320) | func (s Server) getMessageCtrl(w http.ResponseWriter, r *http.Request) {
method getParamsCtrl (line 374) | func (s Server) getParamsCtrl(w http.ResponseWriter, _ *http.Request) {
method sitemapCtrl (line 395) | func (s Server) sitemapCtrl(w http.ResponseWriter, _ *http.Request) {
function New (line 74) | func New(m Messager, version string, cfg Config) (Server, error) {
type Messager (line 104) | type Messager interface
FILE: app/server/server_test.go
function TestServer_saveAndLoadMemory (line 22) | func TestServer_saveAndLoadMemory(t *testing.T) {
function TestServer_saveAndLoadSQLite (line 71) | func TestServer_saveAndLoadSQLite(t *testing.T) {
function TestServer_saveAndManyPinAttempt (line 143) | func TestServer_saveAndManyPinAttempt(t *testing.T) {
function TestServer_saveAndGoodPinAttempt (line 193) | func TestServer_saveAndGoodPinAttempt(t *testing.T) {
function TestServer_getParams (line 238) | func TestServer_getParams(t *testing.T) {
function TestServer_getParams_AllowNoPin (line 255) | func TestServer_getParams_AllowNoPin(t *testing.T) {
function TestServer_saveMessageCtrl_APIRejectsEmptyPinEvenWithAllowNoPin (line 290) | func TestServer_saveMessageCtrl_APIRejectsEmptyPinEvenWithAllowNoPin(t *...
function TestServer_saveMessageCtrl (line 317) | func TestServer_saveMessageCtrl(t *testing.T) {
function TestServer_getMessageCtrl (line 371) | func TestServer_getMessageCtrl(t *testing.T) {
function TestServer_Run (line 432) | func TestServer_Run(t *testing.T) {
function TestServer_EmbeddedFiles (line 473) | func TestServer_EmbeddedFiles(t *testing.T) {
function TestServer_LocalFiles (line 502) | func TestServer_LocalFiles(t *testing.T) {
function TestServer_ThemeToggle (line 544) | func TestServer_ThemeToggle(t *testing.T) {
function TestServer_ClosePopup (line 608) | func TestServer_ClosePopup(t *testing.T) {
function TestServer_CopyFeedback (line 639) | func TestServer_CopyFeedback(t *testing.T) {
function prepTestServer (line 702) | func prepTestServer(t *testing.T) (ts *httptest.Server, teardown func()) {
function TestServer_ping (line 727) | func TestServer_ping(t *testing.T) {
function TestServer_sitemap (line 757) | func TestServer_sitemap(t *testing.T) {
function TestServer_robotsTxt (line 797) | func TestServer_robotsTxt(t *testing.T) {
function TestServer_NewWithNoDomains (line 821) | func TestServer_NewWithNoDomains(t *testing.T) {
function TestServer_NewWithMultipleDomains (line 842) | func TestServer_NewWithMultipleDomains(t *testing.T) {
function TestServer_MultipleDomainsLinkGeneration (line 867) | func TestServer_MultipleDomainsLinkGeneration(t *testing.T) {
function TestServer_getMessageCtrl_FileMessageWhenFilesDisabled (line 922) | func TestServer_getMessageCtrl_FileMessageWhenFilesDisabled(t *testing.T) {
function TestServer_SizeLimit_TextOnly (line 976) | func TestServer_SizeLimit_TextOnly(t *testing.T) {
function TestServer_API_ServerSideEncryption (line 1015) | func TestServer_API_ServerSideEncryption(t *testing.T) {
function TestServer_getMessageCtrl_TimingPad (line 1072) | func TestServer_getMessageCtrl_TimingPad(t *testing.T) {
FILE: app/server/validator/validator.go
type Validator (line 12) | type Validator struct
method Valid (line 18) | func (v *Validator) Valid() bool {
method AddFieldError (line 23) | func (v *Validator) AddFieldError(key, message string) {
method AddNonFieldError (line 34) | func (v *Validator) AddNonFieldError(message string) {
method CheckField (line 39) | func (v *Validator) CheckField(ok bool, key, message string) {
function NotBlank (line 46) | func NotBlank(value string) bool {
function Blank (line 51) | func Blank(value string) bool {
function MaxChars (line 56) | func MaxChars(value string, n int) bool {
function MinChars (line 61) | func MinChars(value string, n int) bool {
function IsNumber (line 66) | func IsNumber(value string) bool {
function MaxDuration (line 72) | func MaxDuration(d, maxDuration time.Duration) bool {
function IsBase64URL (line 78) | func IsBase64URL(value string) bool {
function isBase64URLChar (line 91) | func isBase64URLChar(c rune) bool {
FILE: app/server/validator/validator_test.go
function TestValidator_Valid (line 10) | func TestValidator_Valid(t *testing.T) {
function TestValidator_AddFieldError (line 68) | func TestValidator_AddFieldError(t *testing.T) {
function TestValidator_AddNonFieldError (line 107) | func TestValidator_AddNonFieldError(t *testing.T) {
function TestValidator_CheckField (line 116) | func TestValidator_CheckField(t *testing.T) {
function TestValidator_NotBlank (line 160) | func TestValidator_NotBlank(t *testing.T) {
function TestValidator_MaxChars (line 196) | func TestValidator_MaxChars(t *testing.T) {
function TestValidator_IsNumber (line 256) | func TestValidator_IsNumber(t *testing.T) {
function TestValidator_MaxDuration (line 297) | func TestValidator_MaxDuration(t *testing.T) {
function TestValidator_MinChars (line 341) | func TestValidator_MinChars(t *testing.T) {
function TestValidator_IsBase64URL (line 409) | func TestValidator_IsBase64URL(t *testing.T) {
FILE: app/server/web.go
constant baseTmpl (line 30) | baseTmpl = "base"
constant mainTmpl (line 31) | mainTmpl = "main"
constant errorTmpl (line 32) | errorTmpl = "error"
constant msgKey (line 34) | msgKey = "message"
constant pinKey (line 35) | pinKey = "pin"
constant expKey (line 36) | expKey = "exp"
constant expUnitKey (line 37) | expUnitKey = "expUnit"
constant pathKeyParam (line 38) | pathKeyParam = "key"
type createMsgForm (line 41) | type createMsgForm struct
type showMsgForm (line 52) | type showMsgForm struct
type emailPopupData (line 59) | type emailPopupData struct
type templateData (line 67) | type templateData struct
method render (line 88) | func (s Server) render(w http.ResponseWriter, status int, page, tmplName...
method indexCtrl (line 121) | func (s Server) indexCtrl(w http.ResponseWriter, r *http.Request) {
method generateLinkCtrl (line 141) | func (s Server) generateLinkCtrl(w http.ResponseWriter, r *http.Request) {
method renderSecureLink (line 231) | func (s Server) renderSecureLink(w http.ResponseWriter, r *http.Request,...
method showMessageViewCtrl (line 274) | func (s Server) showMessageViewCtrl(w http.ResponseWriter, r *http.Reque...
method aboutViewCtrl (line 302) | func (s Server) aboutViewCtrl(w http.ResponseWriter, r *http.Request) {
method loadMessageCtrl (line 315) | func (s Server) loadMessageCtrl(w http.ResponseWriter, r *http.Request) {
method handleLoadMessageError (line 421) | func (s Server) handleLoadMessageError(w http.ResponseWriter, r *http.Re...
function duration (line 452) | func duration(n int, unit string) time.Duration {
function validatePIN (line 466) | func validatePIN(pin string, pinValues []string, pinSize int) error {
function humanDuration (line 479) | func humanDuration(d time.Duration) string {
function getTheme (line 500) | func getTheme(r *http.Request) string {
method themeToggleCtrl (line 516) | func (s Server) themeToggleCtrl(w http.ResponseWriter, r *http.Request) {
method copyFeedbackCtrl (line 545) | func (s Server) copyFeedbackCtrl(w http.ResponseWriter, r *http.Request) {
method closePopupCtrl (line 572) | func (s Server) closePopupCtrl(w http.ResponseWriter, _ *http.Request) {
method emailPopupCtrl (line 578) | func (s Server) emailPopupCtrl(w http.ResponseWriter, r *http.Request) {
method sendEmailCtrl (line 614) | func (s Server) sendEmailCtrl(w http.ResponseWriter, r *http.Request) { ...
method isValidSecretLink (line 704) | func (s Server) isValidSecretLink(link string) bool {
function newTemplateCache (line 747) | func newTemplateCache() (map[string]*template.Template, error) {
function until (line 781) | func until(n int) []int {
function formatSize (line 790) | func formatSize(size int64) string {
method getValidatedHost (line 804) | func (s Server) getValidatedHost(r *http.Request) string {
function jsonEscape (line 836) | func jsonEscape(s string) template.JS {
FILE: app/server/web_test.go
function TestTemplates_Duration (line 27) | func TestTemplates_Duration(t *testing.T) {
function TestTemplates_HumanDuration (line 49) | func TestTemplates_HumanDuration(t *testing.T) {
function TestTemplates_NewTemplateCache (line 75) | func TestTemplates_NewTemplateCache(t *testing.T) {
function TestServer_indexCtrl (line 97) | func TestServer_indexCtrl(t *testing.T) {
function TestServer_aboutViewCtrl (line 124) | func TestServer_aboutViewCtrl(t *testing.T) {
function TestServer_showMessageViewCtrl (line 150) | func TestServer_showMessageViewCtrl(t *testing.T) {
function TestServer_generateLinkCtrl (line 198) | func TestServer_generateLinkCtrl(t *testing.T) {
function TestServer_generateLinkCtrl_EmptyPinAllowed (line 344) | func TestServer_generateLinkCtrl_EmptyPinAllowed(t *testing.T) {
function TestServer_generateLinkCtrl_EmptyPinRejected (line 373) | func TestServer_generateLinkCtrl_EmptyPinRejected(t *testing.T) {
function TestServer_generateLinkCtrl_HTMX (line 402) | func TestServer_generateLinkCtrl_HTMX(t *testing.T) {
function TestServer_loadMessageCtrl (line 481) | func TestServer_loadMessageCtrl(t *testing.T) {
function TestServer_showMessageViewCtrl_NoPinMessage (line 569) | func TestServer_showMessageViewCtrl_NoPinMessage(t *testing.T) {
function TestServer_loadMessageCtrl_NoPinMessage (line 597) | func TestServer_loadMessageCtrl_NoPinMessage(t *testing.T) {
function TestServer_render (line 625) | func TestServer_render(t *testing.T) {
function TestServer_until (line 677) | func TestServer_until(t *testing.T) {
function TestServer_newTemplateData (line 696) | func TestServer_newTemplateData(t *testing.T) {
function TestServer_BrandingInTemplates (line 753) | func TestServer_BrandingInTemplates(t *testing.T) {
function TestServer_getValidatedHost (line 798) | func TestServer_getValidatedHost(t *testing.T) {
function TestServer_generateLinkCtrl_MultipleDomain (line 913) | func TestServer_generateLinkCtrl_MultipleDomain(t *testing.T) {
function TestServer_IPv6LinkGeneration (line 969) | func TestServer_IPv6LinkGeneration(t *testing.T) {
function TestIPv6BracketingLogic (line 1070) | func TestIPv6BracketingLogic(t *testing.T) {
function TestServer_URLConstruction (line 1151) | func TestServer_URLConstruction(t *testing.T) {
function TestServer_SEOMetaTags (line 1191) | func TestServer_SEOMetaTags(t *testing.T) {
function TestServer_formatSize (line 1296) | func TestServer_formatSize(t *testing.T) {
function TestServer_generateLinkCtrl_RejectsMultipart (line 1320) | func TestServer_generateLinkCtrl_RejectsMultipart(t *testing.T) {
function TestServer_loadMessageCtrl_FileDownload (line 1364) | func TestServer_loadMessageCtrl_FileDownload(t *testing.T) {
function TestServer_showMessageViewCtrl_IsFile (line 1471) | func TestServer_showMessageViewCtrl_IsFile(t *testing.T) {
function TestServer_CanonicalURL (line 1539) | func TestServer_CanonicalURL(t *testing.T) {
function TestServer_generateLinkCtrl_MultipartRejected (line 1588) | func TestServer_generateLinkCtrl_MultipartRejected(t *testing.T) {
function TestServer_loadMessageCtrl_FileMessageWhenFilesDisabled (line 1633) | func TestServer_loadMessageCtrl_FileMessageWhenFilesDisabled(t *testing....
function TestServer_loadMessageCtrl_ClientEncHTMX (line 1682) | func TestServer_loadMessageCtrl_ClientEncHTMX(t *testing.T) {
function TestServer_emailPopupCtrl (line 1754) | func TestServer_emailPopupCtrl(t *testing.T) {
function TestServer_sendEmailCtrl (line 1795) | func TestServer_sendEmailCtrl(t *testing.T) {
function TestServer_isValidSecretLink (line 1992) | func TestServer_isValidSecretLink(t *testing.T) {
function TestServer_emailPopupCtrl_invalidLink (line 2060) | func TestServer_emailPopupCtrl_invalidLink(t *testing.T) {
function TestServer_sendEmailCtrl_invalidLink (line 2081) | func TestServer_sendEmailCtrl_invalidLink(t *testing.T) {
function TestServer_WithEmail (line 2106) | func TestServer_WithEmail(t *testing.T) {
FILE: app/store/sqlite.go
type SQLite (line 18) | type SQLite struct
method Save (line 99) | func (s *SQLite) Save(ctx context.Context, msg *Message) error {
method Load (line 121) | func (s *SQLite) Load(ctx context.Context, key string) (*Message, erro...
method IncErr (line 149) | func (s *SQLite) IncErr(ctx context.Context, key string) (int, error) {
method Remove (line 172) | func (s *SQLite) Remove(ctx context.Context, key string) error {
method Close (line 186) | func (s *SQLite) Close() error {
method activateCleaner (line 196) | func (s *SQLite) activateCleaner(every time.Duration) {
function NewInMemory (line 27) | func NewInMemory(cleanupDuration time.Duration) *SQLite {
function NewSQLite (line 42) | func NewSQLite(dbFile string, cleanupDuration time.Duration) (*SQLite, e...
function migrateClientEnc (line 225) | func migrateClientEnc(ctx context.Context, db *sql.DB) error {
FILE: app/store/sqlite_test.go
function TestSQLite_Save (line 16) | func TestSQLite_Save(t *testing.T) {
function TestSQLite_Load (line 38) | func TestSQLite_Load(t *testing.T) {
function TestSQLite_Load_NotFound (line 58) | func TestSQLite_Load_NotFound(t *testing.T) {
function TestSQLite_IncErr (line 70) | func TestSQLite_IncErr(t *testing.T) {
function TestSQLite_IncErr_Concurrent (line 98) | func TestSQLite_IncErr_Concurrent(t *testing.T) {
function TestSQLite_Remove (line 128) | func TestSQLite_Remove(t *testing.T) {
function TestSQLite_Cleanup (line 152) | func TestSQLite_Cleanup(t *testing.T) {
function TestSQLite_Cleanup_KeepsValid (line 176) | func TestSQLite_Cleanup_KeepsValid(t *testing.T) {
function TestSQLite_CleanerStopsOnClose (line 197) | func TestSQLite_CleanerStopsOnClose(t *testing.T) {
function TestSQLite_SaveLoadClientEnc (line 214) | func TestSQLite_SaveLoadClientEnc(t *testing.T) {
function TestSQLite_MigrateExistingDB (line 241) | func TestSQLite_MigrateExistingDB(t *testing.T) {
function TestInMemory_SharedAcrossConnections (line 285) | func TestInMemory_SharedAcrossConnections(t *testing.T) {
FILE: app/store/store.go
type Message (line 17) | type Message struct
constant alphabet (line 27) | alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
function GenerateID (line 31) | func GenerateID() string {
FILE: app/store/store_test.go
function TestGenerateID_Length (line 10) | func TestGenerateID_Length(t *testing.T) {
function TestGenerateID_Charset (line 15) | func TestGenerateID_Charset(t *testing.T) {
function TestGenerateID_Uniqueness (line 25) | func TestGenerateID_Uniqueness(t *testing.T) {
FILE: e2e/auth_test.go
constant authServerURL (line 16) | authServerURL = "http://localhost:18081"
constant testAuthHash (line 18) | testAuthHash = "$2a$10$q8UbvhCC/LFB4kCxenUGQ.34UuyUVg.7otCerbwj9xkrNXO9F...
function startAuthServer (line 23) | func startAuthServer(t *testing.T) func() {
function TestAuth_LoginPopupOnGenerate (line 55) | func TestAuth_LoginPopupOnGenerate(t *testing.T) {
function TestAuth_LoginSuccess (line 84) | func TestAuth_LoginSuccess(t *testing.T) {
function TestAuth_LoginWrongPassword (line 118) | func TestAuth_LoginWrongPassword(t *testing.T) {
function TestAuth_SessionPersists (line 155) | func TestAuth_SessionPersists(t *testing.T) {
function TestAuth_PopupCancel (line 198) | func TestAuth_PopupCancel(t *testing.T) {
function TestAuth_Logout (line 235) | func TestAuth_Logout(t *testing.T) {
FILE: e2e/crypto_test.go
function waitForCryptoJS (line 14) | func waitForCryptoJS(t *testing.T, page playwright.Page) {
function TestCrypto_CheckAvailable (line 21) | func TestCrypto_CheckAvailable(t *testing.T) {
function TestCrypto_GenerateKey (line 34) | func TestCrypto_GenerateKey(t *testing.T) {
function TestCrypto_TextRoundTrip (line 50) | func TestCrypto_TextRoundTrip(t *testing.T) {
function TestCrypto_TextWrongKey (line 72) | func TestCrypto_TextWrongKey(t *testing.T) {
function TestCrypto_FileRoundTrip (line 97) | func TestCrypto_FileRoundTrip(t *testing.T) {
function TestCrypto_FileRoundTrip_ArrayBuffer (line 133) | func TestCrypto_FileRoundTrip_ArrayBuffer(t *testing.T) {
function TestCrypto_DecryptAuto_Text (line 167) | func TestCrypto_DecryptAuto_Text(t *testing.T) {
function TestCrypto_DecryptAuto_File (line 188) | func TestCrypto_DecryptAuto_File(t *testing.T) {
function TestCrypto_UnicodePlaintext (line 217) | func TestCrypto_UnicodePlaintext(t *testing.T) {
function TestCrypto_UnicodeFilename (line 238) | func TestCrypto_UnicodeFilename(t *testing.T) {
function TestCrypto_EmptyPlaintext (line 266) | func TestCrypto_EmptyPlaintext(t *testing.T) {
function TestCrypto_LargeBinaryFile (line 296) | func TestCrypto_LargeBinaryFile(t *testing.T) {
FILE: e2e/e2e_test.go
constant baseURL (line 26) | baseURL = "http://localhost:18080"
constant testPin (line 27) | testPin = "12345"
function TestMain (line 36) | func TestMain(m *testing.M) {
function waitForServer (line 125) | func waitForServer(url string, timeout time.Duration) error { //nolint:u...
function newPage (line 140) | func newPage(t *testing.T) playwright.Page {
function waitVisible (line 153) | func waitVisible(t *testing.T, loc playwright.Locator) {
function waitHidden (line 162) | func waitHidden(t *testing.T, loc playwright.Locator) {
function extractMessageKey (line 171) | func extractMessageKey(t *testing.T, secretLink string) string {
function TestHome_PageLoads (line 181) | func TestHome_PageLoads(t *testing.T) {
function TestHome_FormElements (line 191) | func TestHome_FormElements(t *testing.T) {
function TestSecret_CreateAndReveal (line 219) | func TestSecret_CreateAndReveal(t *testing.T) {
function TestSecret_WrongPin (line 259) | func TestSecret_WrongPin(t *testing.T) {
function TestSecret_MaxAttempts (line 292) | func TestSecret_MaxAttempts(t *testing.T) {
function TestSecret_AlreadyViewed (line 330) | func TestSecret_AlreadyViewed(t *testing.T) {
function TestTheme_Toggle (line 377) | func TestTheme_Toggle(t *testing.T) {
function TestAbout_PageLoads (line 406) | func TestAbout_PageLoads(t *testing.T) {
function TestNavigation_HomeLink (line 424) | func TestNavigation_HomeLink(t *testing.T) {
function TestValidation_EmptyMessage (line 450) | func TestValidation_EmptyMessage(t *testing.T) {
function TestValidation_EmptyPin (line 466) | func TestValidation_EmptyPin(t *testing.T) {
function TestValidation_InvalidPinFormat (line 482) | func TestValidation_InvalidPinFormat(t *testing.T) {
function TestCopyLink_ButtonVisible (line 499) | func TestCopyLink_ButtonVisible(t *testing.T) {
function TestNewSecret_ButtonAfterCreate (line 514) | func TestNewSecret_ButtonAfterCreate(t *testing.T) {
function TestExpiration_UnitSelection (line 534) | func TestExpiration_UnitSelection(t *testing.T) {
function TestValidation_PinTooShort (line 560) | func TestValidation_PinTooShort(t *testing.T) {
constant multiDomainServerURL (line 581) | multiDomainServerURL = "http://localhost:18084"
function startMultiDomainServer (line 585) | func startMultiDomainServer(t *testing.T) func() {
function TestSecret_MultiDomainLinkGeneration (line 624) | func TestSecret_MultiDomainLinkGeneration(t *testing.T) {
function TestSecurityHeaders_Present (line 652) | func TestSecurityHeaders_Present(t *testing.T) {
function TestSecret_MissingKeyFragment (line 673) | func TestSecret_MissingKeyFragment(t *testing.T) {
FILE: e2e/email_test.go
constant emailServerURL (line 16) | emailServerURL = "http://localhost:18082"
function startEmailServer (line 20) | func startEmailServer(t *testing.T) func() {
function TestEmail_ButtonVisible (line 63) | func TestEmail_ButtonVisible(t *testing.T) {
function TestEmail_PopupOpens (line 84) | func TestEmail_PopupOpens(t *testing.T) {
function TestEmail_SendFailsWithFakeSMTP (line 121) | func TestEmail_SendFailsWithFakeSMTP(t *testing.T) {
function TestEmail_PopupCancel (line 160) | func TestEmail_PopupCancel(t *testing.T) {
FILE: e2e/file_test.go
constant noFilesServerURL (line 16) | noFilesServerURL = "http://localhost:18083"
function startNoFilesServer (line 20) | func startNoFilesServer(t *testing.T) func() {
function TestFile_TabVisible (line 60) | func TestFile_TabVisible(t *testing.T) {
function TestFile_TabSwitch (line 71) | func TestFile_TabSwitch(t *testing.T) {
function TestFile_SwitchBack (line 92) | func TestFile_SwitchBack(t *testing.T) {
function TestFile_UploadAndDownload (line 114) | func TestFile_UploadAndDownload(t *testing.T) {
function TestFile_InfoDisplay (line 168) | func TestFile_InfoDisplay(t *testing.T) {
function TestFile_LongFilenameWrapping (line 199) | func TestFile_LongFilenameWrapping(t *testing.T) {
function TestFile_TabHiddenWhenDisabled (line 242) | func TestFile_TabHiddenWhenDisabled(t *testing.T) {
FILE: e2e/hybrid_test.go
constant hybridServerURL (line 22) | hybridServerURL = "http://localhost:18085"
constant hybridAuthServerURL (line 23) | hybridAuthServerURL = "http://localhost:18086"
constant hybridTestAuthHash (line 25) | hybridTestAuthHash = "$2a$10$q8UbvhCC/LFB4kCxenUGQ.34UuyUVg.7otCerbwj9xk...
function startHybridServer (line 30) | func startHybridServer(t *testing.T) func() {
function startHybridAuthServer (line 71) | func startHybridAuthServer(t *testing.T) func() {
function TestHybrid_UIFlow_CryptoAvailable (line 106) | func TestHybrid_UIFlow_CryptoAvailable(t *testing.T) {
function TestHybrid_UIFlow_CreateTextSecret_HasFragment (line 125) | func TestHybrid_UIFlow_CreateTextSecret_HasFragment(t *testing.T) {
function TestHybrid_UIFlow_CreateAndRetrieve_RoundTrip (line 160) | func TestHybrid_UIFlow_CreateAndRetrieve_RoundTrip(t *testing.T) {
function TestHybrid_UIFlow_WrongPin (line 202) | func TestHybrid_UIFlow_WrongPin(t *testing.T) {
function TestHybrid_UIFlow_OneTimeRead (line 238) | func TestHybrid_UIFlow_OneTimeRead(t *testing.T) {
function TestHybrid_APIFlow_CreateAndRetrieve (line 296) | func TestHybrid_APIFlow_CreateAndRetrieve(t *testing.T) {
function TestHybrid_APIFlow_WrongPin (line 331) | func TestHybrid_APIFlow_WrongPin(t *testing.T) {
function TestHybrid_CrossMode_UICreateAPIRetrieve (line 356) | func TestHybrid_CrossMode_UICreateAPIRetrieve(t *testing.T) {
function TestHybrid_CrossMode_APICreateUIRetrieve (line 399) | func TestHybrid_CrossMode_APICreateUIRetrieve(t *testing.T) {
function TestHybrid_UIFile_ClientSideEncryption_RoundTrip (line 439) | func TestHybrid_UIFile_ClientSideEncryption_RoundTrip(t *testing.T) {
function TestHybrid_UIFile_SizeValidation (line 518) | func TestHybrid_UIFile_SizeValidation(t *testing.T) {
function TestHybrid_WebWithoutHTMX_Returns400 (line 561) | func TestHybrid_WebWithoutHTMX_Returns400(t *testing.T) {
function TestHybrid_WithAuth_RoundTrip (line 585) | func TestHybrid_WithAuth_RoundTrip(t *testing.T) {
function TestHybrid_ReEncryptsAfterValidationError (line 643) | func TestHybrid_ReEncryptsAfterValidationError(t *testing.T) {
function TestHybrid_TextSizeValidation (line 719) | func TestHybrid_TextSizeValidation(t *testing.T) {
function TestHybrid_WithAuth_WrongPasswordRetry (line 748) | func TestHybrid_WithAuth_WrongPasswordRetry(t *testing.T) {
FILE: e2e/no_pin_test.go
constant noPinServerURL (line 17) | noPinServerURL = "http://localhost:18085"
function startNoPinServer (line 20) | func startNoPinServer(t *testing.T) func() {
function TestNoPin_FormShowsOptionalLabel (line 59) | func TestNoPin_FormShowsOptionalLabel(t *testing.T) {
function TestNoPin_ModalAppearsOnEmptyPin (line 80) | func TestNoPin_ModalAppearsOnEmptyPin(t *testing.T) {
function TestNoPin_ModalCancelFocusesPIN (line 106) | func TestNoPin_ModalCancelFocusesPIN(t *testing.T) {
function TestNoPin_ModalConfirmCreatesSecret (line 138) | func TestNoPin_ModalConfirmCreatesSecret(t *testing.T) {
function TestNoPin_RevealButtonShown (line 171) | func TestNoPin_RevealButtonShown(t *testing.T) {
function TestNoPin_RevealButtonRevealsSecret (line 213) | func TestNoPin_RevealButtonRevealsSecret(t *testing.T) {
function TestNoPin_SecretWithPinStillWorks (line 255) | func TestNoPin_SecretWithPinStillWorks(t *testing.T) {
function TestNoPin_DeletedSecretShows404 (line 307) | func TestNoPin_DeletedSecretShows404(t *testing.T) {
function TestNoPin_ModalWorksAfterLogoClick (line 373) | func TestNoPin_ModalWorksAfterLogoClick(t *testing.T) {
function TestNoPin_ModalWorksAfterNewButton (line 417) | func TestNoPin_ModalWorksAfterNewButton(t *testing.T) {
function TestNoPin_ModalWorksAfterAboutPage (line 463) | func TestNoPin_ModalWorksAfterAboutPage(t *testing.T) {
function TestNoPin_DisabledBlocksEmptyPin (line 502) | func TestNoPin_DisabledBlocksEmptyPin(t *testing.T) {
FILE: vendor/github.com/aymerick/douceur/css/declaration.go
type Declaration (line 6) | type Declaration struct
method String (line 18) | func (decl *Declaration) String() string {
method StringWithImportant (line 23) | func (decl *Declaration) StringWithImportant(option bool) string {
method Equal (line 36) | func (decl *Declaration) Equal(other *Declaration) bool {
function NewDeclaration (line 13) | func NewDeclaration() *Declaration {
type DeclarationsByProperty (line 45) | type DeclarationsByProperty
method Len (line 48) | func (declarations DeclarationsByProperty) Len() int {
method Swap (line 53) | func (declarations DeclarationsByProperty) Swap(i, j int) {
method Less (line 58) | func (declarations DeclarationsByProperty) Less(i, j int) bool {
FILE: vendor/github.com/aymerick/douceur/css/rule.go
constant indentSpace (line 9) | indentSpace = 2
type RuleKind (line 13) | type RuleKind
method String (line 57) | func (kind RuleKind) String() string {
constant QualifiedRule (line 17) | QualifiedRule RuleKind = iota
constant AtRule (line 18) | AtRule
type Rule (line 27) | type Rule struct
method EmbedsRules (line 69) | func (rule *Rule) EmbedsRules() bool {
method Equal (line 82) | func (rule *Rule) Equal(other *Rule) bool {
method Diff (line 117) | func (rule *Rule) Diff(other *Rule) []string {
method String (line 167) | func (rule *Rule) String() string {
method indent (line 211) | func (rule *Rule) indent() string {
method indentEndBlock (line 222) | func (rule *Rule) indentEndBlock() string {
function NewRule (line 50) | func NewRule(kind RuleKind) *Rule {
FILE: vendor/github.com/aymerick/douceur/css/stylesheet.go
type Stylesheet (line 4) | type Stylesheet struct
method String (line 14) | func (sheet *Stylesheet) String() string {
function NewStylesheet (line 9) | func NewStylesheet() *Stylesheet {
FILE: vendor/github.com/aymerick/douceur/parser/parser.go
constant importantSuffixRegexp (line 15) | importantSuffixRegexp = `(?i)\s*!important\s*$`
type Parser (line 23) | type Parser struct
method ParseStylesheet (line 65) | func (parser *Parser) ParseStylesheet() (*css.Stylesheet, error) {
method ParseRules (line 85) | func (parser *Parser) ParseRules() ([]*css.Rule, error) {
method ParseRule (line 126) | func (parser *Parser) ParseRule() (*css.Rule, error) {
method ParseDeclarations (line 135) | func (parser *Parser) ParseDeclarations() ([]*css.Declaration, error) {
method ParseDeclaration (line 163) | func (parser *Parser) ParseDeclaration() (*css.Declaration, error) {
method parseAtRule (line 204) | func (parser *Parser) parseAtRule() (*css.Rule, error) {
method parseQualifiedRule (line 255) | func (parser *Parser) parseQualifiedRule() (*css.Rule, error) {
method parsePrelude (line 297) | func (parser *Parser) parsePrelude() (string, error) {
method parseBOM (line 313) | func (parser *Parser) parseBOM() (bool, error) {
method nextToken (line 323) | func (parser *Parser) nextToken() *scanner.Token {
method shiftToken (line 338) | func (parser *Parser) shiftToken() *scanner.Token {
method err (line 346) | func (parser *Parser) err() error {
method tokenError (line 356) | func (parser *Parser) tokenError() bool {
method tokenEOF (line 361) | func (parser *Parser) tokenEOF() bool {
method tokenWS (line 366) | func (parser *Parser) tokenWS() bool {
method tokenComment (line 371) | func (parser *Parser) tokenComment() bool {
method tokenCDOorCDC (line 376) | func (parser *Parser) tokenCDOorCDC() bool {
method tokenIgnorable (line 386) | func (parser *Parser) tokenIgnorable() bool {
method tokenParsable (line 391) | func (parser *Parser) tokenParsable() bool {
method tokenAtKeyword (line 396) | func (parser *Parser) tokenAtKeyword() bool {
method tokenChar (line 401) | func (parser *Parser) tokenChar(value string) bool {
method tokenEndOfPrelude (line 407) | func (parser *Parser) tokenEndOfPrelude() bool {
function init (line 33) | func init() {
function NewParser (line 38) | func NewParser(txt string) *Parser {
function Parse (line 45) | func Parse(text string) (*css.Stylesheet, error) {
function ParseDeclarations (line 55) | func ParseDeclarations(text string) ([]*css.Declaration, error) {
FILE: vendor/github.com/davecgh/go-spew/spew/bypass.go
constant UnsafeDisabled (line 33) | UnsafeDisabled = false
constant ptrSize (line 36) | ptrSize = unsafe.Sizeof((*byte)(nil))
type flag (line 39) | type flag
constant flagKindMask (line 54) | flagKindMask = flag(0x1f)
function flagField (line 80) | func flagField(v *reflect.Value) *flag {
function unsafeReflectValue (line 93) | func unsafeReflectValue(v reflect.Value) reflect.Value {
function init (line 105) | func init() {
FILE: vendor/github.com/davecgh/go-spew/spew/bypasssafe.go
constant UnsafeDisabled (line 28) | UnsafeDisabled = true
function unsafeReflectValue (line 36) | func unsafeReflectValue(v reflect.Value) reflect.Value {
FILE: vendor/github.com/davecgh/go-spew/spew/common.go
function catchPanic (line 72) | func catchPanic(w io.Writer, v reflect.Value) {
function handleMethods (line 85) | func handleMethods(cs *ConfigState, w io.Writer, v reflect.Value) (handl...
function printBool (line 144) | func printBool(w io.Writer, val bool) {
function printInt (line 153) | func printInt(w io.Writer, val int64, base int) {
function printUint (line 158) | func printUint(w io.Writer, val uint64, base int) {
function printFloat (line 164) | func printFloat(w io.Writer, val float64, precision int) {
function printComplex (line 170) | func printComplex(w io.Writer, c complex128, floatPrecision int) {
function printHexPtr (line 185) | func printHexPtr(w io.Writer, p uintptr) {
type valuesSorter (line 219) | type valuesSorter struct
method Len (line 279) | func (s *valuesSorter) Len() int {
method Swap (line 285) | func (s *valuesSorter) Swap(i, j int) {
method Less (line 326) | func (s *valuesSorter) Less(i, j int) bool {
function newValuesSorter (line 228) | func newValuesSorter(values []reflect.Value, cs *ConfigState) sort.Inter...
function canSortSimply (line 256) | func canSortSimply(kind reflect.Kind) bool {
function valueSortLess (line 295) | func valueSortLess(a, b reflect.Value) bool {
function sortValues (line 336) | func sortValues(values []reflect.Value, cs *ConfigState) {
FILE: vendor/github.com/davecgh/go-spew/spew/config.go
type ConfigState (line 37) | type ConfigState struct
method Errorf (line 115) | func (c *ConfigState) Errorf(format string, a ...interface{}) (err err...
method Fprint (line 127) | func (c *ConfigState) Fprint(w io.Writer, a ...interface{}) (n int, er...
method Fprintf (line 139) | func (c *ConfigState) Fprintf(w io.Writer, format string, a ...interfa...
method Fprintln (line 150) | func (c *ConfigState) Fprintln(w io.Writer, a ...interface{}) (n int, ...
method Print (line 162) | func (c *ConfigState) Print(a ...interface{}) (n int, err error) {
method Printf (line 174) | func (c *ConfigState) Printf(format string, a ...interface{}) (n int, ...
method Println (line 186) | func (c *ConfigState) Println(a ...interface{}) (n int, err error) {
method Sprint (line 197) | func (c *ConfigState) Sprint(a ...interface{}) string {
method Sprintf (line 208) | func (c *ConfigState) Sprintf(format string, a ...interface{}) string {
method Sprintln (line 219) | func (c *ConfigState) Sprintln(a ...interface{}) string {
method NewFormatter (line 240) | func (c *ConfigState) NewFormatter(v interface{}) fmt.Formatter {
method Fdump (line 246) | func (c *ConfigState) Fdump(w io.Writer, a ...interface{}) {
method Dump (line 273) | func (c *ConfigState) Dump(a ...interface{}) {
method Sdump (line 279) | func (c *ConfigState) Sdump(a ...interface{}) string {
method convertArgs (line 288) | func (c *ConfigState) convertArgs(args []interface{}) (formatters []in...
function NewDefaultConfig (line 304) | func NewDefaultConfig() *ConfigState {
FILE: vendor/github.com/davecgh/go-spew/spew/dump.go
type dumpState (line 51) | type dumpState struct
method indent (line 62) | func (d *dumpState) indent() {
method unpackValue (line 73) | func (d *dumpState) unpackValue(v reflect.Value) reflect.Value {
method dumpPtr (line 81) | func (d *dumpState) dumpPtr(v reflect.Value) {
method dumpSlice (line 161) | func (d *dumpState) dumpSlice(v reflect.Value) {
method dump (line 251) | func (d *dumpState) dump(v reflect.Value) {
function fdump (line 453) | func fdump(cs *ConfigState, w io.Writer, a ...interface{}) {
function Fdump (line 472) | func Fdump(w io.Writer, a ...interface{}) {
function Sdump (line 478) | func Sdump(a ...interface{}) string {
function Dump (line 507) | func Dump(a ...interface{}) {
FILE: vendor/github.com/davecgh/go-spew/spew/format.go
constant supportedFlags (line 28) | supportedFlags = "0-+# "
type formatState (line 34) | type formatState struct
method buildDefaultFormat (line 47) | func (f *formatState) buildDefaultFormat() (format string) {
method constructOrigFormat (line 65) | func (f *formatState) constructOrigFormat(verb rune) (format string) {
method unpackValue (line 94) | func (f *formatState) unpackValue(v reflect.Value) reflect.Value {
method formatPtr (line 105) | func (f *formatState) formatPtr(v reflect.Value) {
method format (line 201) | func (f *formatState) format(v reflect.Value) {
method Format (line 371) | func (f *formatState) Format(fs fmt.State, verb rune) {
function newFormatter (line 394) | func newFormatter(cs *ConfigState, v interface{}) fmt.Formatter {
function NewFormatter (line 417) | func NewFormatter(v interface{}) fmt.Formatter {
FILE: vendor/github.com/davecgh/go-spew/spew/spew.go
function Errorf (line 32) | func Errorf(format string, a ...interface{}) (err error) {
function Fprint (line 44) | func Fprint(w io.Writer, a ...interface{}) (n int, err error) {
function Fprintf (line 56) | func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err e...
function Fprintln (line 67) | func Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
function Print (line 79) | func Print(a ...interface{}) (n int, err error) {
function Printf (line 91) | func Printf(format string, a ...interface{}) (n int, err error) {
function Println (line 103) | func Println(a ...interface{}) (n int, err error) {
function Sprint (line 114) | func Sprint(a ...interface{}) string {
function Sprintf (line 125) | func Sprintf(format string, a ...interface{}) string {
function Sprintln (line 136) | func Sprintln(a ...interface{}) string {
function convertArgs (line 142) | func convertArgs(args []interface{}) (formatters []interface{}) {
FILE: vendor/github.com/deckarep/golang-set/v2/iterator.go
type Iterator (line 30) | type Iterator struct
method Stop (line 36) | func (i *Iterator[T]) Stop() {
function newIterator (line 51) | func newIterator[T comparable]() (*Iterator[T], chan<- T, <-chan struct{...
FILE: vendor/github.com/deckarep/golang-set/v2/set.go
type Set (line 41) | type Set interface
function NewSet (line 201) | func NewSet[T comparable](vals ...T) Set[T] {
function NewSetWithSize (line 211) | func NewSetWithSize[T comparable](cardinality int) Set[T] {
function NewThreadUnsafeSet (line 218) | func NewThreadUnsafeSet[T comparable](vals ...T) Set[T] {
function NewThreadUnsafeSetWithSize (line 228) | func NewThreadUnsafeSetWithSize[T comparable](cardinality int) Set[T] {
function NewSetFromMapKeys (line 235) | func NewSetFromMapKeys[T comparable, V any](val map[T]V) Set[T] {
function NewThreadUnsafeSetFromMapKeys (line 247) | func NewThreadUnsafeSetFromMapKeys[T comparable, V any](val map[T]V) Set...
FILE: vendor/github.com/deckarep/golang-set/v2/sorted.go
function Sorted (line 38) | func Sorted[E cmp.Ordered](set Set[E]) []E {
FILE: vendor/github.com/deckarep/golang-set/v2/threadsafe.go
type threadSafeSet (line 30) | type threadSafeSet struct
function newThreadSafeSet (line 35) | func newThreadSafeSet[T comparable]() *threadSafeSet[T] {
function newThreadSafeSetWithSize (line 41) | func newThreadSafeSetWithSize[T comparable](cardinality int) *threadSafe...
method Add (line 47) | func (t *threadSafeSet[T]) Add(v T) bool {
method Append (line 54) | func (t *threadSafeSet[T]) Append(v ...T) int {
method Contains (line 61) | func (t *threadSafeSet[T]) Contains(v ...T) bool {
method ContainsOne (line 69) | func (t *threadSafeSet[T]) ContainsOne(v T) bool {
method ContainsAny (line 77) | func (t *threadSafeSet[T]) ContainsAny(v ...T) bool {
method IsEmpty (line 85) | func (t *threadSafeSet[T]) IsEmpty() bool {
method IsSubset (line 89) | func (t *threadSafeSet[T]) IsSubset(other Set[T]) bool {
method IsProperSubset (line 101) | func (t *threadSafeSet[T]) IsProperSubset(other Set[T]) bool {
method IsSuperset (line 112) | func (t *threadSafeSet[T]) IsSuperset(other Set[T]) bool {
method IsProperSuperset (line 116) | func (t *threadSafeSet[T]) IsProperSuperset(other Set[T]) bool {
method Union (line 120) | func (t *threadSafeSet[T]) Union(other Set[T]) Set[T] {
method Intersect (line 133) | func (t *threadSafeSet[T]) Intersect(other Set[T]) Set[T] {
method Difference (line 146) | func (t *threadSafeSet[T]) Difference(other Set[T]) Set[T] {
method SymmetricDifference (line 159) | func (t *threadSafeSet[T]) SymmetricDifference(other Set[T]) Set[T] {
method Clear (line 172) | func (t *threadSafeSet[T]) Clear() {
method Remove (line 178) | func (t *threadSafeSet[T]) Remove(v T) {
method RemoveAll (line 184) | func (t *threadSafeSet[T]) RemoveAll(i ...T) {
method Cardinality (line 190) | func (t *threadSafeSet[T]) Cardinality() int {
method Each (line 196) | func (t *threadSafeSet[T]) Each(cb func(T) bool) {
method Iter (line 206) | func (t *threadSafeSet[T]) Iter() <-chan T {
method Iterator (line 221) | func (t *threadSafeSet[T]) Iterator() *Iterator[T] {
method Equal (line 241) | func (t *threadSafeSet[T]) Equal(other Set[T]) bool {
method Clone (line 253) | func (t *threadSafeSet[T]) Clone() Set[T] {
method String (line 262) | func (t *threadSafeSet[T]) String() string {
method Pop (line 269) | func (t *threadSafeSet[T]) Pop() (T, bool) {
method ToSlice (line 275) | func (t *threadSafeSet[T]) ToSlice() []T {
method MarshalJSON (line 285) | func (t *threadSafeSet[T]) MarshalJSON() ([]byte, error) {
method UnmarshalJSON (line 293) | func (t *threadSafeSet[T]) UnmarshalJSON(p []byte) error {
FILE: vendor/github.com/deckarep/golang-set/v2/threadunsafe.go
type threadUnsafeSet (line 34) | type threadUnsafeSet
function newThreadUnsafeSet (line 39) | func newThreadUnsafeSet[T comparable]() *threadUnsafeSet[T] {
function newThreadUnsafeSetWithSize (line 44) | func newThreadUnsafeSetWithSize[T comparable](cardinality int) *threadUn...
method Add (line 49) | func (s threadUnsafeSet[T]) Add(v T) bool {
method Append (line 55) | func (s *threadUnsafeSet[T]) Append(v ...T) int {
method add (line 64) | func (s *threadUnsafeSet[T]) add(v T) {
method Cardinality (line 68) | func (s *threadUnsafeSet[T]) Cardinality() int {
method Clear (line 72) | func (s *threadUnsafeSet[T]) Clear() {
method Clone (line 81) | func (s *threadUnsafeSet[T]) Clone() Set[T] {
method Contains (line 89) | func (s *threadUnsafeSet[T]) Contains(v ...T) bool {
method ContainsOne (line 98) | func (s *threadUnsafeSet[T]) ContainsOne(v T) bool {
method ContainsAny (line 103) | func (s *threadUnsafeSet[T]) ContainsAny(v ...T) bool {
method contains (line 113) | func (s *threadUnsafeSet[T]) contains(v T) (ok bool) {
method Difference (line 118) | func (s *threadUnsafeSet[T]) Difference(other Set[T]) Set[T] {
method Each (line 130) | func (s *threadUnsafeSet[T]) Each(cb func(T) bool) {
method Equal (line 138) | func (s *threadUnsafeSet[T]) Equal(other Set[T]) bool {
method Intersect (line 152) | func (s *threadUnsafeSet[T]) Intersect(other Set[T]) Set[T] {
method IsEmpty (line 173) | func (s *threadUnsafeSet[T]) IsEmpty() bool {
method IsProperSubset (line 177) | func (s *threadUnsafeSet[T]) IsProperSubset(other Set[T]) bool {
method IsProperSuperset (line 181) | func (s *threadUnsafeSet[T]) IsProperSuperset(other Set[T]) bool {
method IsSubset (line 185) | func (s *threadUnsafeSet[T]) IsSubset(other Set[T]) bool {
method IsSuperset (line 198) | func (s *threadUnsafeSet[T]) IsSuperset(other Set[T]) bool {
method Iter (line 202) | func (s *threadUnsafeSet[T]) Iter() <-chan T {
method Iterator (line 214) | func (s *threadUnsafeSet[T]) Iterator() *Iterator[T] {
method Pop (line 234) | func (s *threadUnsafeSet[T]) Pop() (v T, ok bool) {
method Remove (line 242) | func (s threadUnsafeSet[T]) Remove(v T) {
method RemoveAll (line 246) | func (s threadUnsafeSet[T]) RemoveAll(i ...T) {
method String (line 252) | func (s threadUnsafeSet[T]) String() string {
method SymmetricDifference (line 261) | func (s *threadUnsafeSet[T]) SymmetricDifference(other Set[T]) Set[T] {
method ToSlice (line 278) | func (s threadUnsafeSet[T]) ToSlice() []T {
method Union (line 287) | func (s threadUnsafeSet[T]) Union(other Set[T]) Set[T] {
method MarshalJSON (line 306) | func (s threadUnsafeSet[T]) MarshalJSON() ([]byte, error) {
method UnmarshalJSON (line 323) | func (s *threadUnsafeSet[T]) UnmarshalJSON(b []byte) error {
FILE: vendor/github.com/didip/tollbooth/v8/errors/errors.go
type HTTPError (line 7) | type HTTPError struct
method Error (line 13) | func (httperror *HTTPError) Error() string {
FILE: vendor/github.com/didip/tollbooth/v8/internal/time/rate/rate.go
type Limit (line 19) | type Limit
method durationFromTokens (line 387) | func (limit Limit) durationFromTokens(tokens float64) time.Duration {
method tokensFromDuration (line 394) | func (limit Limit) tokensFromDuration(d time.Duration) float64 {
constant Inf (line 22) | Inf = Limit(math.MaxFloat64)
function Every (line 25) | func Every(interval time.Duration) Limit {
type Limiter (line 55) | type Limiter struct
method Limit (line 67) | func (lim *Limiter) Limit() Limit {
method Burst (line 77) | func (lim *Limiter) Burst() int {
method Allow (line 93) | func (lim *Limiter) Allow() bool {
method TokensAt (line 98) | func (lim *Limiter) TokensAt(t time.Time) float64 {
method AllowN (line 108) | func (lim *Limiter) AllowN(now time.Time, n int) bool {
method Reserve (line 199) | func (lim *Limiter) Reserve() *Reservation {
method ReserveN (line 217) | func (lim *Limiter) ReserveN(now time.Time, n int) *Reservation {
method Wait (line 223) | func (lim *Limiter) Wait(ctx context.Context) (err error) {
method WaitN (line 231) | func (lim *Limiter) WaitN(ctx context.Context, n int) (err error) {
method SetLimit (line 277) | func (lim *Limiter) SetLimit(newLimit Limit) {
method SetLimitAt (line 284) | func (lim *Limiter) SetLimitAt(now time.Time, newLimit Limit) {
method SetBurst (line 296) | func (lim *Limiter) SetBurst(newBurst int) {
method SetBurstAt (line 301) | func (lim *Limiter) SetBurstAt(now time.Time, newBurst int) {
method reserveN (line 315) | func (lim *Limiter) reserveN(now time.Time, n int, maxFutureReserve ti...
method advance (line 369) | func (lim *Limiter) advance(now time.Time) (newNow time.Time, newLast ...
function NewLimiter (line 85) | func NewLimiter(r Limit, b int) *Limiter {
type Reservation (line 114) | type Reservation struct
method OK (line 126) | func (r *Reservation) OK() bool {
method Delay (line 131) | func (r *Reservation) Delay() time.Duration {
method DelayFrom (line 142) | func (r *Reservation) DelayFrom(now time.Time) time.Duration {
method Cancel (line 154) | func (r *Reservation) Cancel() {
method CancelAt (line 161) | func (r *Reservation) CancelAt(now time.Time) {
constant InfDuration (line 136) | InfDuration = time.Duration(1<<63 - 1)
FILE: vendor/github.com/didip/tollbooth/v8/libstring/libstring.go
function StringInSlice (line 13) | func StringInSlice(sliceString []string, needle string) bool {
function RemoteIPFromIPLookup (line 24) | func RemoteIPFromIPLookup(ipLookup limiter.IPLookup, r *http.Request) st...
function CanonicalizeIP (line 59) | func CanonicalizeIP(ip string) string {
FILE: vendor/github.com/didip/tollbooth/v8/limiter/limiter.go
function New (line 15) | func New(generalExpirableOptions *ExpirableOptions) *Limiter {
type IPLookup (line 46) | type IPLookup struct
type Limiter (line 58) | type Limiter struct
method SetTokenBucketExpirationTTL (line 118) | func (l *Limiter) SetTokenBucketExpirationTTL(ttl time.Duration) *Limi...
method GetTokenBucketExpirationTTL (line 127) | func (l *Limiter) GetTokenBucketExpirationTTL() time.Duration {
method SetBasicAuthExpirationTTL (line 134) | func (l *Limiter) SetBasicAuthExpirationTTL(ttl time.Duration) *Limiter {
method GetBasicAuthExpirationTTL (line 143) | func (l *Limiter) GetBasicAuthExpirationTTL() time.Duration {
method SetHeaderEntryExpirationTTL (line 150) | func (l *Limiter) SetHeaderEntryExpirationTTL(ttl time.Duration) *Limi...
method GetHeaderEntryExpirationTTL (line 159) | func (l *Limiter) GetHeaderEntryExpirationTTL() time.Duration {
method SetContextValueEntryExpirationTTL (line 166) | func (l *Limiter) SetContextValueEntryExpirationTTL(ttl time.Duration)...
method GetContextValueEntryExpirationTTL (line 175) | func (l *Limiter) GetContextValueEntryExpirationTTL() time.Duration {
method SetMax (line 182) | func (l *Limiter) SetMax(max float64) *Limiter {
method GetMax (line 191) | func (l *Limiter) GetMax() float64 {
method SetBurst (line 198) | func (l *Limiter) SetBurst(burst int) *Limiter {
method GetBurst (line 207) | func (l *Limiter) GetBurst() int {
method SetMessage (line 215) | func (l *Limiter) SetMessage(msg string) *Limiter {
method GetMessage (line 224) | func (l *Limiter) GetMessage() string {
method SetMessageContentType (line 231) | func (l *Limiter) SetMessageContentType(contentType string) *Limiter {
method GetMessageContentType (line 240) | func (l *Limiter) GetMessageContentType() string {
method SetStatusCode (line 247) | func (l *Limiter) SetStatusCode(statusCode int) *Limiter {
method GetStatusCode (line 256) | func (l *Limiter) GetStatusCode() int {
method SetOnLimitReached (line 263) | func (l *Limiter) SetOnLimitReached(fn func(w http.ResponseWriter, r *...
method ExecOnLimitReached (line 272) | func (l *Limiter) ExecOnLimitReached(w http.ResponseWriter, r *http.Re...
method SetOverrideDefaultResponseWriter (line 283) | func (l *Limiter) SetOverrideDefaultResponseWriter(override bool) *Lim...
method GetOverrideDefaultResponseWriter (line 292) | func (l *Limiter) GetOverrideDefaultResponseWriter() bool {
method SetIPLookup (line 300) | func (l *Limiter) SetIPLookup(lookup IPLookup) *Limiter {
method GetIPLookup (line 310) | func (l *Limiter) GetIPLookup() IPLookup {
method SetIgnoreURL (line 317) | func (l *Limiter) SetIgnoreURL(enabled bool) *Limiter {
method GetIgnoreURL (line 326) | func (l *Limiter) GetIgnoreURL() bool {
method SetForwardedForIndexFromBehind (line 333) | func (l *Limiter) SetForwardedForIndexFromBehind(forwardedForIndex int...
method GetForwardedForIndexFromBehind (line 342) | func (l *Limiter) GetForwardedForIndexFromBehind() int {
method SetMethods (line 349) | func (l *Limiter) SetMethods(methods []string) *Limiter {
method GetMethods (line 358) | func (l *Limiter) GetMethods() []string {
method SetBasicAuthUsers (line 365) | func (l *Limiter) SetBasicAuthUsers(basicAuthUsers []string) *Limiter {
method GetBasicAuthUsers (line 379) | func (l *Limiter) GetBasicAuthUsers() []string {
method RemoveBasicAuthUsers (line 384) | func (l *Limiter) RemoveBasicAuthUsers(basicAuthUsers []string) *Limit...
method DeleteExpiredTokenBuckets (line 393) | func (l *Limiter) DeleteExpiredTokenBuckets() {
method SetHeaders (line 398) | func (l *Limiter) SetHeaders(headers map[string][]string) *Limiter {
method GetHeaders (line 411) | func (l *Limiter) GetHeaders() map[string][]string {
method SetHeader (line 425) | func (l *Limiter) SetHeader(header string, entries []string) *Limiter {
method GetHeader (line 451) | func (l *Limiter) GetHeader(header string) []string {
method RemoveHeader (line 460) | func (l *Limiter) RemoveHeader(header string) *Limiter {
method RemoveHeaderEntries (line 474) | func (l *Limiter) RemoveHeaderEntries(header string, entriesForRemoval...
method SetContextValues (line 491) | func (l *Limiter) SetContextValues(contextValues map[string][]string) ...
method GetContextValues (line 504) | func (l *Limiter) GetContextValues() map[string][]string {
method SetContextValue (line 518) | func (l *Limiter) SetContextValue(contextValue string, entries []strin...
method GetContextValue (line 544) | func (l *Limiter) GetContextValue(contextValue string) []string {
method RemoveContextValue (line 553) | func (l *Limiter) RemoveContextValue(contextValue string) *Limiter {
method RemoveContextValuesEntries (line 567) | func (l *Limiter) RemoveContextValuesEntries(contextValue string, entr...
method limitReachedWithTokenBucketTTL (line 583) | func (l *Limiter) limitReachedWithTokenBucketTTL(key string, tokenBuck...
method LimitReached (line 606) | func (l *Limiter) LimitReached(key string) bool {
method Tokens (line 617) | func (l *Limiter) Tokens(key string) int {
FILE: vendor/github.com/didip/tollbooth/v8/limiter/limiter_options.go
type ExpirableOptions (line 8) | type ExpirableOptions struct
FILE: vendor/github.com/didip/tollbooth/v8/tollbooth.go
function setResponseHeaders (line 16) | func setResponseHeaders(lmt *limiter.Limiter, w http.ResponseWriter, r *...
function setRateLimitResponseHeaders (line 30) | func setRateLimitResponseHeaders(lmt *limiter.Limiter, w http.ResponseWr...
function NewLimiter (line 37) | func NewLimiter(max float64, tbOptions *limiter.ExpirableOptions) *limit...
function LimitByKeys (line 45) | func LimitByKeys(lmt *limiter.Limiter, keys []string) *errors.HTTPError {
function LimitByKeysAndReturn (line 52) | func LimitByKeysAndReturn(lmt *limiter.Limiter, keys []string) (*errors....
function ShouldSkipLimiter (line 61) | func ShouldSkipLimiter(lmt *limiter.Limiter, r *http.Request) bool {
function BuildKeys (line 196) | func BuildKeys(lmt *limiter.Limiter, r *http.Request) [][]string {
function LimitByRequest (line 292) | func LimitByRequest(lmt *limiter.Limiter, w http.ResponseWriter, r *http...
function LimitHandler (line 324) | func LimitHandler(lmt *limiter.Limiter, next http.Handler) http.Handler {
function LimitFuncHandler (line 346) | func LimitFuncHandler(lmt *limiter.Limiter, nextFunc func(http.ResponseW...
function HTTPMiddleware (line 351) | func HTTPMiddleware(lmt *limiter.Limiter) func(http.Handler) http.Handler {
FILE: vendor/github.com/dustin/go-humanize/big.go
function oomm (line 8) | func oomm(n, b *big.Int, maxmag int) (float64, int) {
function oom (line 23) | func oom(n, b *big.Int) (float64, int) {
FILE: vendor/github.com/dustin/go-humanize/bigbytes.go
function humanateBigBytes (line 112) | func humanateBigBytes(s, base *big.Int, sizes []string) string {
function BigBytes (line 133) | func BigBytes(s *big.Int) string {
function BigIBytes (line 143) | func BigIBytes(s *big.Int) string {
function ParseBigBytes (line 155) | func ParseBigBytes(s string) (*big.Int, error) {
FILE: vendor/github.com/dustin/go-humanize/bytes.go
constant Byte (line 14) | Byte = 1 << (iota * 10)
constant KiByte (line 15) | KiByte
constant MiByte (line 16) | MiByte
constant GiByte (line 17) | GiByte
constant TiByte (line 18) | TiByte
constant PiByte (line 19) | PiByte
constant EiByte (line 20) | EiByte
constant IByte (line 25) | IByte = 1
constant KByte (line 26) | KByte = IByte * 1000
constant MByte (line 27) | MByte = KByte * 1000
constant GByte (line 28) | GByte = MByte * 1000
constant TByte (line 29) | TByte = GByte * 1000
constant PByte (line 30) | PByte = TByte * 1000
constant EByte (line 31) | EByte = PByte * 1000
function logn (line 64) | func logn(n, b float64) float64 {
function humanateBytes (line 68) | func humanateBytes(s uint64, base float64, sizes []string) string {
function Bytes (line 88) | func Bytes(s uint64) string {
function IBytes (line 98) | func IBytes(s uint64) string {
function ParseBytes (line 110) | func ParseBytes(s string) (uint64, error) {
FILE: vendor/github.com/dustin/go-humanize/comma.go
function Comma (line 15) | func Comma(v int64) string {
function Commaf (line 50) | func Commaf(v float64) string {
function CommafWithDigits (line 83) | func CommafWithDigits(f float64, decimals int) string {
function BigComma (line 89) | func BigComma(b *big.Int) string {
FILE: vendor/github.com/dustin/go-humanize/commaf.go
function BigCommaf (line 14) | func BigCommaf(v *big.Float) string {
FILE: vendor/github.com/dustin/go-humanize/ftoa.go
function stripTrailingZeros (line 8) | func stripTrailingZeros(s string) string {
function stripTrailingDigits (line 26) | func stripTrailingDigits(s string, digits int) string {
function Ftoa (line 41) | func Ftoa(num float64) string {
function FtoaWithDigits (line 47) | func FtoaWithDigits(num float64, digits int) string {
FILE: vendor/github.com/dustin/go-humanize/number.go
function FormatFloat (line 65) | func FormatFloat(format string, n float64) string {
function FormatInteger (line 190) | func FormatInteger(format string, n int) string {
FILE: vendor/github.com/dustin/go-humanize/ordinals.go
function Ordinal (line 8) | func Ordinal(x int) string {
FILE: vendor/github.com/dustin/go-humanize/si.go
function revfmap (line 37) | func revfmap(in map[float64]string) map[string]float64 {
function init (line 47) | func init() {
function ComputeSI (line 64) | func ComputeSI(input float64) (float64, string) {
function SI (line 95) | func SI(input float64, unit string) string {
function SIWithDigits (line 105) | func SIWithDigits(input float64, decimals int, unit string) string {
function ParseSI (line 117) | func ParseSI(input string) (float64, string, error) {
FILE: vendor/github.com/dustin/go-humanize/times.go
constant Day (line 12) | Day = 24 * time.Hour
constant Week (line 13) | Week = 7 * Day
constant Month (line 14) | Month = 30 * Day
constant Year (line 15) | Year = 12 * Month
constant LongTime (line 16) | LongTime = 37 * Year
function Time (line 22) | func Time(then time.Time) string {
type RelTimeMagnitude (line 41) | type RelTimeMagnitude struct
function RelTime (line 74) | func RelTime(a, b time.Time, albl, blbl string) string {
function CustomRelTime (line 84) | func CustomRelTime(a, b time.Time, albl, blbl string, magnitudes []RelTi...
FILE: vendor/github.com/go-jose/go-jose/v3/json/decode.go
function Unmarshal (line 85) | func Unmarshal(data []byte, v interface{}) error {
type Unmarshaler (line 104) | type Unmarshaler interface
type UnmarshalTypeError (line 110) | type UnmarshalTypeError struct
method Error (line 116) | func (e *UnmarshalTypeError) Error() string {
type UnmarshalFieldError (line 123) | type UnmarshalFieldError struct
method Error (line 129) | func (e *UnmarshalFieldError) Error() string {
type InvalidUnmarshalError (line 135) | type InvalidUnmarshalError struct
method Error (line 139) | func (e *InvalidUnmarshalError) Error() string {
type Number (line 173) | type Number
method String (line 176) | func (n Number) String() string { return string(n) }
method Float64 (line 179) | func (n Number) Float64() (float64, error) {
method Int64 (line 184) | func (n Number) Int64() (int64, error) {
function isValidNumber (line 189) | func isValidNumber(s string) bool {
type NumberUnmarshalType (line 248) | type NumberUnmarshalType
constant UnmarshalFloat (line 252) | UnmarshalFloat NumberUnmarshalType = iota
constant UnmarshalJSONNumber (line 254) | UnmarshalJSONNumber
constant UnmarshalIntOrFloat (line 257) | UnmarshalIntOrFloat
type decodeState (line 261) | type decodeState struct
method unmarshal (line 150) | func (d *decodeState) unmarshal(v interface{}) (err error) {
method init (line 275) | func (d *decodeState) init(data []byte) *decodeState {
method error (line 283) | func (d *decodeState) error(err error) {
method saveError (line 289) | func (d *decodeState) saveError(err error) {
method next (line 297) | func (d *decodeState) next() []byte {
method scanWhile (line 320) | func (d *decodeState) scanWhile(op int) int {
method value (line 340) | func (d *decodeState) value(v reflect.Value) {
method valueQuoted (line 392) | func (d *decodeState) valueQuoted() interface{} {
method indirect (line 416) | func (d *decodeState) indirect(v reflect.Value, decodingNull bool) (Un...
method array (line 459) | func (d *decodeState) array(v reflect.Value) {
method object (line 567) | func (d *decodeState) object(v reflect.Value) {
method literal (line 726) | func (d *decodeState) literal(v reflect.Value) {
method convertNumber (line 740) | func (d *decodeState) convertNumber(s string) (interface{}, error) {
method literalStore (line 779) | func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQ...
method valueInterface (line 948) | func (d *decodeState) valueInterface() interface{} {
method arrayInterface (line 963) | func (d *decodeState) arrayInterface() []interface{} {
method objectInterface (line 991) | func (d *decodeState) objectInterface() map[string]interface{} {
method literalInterface (line 1047) | func (d *decodeState) literalInterface() interface{} {
type unquotedValue (line 386) | type unquotedValue struct
function getu4 (line 1085) | func getu4(s []byte) rune {
function unquote (line 1098) | func unquote(s []byte) (t string, ok bool) {
function unquoteBytes (line 1104) | func unquoteBytes(s []byte) (t []byte, ok bool) {
FILE: vendor/github.com/go-jose/go-jose/v3/json/encode.go
function Marshal (line 137) | func Marshal(v interface{}) ([]byte, error) {
function MarshalIndent (line 147) | func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) {
function HTMLEscape (line 166) | func HTMLEscape(dst *bytes.Buffer, src []byte) {
type Marshaler (line 197) | type Marshaler interface
type UnsupportedTypeError (line 203) | type UnsupportedTypeError struct
method Error (line 207) | func (e *UnsupportedTypeError) Error() string {
type UnsupportedValueError (line 211) | type UnsupportedValueError struct
method Error (line 216) | func (e *UnsupportedValueError) Error() string {
type InvalidUTF8Error (line 226) | type InvalidUTF8Error struct
method Error (line 230) | func (e *InvalidUTF8Error) Error() string {
type MarshalerError (line 234) | type MarshalerError struct
method Error (line 239) | func (e *MarshalerError) Error() string {
type encodeState (line 246) | type encodeState struct
method marshal (line 262) | func (e *encodeState) marshal(v interface{}) (err error) {
method error (line 278) | func (e *encodeState) error(err error) {
method reflectValue (line 300) | func (e *encodeState) reflectValue(v reflect.Value) {
method string (line 788) | func (e *encodeState) string(s string) int {
method stringBytes (line 864) | func (e *encodeState) stringBytes(s []byte) int {
function newEncodeState (line 253) | func newEncodeState() *encodeState {
function isEmptyValue (line 282) | func isEmptyValue(v reflect.Value) bool {
type encoderFunc (line 304) | type encoderFunc
function valueEncoder (line 311) | func valueEncoder(v reflect.Value) encoderFunc {
function typeEncoder (line 318) | func typeEncoder(t reflect.Type) encoderFunc {
function newTypeEncoder (line 359) | func newTypeEncoder(t reflect.Type, allowAddr bool) encoderFunc {
function invalidValueEncoder (line 408) | func invalidValueEncoder(e *encodeState, v reflect.Value, quoted bool) {
function marshalerEncoder (line 412) | func marshalerEncoder(e *encodeState, v reflect.Value, quoted bool) {
function addrMarshalerEncoder (line 428) | func addrMarshalerEncoder(e *encodeState, v reflect.Value, quoted bool) {
function textMarshalerEncoder (line 445) | func textMarshalerEncoder(e *encodeState, v reflect.Value, quoted bool) {
function addrTextMarshalerEncoder (line 458) | func addrTextMarshalerEncoder(e *encodeState, v reflect.Value, quoted bo...
function boolEncoder (line 472) | func boolEncoder(e *encodeState, v reflect.Value, quoted bool) {
function intEncoder (line 486) | func intEncoder(e *encodeState, v reflect.Value, quoted bool) {
function uintEncoder (line 497) | func uintEncoder(e *encodeState, v reflect.Value, quoted bool) {
type floatEncoder (line 508) | type floatEncoder
method encode (line 510) | func (bits floatEncoder) encode(e *encodeState, v reflect.Value, quote...
function stringEncoder (line 530) | func stringEncoder(e *encodeState, v reflect.Value, quoted bool) {
function interfaceEncoder (line 555) | func interfaceEncoder(e *encodeState, v reflect.Value, quoted bool) {
function unsupportedTypeEncoder (line 563) | func unsupportedTypeEncoder(e *encodeState, v reflect.Value, quoted bool) {
type structEncoder (line 567) | type structEncoder struct
method encode (line 572) | func (se *structEncoder) encode(e *encodeState, v reflect.Value, quote...
function newStructEncoder (line 592) | func newStructEncoder(t reflect.Type) encoderFunc {
type mapEncoder (line 604) | type mapEncoder struct
method encode (line 608) | func (me *mapEncoder) encode(e *encodeState, v reflect.Value, _ bool) {
function newMapEncoder (line 627) | func newMapEncoder(t reflect.Type) encoderFunc {
function encodeByteSlice (line 635) | func encodeByteSlice(e *encodeState, v reflect.Value, _ bool) {
type sliceEncoder (line 658) | type sliceEncoder struct
method encode (line 662) | func (se *sliceEncoder) encode(e *encodeState, v reflect.Value, _ bool) {
function newSliceEncoder (line 670) | func newSliceEncoder(t reflect.Type) encoderFunc {
type arrayEncoder (line 679) | type arrayEncoder struct
method encode (line 683) | func (ae *arrayEncoder) encode(e *encodeState, v reflect.Value, _ bool) {
function newArrayEncoder (line 695) | func newArrayEncoder(t reflect.Type) encoderFunc {
type ptrEncoder (line 700) | type ptrEncoder struct
method encode (line 704) | func (pe *ptrEncoder) encode(e *encodeState, v reflect.Value, quoted b...
function newPtrEncoder (line 712) | func newPtrEncoder(t reflect.Type) encoderFunc {
type condAddrEncoder (line 717) | type condAddrEncoder struct
method encode (line 721) | func (ce *condAddrEncoder) encode(e *encodeState, v reflect.Value, quo...
function newCondAddrEncoder (line 731) | func newCondAddrEncoder(canAddrEnc, elseEnc encoderFunc) encoderFunc {
function isValidTag (line 736) | func isValidTag(s string) bool {
function fieldByIndex (line 755) | func fieldByIndex(v reflect.Value, index []int) reflect.Value {
function typeByIndex (line 768) | func typeByIndex(t reflect.Type, index []int) reflect.Type {
type stringValues (line 780) | type stringValues
method Len (line 782) | func (sv stringValues) Len() int { return len(sv) }
method Swap (line 783) | func (sv stringValues) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[...
method Less (line 784) | func (sv stringValues) Less(i, j int) bool { return sv.get(i) < sv.get...
method get (line 785) | func (sv stringValues) get(i int) string { return sv[i].String() }
type field (line 940) | type field struct
function fillField (line 951) | func fillField(f field) field {
type byName (line 959) | type byName
method Len (line 961) | func (x byName) Len() int { return len(x) }
method Swap (line 963) | func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
method Less (line 965) | func (x byName) Less(i, j int) bool {
type byIndex (line 979) | type byIndex
method Len (line 981) | func (x byIndex) Len() int { return len(x) }
method Swap (line 983) | func (x byIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
method Less (line 985) | func (x byIndex) Less(i, j int) bool {
function typeFields (line 1000) | func typeFields(t reflect.Type) []field {
function dominantField (line 1137) | func dominantField(fields []field) (field, bool) {
function cachedTypeFields (line 1175) | func cachedTypeFields(t reflect.Type) []field {
FILE: vendor/github.com/go-jose/go-jose/v3/json/indent.go
function Compact (line 11) | func Compact(dst *bytes.Buffer, src []byte) error {
function compact (line 15) | func compact(dst *bytes.Buffer, src []byte, escape bool) error {
function newline (line 60) | func newline(dst *bytes.Buffer, prefix, indent string, depth int) {
function Indent (line 79) | func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error {
FILE: vendor/github.com/go-jose/go-jose/v3/json/scanner.go
function checkValid (line 20) | func checkValid(data []byte, scan *scanner) error {
function nextValue (line 37) | func nextValue(data []byte, scan *scanner) (value, rest []byte, err erro...
type SyntaxError (line 64) | type SyntaxError struct
method Error (line 69) | func (e *SyntaxError) Error() string { return e.msg }
type scanner (line 83) | type scanner struct
method reset (line 145) | func (s *scanner) reset() {
method eof (line 155) | func (s *scanner) eof() int {
method pushParseState (line 173) | func (s *scanner) pushParseState(p int) {
method popParseState (line 179) | func (s *scanner) popParseState() {
method error (line 585) | func (s *scanner) error(c byte, context string) int {
method undo (line 608) | func (s *scanner) undo(scanCode int) {
constant scanContinue (line 117) | scanContinue = iota
constant scanBeginLiteral (line 118) | scanBeginLiteral
constant scanBeginObject (line 119) | scanBeginObject
constant scanObjectKey (line 120) | scanObjectKey
constant scanObjectValue (line 121) | scanObjectValue
constant scanEndObject (line 122) | scanEndObject
constant scanBeginArray (line 123) | scanBeginArray
constant scanArrayValue (line 124) | scanArrayValue
constant scanEndArray (line 125) | scanEndArray
constant scanSkipSpace (line 126) | scanSkipSpace
constant scanEnd (line 129) | scanEnd
constant scanError (line 130) | scanError
constant parseObjectKey (line 138) | parseObjectKey = iota
constant parseObjectValue (line 139) | parseObjectValue
constant parseArrayValue (line 140) | parseArrayValue
function isSpace (line 191) | func isSpace(c byte) bool {
function stateBeginValueOrEmpty (line 196) | func stateBeginValueOrEmpty(s *scanner, c byte) int {
function stateBeginValue (line 207) | func stateBeginValue(s *scanner, c byte) int {
function stateBeginStringOrEmpty (line 247) | func stateBeginStringOrEmpty(s *scanner, c byte) int {
function stateBeginString (line 260) | func stateBeginString(s *scanner, c byte) int {
function stateEndValue (line 273) | func stateEndValue(s *scanner, c byte) int {
function stateEndTop (line 322) | func stateEndTop(s *scanner, c byte) int {
function stateInString (line 331) | func stateInString(s *scanner, c byte) int {
function stateInStringEsc (line 347) | func stateInStringEsc(s *scanner, c byte) int {
function stateInStringEscU (line 360) | func stateInStringEscU(s *scanner, c byte) int {
function stateInStringEscU1 (line 370) | func stateInStringEscU1(s *scanner, c byte) int {
function stateInStringEscU12 (line 380) | func stateInStringEscU12(s *scanner, c byte) int {
function stateInStringEscU123 (line 390) | func stateInStringEscU123(s *scanner, c byte) int {
function stateNeg (line 400) | func stateNeg(s *scanner, c byte) int {
function state1 (line 414) | func state1(s *scanner, c byte) int {
function state0 (line 423) | func state0(s *scanner, c byte) int {
function stateDot (line 437) | func stateDot(s *scanner, c byte) int {
function stateDot0 (line 447) | func stateDot0(s *scanner, c byte) int {
function stateE (line 460) | func stateE(s *scanner, c byte) int {
function stateESign (line 470) | func stateESign(s *scanner, c byte) int {
function stateE0 (line 481) | func stateE0(s *scanner, c byte) int {
function stateT (line 489) | func stateT(s *scanner, c byte) int {
function stateTr (line 498) | func stateTr(s *scanner, c byte) int {
function stateTru (line 507) | func stateTru(s *scanner, c byte) int {
function stateF (line 516) | func stateF(s *scanner, c byte) int {
function stateFa (line 525) | func stateFa(s *scanner, c byte) int {
function stateFal (line 534) | func stateFal(s *scanner, c byte) int {
function stateFals (line 543) | func stateFals(s *scanner, c byte) int {
function stateN (line 552) | func stateN(s *scanner, c byte) int {
function stateNu (line 561) | func stateNu(s *scanner, c byte) int {
function stateNul (line 570) | func stateNul(s *scanner, c byte) int {
function stateError (line 580) | func stateError(s *scanner, c byte) int {
function quoteChar (line 592) | func quoteChar(c byte) string {
function stateRedo (line 619) | func stateRedo(s *scanner, c byte) int {
FILE: vendor/github.com/go-jose/go-jose/v3/json/stream.go
type Decoder (line 14) | type Decoder struct
method UseNumber (line 37) | func (dec *Decoder) UseNumber() { dec.d.numberType = UnmarshalJSONNumb...
method SetNumberType (line 41) | func (dec *Decoder) SetNumberType(t NumberUnmarshalType) { dec.d.numbe...
method Decode (line 48) | func (dec *Decoder) Decode(v interface{}) error {
method Buffered (line 82) | func (dec *Decoder) Buffered() io.Reader {
method readValue (line 88) | func (dec *Decoder) readValue() (int, error) {
method refill (line 139) | func (dec *Decoder) refill() error {
method tokenPrepareForDecode (line 258) | func (dec *Decoder) tokenPrepareForDecode() error {
method tokenValueAllowed (line 287) | func (dec *Decoder) tokenValueAllowed() bool {
method tokenValueEnd (line 295) | func (dec *Decoder) tokenValueEnd() {
method Token (line 322) | func (dec *Decoder) Token() (Token, error) {
method tokenError (line 424) | func (dec *Decoder) tokenError(c byte) (Token, error) {
method More (line 445) | func (dec *Decoder) More() bool {
method peek (line 450) | func (dec *Decoder) peek() (byte, error) {
function NewDecoder (line 30) | func NewDecoder(r io.Reader) *Decoder {
function nonSpace (line 163) | func nonSpace(b []byte) bool {
type Encoder (line 173) | type Encoder struct
method Encode (line 188) | func (enc *Encoder) Encode(v interface{}) error {
function NewEncoder (line 179) | func NewEncoder(w io.Writer) *Encoder {
type RawMessage (line 216) | type RawMessage
method MarshalJSON (line 219) | func (m *RawMessage) MarshalJSON() ([]byte, error) {
method UnmarshalJSON (line 224) | func (m *RawMessage) UnmarshalJSON(data []byte) error {
type Token (line 243) | type Token interface
constant tokenTopValue (line 246) | tokenTopValue = iota
constant tokenArrayStart (line 247) | tokenArrayStart
constant tokenArrayValue (line 248) | tokenArrayValue
constant tokenArrayComma (line 249) | tokenArrayComma
constant tokenObjectStart (line 250) | tokenObjectStart
constant tokenObjectKey (line 251) | tokenObjectKey
constant tokenObjectColon (line 252) | tokenObjectColon
constant tokenObjectValue (line 253) | tokenObjectValue
constant tokenObjectComma (line 254) | tokenObjectComma
type Delim (line 305) | type Delim
method String (line 307) | func (d Delim) String() string {
function clearOffset (line 418) | func clearOffset(err error) {
FILE: vendor/github.com/go-jose/go-jose/v3/json/tags.go
type tagOptions (line 13) | type tagOptions
method Contains (line 27) | func (o tagOptions) Contains(optionName string) bool {
function parseTag (line 17) | func parseTag(tag string) (string, tagOptions) {
FILE: vendor/github.com/go-pkgz/email/auth.go
type authMethod (line 9) | type authMethod
constant authMethodPlain (line 13) | authMethodPlain authMethod = "PLAIN"
constant authMethodLogin (line 14) | authMethodLogin authMethod = "LOGIN"
function newLoginAuth (line 29) | func newLoginAuth(usr, pwd, host string) smtp.Auth {
type loginAuth (line 33) | type loginAuth struct
method Start (line 43) | func (a *loginAuth) Start(server *smtp.ServerInfo) (proto string, toSe...
method Next (line 54) | func (a *loginAuth) Next(_ []byte, more bool) (toServer []byte, err er...
function isLocalhost (line 39) | func isLocalhost(name string) bool {
FILE: vendor/github.com/go-pkgz/email/email.go
type Sender (line 30) | type Sender struct
method Send (line 103) | func (em *Sender) Send(text string, params Params) error {
method String (line 181) | func (em *Sender) String() string {
method client (line 186) | func (em *Sender) client() (c *smtp.Client, err error) {
method auth (line 227) | func (em *Sender) auth() smtp.Auth {
method buildMessage (line 238) | func (em *Sender) buildMessage(text string, params Params) (message st...
method writeBody (line 312) | func (em *Sender) writeBody(wc io.WriteCloser, text string) error {
method writeFiles (line 322) | func (em *Sender) writeFiles(mp *multipart.Writer, files []string, dis...
type Params (line 48) | type Params struct
type Logger (line 59) | type Logger interface
type SMTPClient (line 64) | type SMTPClient interface
function NewSender (line 74) | func NewSender(smtpHost string, options ...Option) *Sender {
function extractEmailAddress (line 173) | func extractEmailAddress(from string) string {
type nopLogger (line 380) | type nopLogger struct
method Logf (line 382) | func (nopLogger) Logf(_ string, _ ...interface{}) {}
FILE: vendor/github.com/go-pkgz/email/options.go
type Option (line 6) | type Option
function SMTP (line 9) | func SMTP(smtp SMTPClient) Option {
function Log (line 16) | func Log(l Logger) Option {
function Port (line 23) | func Port(port int) Option {
function ContentType (line 30) | func ContentType(contentType string) Option {
function Charset (line 37) | func Charset(charset string) Option {
function TLS (line 44) | func TLS(enabled bool) Option {
function STARTTLS (line 51) | func STARTTLS(enabled bool) Option {
function InsecureSkipVerify (line 58) | func InsecureSkipVerify(enabled bool) Option {
function Auth (line 65) | func Auth(smtpUserName, smtpPasswd string) Option {
function LoginAuth (line 73) | func LoginAuth() Option {
function TimeOut (line 80) | func TimeOut(timeOut time.Duration) Option {
FILE: vendor/github.com/go-pkgz/expirable-cache/v3/cache.go
type Cache (line 23) | type Cache interface
type Stats (line 47) | type Stats struct
type cacheImpl (line 53) | type cacheImpl struct
constant noEvictionTTL (line 66) | noEvictionTTL = time.Hour * 24 * 365 * 10
function NewCache (line 72) | func NewCache[K comparable, V any]() Cache[K, V] {
method Add (line 84) | func (c *cacheImpl[K, V]) Add(key K, value V) (evicted bool) {
method Set (line 89) | func (c *cacheImpl[K, V]) Set(key K, value V, ttl time.Duration) {
method addWithTTL (line 96) | func (c *cacheImpl[K, V]) addWithTTL(key K, value V, ttl time.Duration) ...
method Get (line 134) | func (c *cacheImpl[K, V]) Get(key K) (V, bool) {
method Contains (line 156) | func (c *cacheImpl[K, V]) Contains(key K) (ok bool) {
method Peek (line 165) | func (c *cacheImpl[K, V]) Peek(key K) (V, bool) {
method GetExpiration (line 183) | func (c *cacheImpl[K, V]) GetExpiration(key K) (time.Time, bool) {
method Keys (line 193) | func (c *cacheImpl[K, V]) Keys() []K {
method Values (line 201) | func (c *cacheImpl[K, V]) Values() []V {
method Len (line 215) | func (c *cacheImpl[K, V]) Len() int {
method Resize (line 222) | func (c *cacheImpl[K, V]) Resize(size int) int {
method Invalidate (line 241) | func (c *cacheImpl[K, V]) Invalidate(key K) {
method InvalidateFn (line 250) | func (c *cacheImpl[K, V]) InvalidateFn(fn func(key K) bool) {
method Remove (line 262) | func (c *cacheImpl[K, V]) Remove(key K) bool {
method RemoveOldest (line 273) | func (c *cacheImpl[K, V]) RemoveOldest() (key K, value V, ok bool) {
method GetOldest (line 284) | func (c *cacheImpl[K, V]) GetOldest() (key K, value V, ok bool) {
method DeleteExpired (line 294) | func (c *cacheImpl[K, V]) DeleteExpired() {
method Purge (line 308) | func (c *cacheImpl[K, V]) Purge() {
method Stat (line 322) | func (c *cacheImpl[K, V]) Stat() Stats {
method String (line 328) | func (c *cacheImpl[K, V]) String() string {
method keys (line 335) | func (c *cacheImpl[K, V]) keys() []K {
method removeOldest (line 344) | func (c *cacheImpl[K, V]) removeOldest() {
method removeElement (line 352) | func (c *cacheImpl[K, V]) removeElement(e *list.Element) {
type cacheItem (line 363) | type cacheItem struct
FILE: vendor/github.com/go-pkgz/expirable-cache/v3/options.go
type options (line 5) | type options interface
method WithTTL (line 14) | func (c *cacheImpl[K, V]) WithTTL(ttl time.Duration) Cache[K, V] {
method WithMaxKeys (line 21) | func (c *cacheImpl[K, V]) WithMaxKeys(maxKeys int) Cache[K, V] {
method WithLRU (line 27) | func (c *cacheImpl[K, V]) WithLRU() Cache[K, V] {
method WithOnEvicted (line 33) | func (c *cacheImpl[K, V]) WithOnEvicted(fn func(key K, value V)) Cache[K...
FILE: vendor/github.com/go-pkgz/notify/email.go
type SMTPParams (line 15) | type SMTPParams struct
type Email (line 30) | type Email struct
method Send (line 88) | func (e *Email) Send(ctx context.Context, destination, text string) er...
method Schema (line 103) | func (e *Email) Schema() string {
method String (line 108) | func (e *Email) String() string {
method parseDestination (line 120) | func (e *Email) parseDestination(destination string) (email.Params, er...
function NewEmail (line 36) | func NewEmail(smtpParams SMTPParams) *Email {
FILE: vendor/github.com/go-pkgz/notify/interface.go
type Notifier (line 11) | type Notifier interface
function Send (line 18) | func Send(ctx context.Context, notifiers []Notifier, destination, text s...
FILE: vendor/github.com/go-pkgz/notify/slack.go
type Slack (line 14) | type Slack struct
method Send (line 32) | func (s *Slack) Send(ctx context.Context, destination, text string) er...
method Schema (line 52) | func (s *Slack) Schema() string {
method String (line 56) | func (s *Slack) String() string {
method parseDestination (line 63) | func (s *Slack) parseDestination(destination string) (string, slack.At...
method findChannelIDByName (line 88) | func (s *Slack) findChannelIDByName(name string) (string, error) {
function NewSlack (line 19) | func NewSlack(token string, opts ...slack.Option) *Slack {
FILE: vendor/github.com/go-pkgz/notify/telegram.go
type TelegramParams (line 25) | type TelegramParams struct
type Telegram (line 34) | type Telegram struct
method Send (line 116) | func (t *Telegram) Send(ctx context.Context, destination, text string)...
method GetBotUsername (line 210) | func (t *Telegram) GetBotUsername() string {
method AddToken (line 215) | func (t *Telegram) AddToken(token, user, site string, expires time.Tim...
method CheckToken (line 226) | func (t *Telegram) CheckToken(token, user string) (telegram, site stri...
method Run (line 260) | func (t *Telegram) Run(ctx context.Context) {
method ProcessUpdate (line 294) | func (t *Telegram) ProcessUpdate(ctx context.Context, textUpdate strin...
method Schema (line 319) | func (t *Telegram) Schema() string {
method String (line 323) | func (t *Telegram) String() string {
method parseDestination (line 329) | func (t *Telegram) parseDestination(destination string) (chatID, parse...
method getUpdates (line 353) | func (t *Telegram) getUpdates(ctx context.Context) (*TelegramUpdate, e...
method processUpdates (line 376) | func (t *Telegram) processUpdates(ctx context.Context, updates *Telegr...
method sendText (line 415) | func (t *Telegram) sendText(ctx context.Context, recipientID int, msg ...
method botInfo (line 421) | func (t *Telegram) botInfo(ctx context.Context) (*TelegramBotInfo, err...
method Request (line 438) | func (t *Telegram) Request(ctx context.Context, method string, b []byt...
method parseError (line 474) | func (t *Telegram) parseError(r io.Reader, statusCode int) error {
type telegramMsg (line 52) | type telegramMsg struct
type tgAuthRequest (line 57) | type tgAuthRequest struct
type TelegramBotInfo (line 66) | type TelegramBotInfo struct
constant telegramTimeOut (line 70) | telegramTimeOut = 5000 * time.Millisecond
constant telegramAPIPrefix (line 71) | telegramAPIPrefix = "https://api.telegram.org/bot"
constant tgPollInterval (line 72) | tgPollInterval = time.Second * 5
constant tgCleanupInterval (line 73) | tgCleanupInterval = time.Minute * 5
function NewTelegram (line 76) | func NewTelegram(params TelegramParams) (*Telegram, error) {
function TelegramSupportedHTML (line 135) | func TelegramSupportedHTML(htmlText string) string {
function EscapeTelegramText (line 150) | func EscapeTelegramText(text string) string {
function adjustHTMLTags (line 160) | func adjustHTMLTags(htmlText string) string {
type TelegramUpdate (line 195) | type TelegramUpdate struct
FILE: vendor/github.com/go-pkgz/notify/webhook.go
constant webhookTimeOut (line 14) | webhookTimeOut = 5000 * time.Millisecond
type WebhookParams (line 17) | type WebhookParams struct
type Webhook (line 23) | type Webhook struct
method Send (line 51) | func (wh *Webhook) Send(ctx context.Context, destination, text string)...
method Schema (line 85) | func (wh *Webhook) Schema() string {
method String (line 90) | func (wh *Webhook) String() string {
type webhookClient (line 29) | type webhookClient interface
function NewWebhook (line 34) | func NewWebhook(params WebhookParams) *Webhook {
FILE: vendor/github.com/go-pkgz/repeater/repeater.go
type Repeater (line 15) | type Repeater struct
method Do (line 39) | func (r Repeater) Do(ctx context.Context, fun func() error, errs ...er...
type Strategy (line 20) | type Strategy interface
function New (line 25) | func New(strtg strategy.Interface) *Repeater {
function NewDefault (line 34) | func NewDefault(repeats int, delay time.Duration) *Repeater {
FILE: vendor/github.com/go-pkgz/repeater/strategy/backoff.go
type Backoff (line 14) | type Backoff struct
method Start (line 26) | func (b *Backoff) Start(ctx context.Context) <-chan struct{} {
FILE: vendor/github.com/go-pkgz/repeater/strategy/fixed.go
type FixedDelay (line 9) | type FixedDelay struct
method Start (line 17) | func (s *FixedDelay) Start(ctx context.Context) <-chan struct{} {
FILE: vendor/github.com/go-pkgz/repeater/strategy/strategy.go
type Interface (line 11) | type Interface interface
type Once (line 16) | type Once struct
method Start (line 19) | func (s *Once) Start(_ context.Context) <-chan struct{} {
function sleep (line 28) | func sleep(ctx context.Context, duration time.Duration) {
FILE: vendor/github.com/go-pkgz/routegroup/group.go
type Bundle (line 12) | type Bundle struct
method ServeHTTP (line 44) | func (b *Bundle) ServeHTTP(w http.ResponseWriter, r *http.Request) {
method Group (line 91) | func (b *Bundle) Group() *Bundle {
method Mount (line 96) | func (b *Bundle) Mount(basePath string) *Bundle {
method Use (line 108) | func (b *Bundle) Use(middleware func(http.Handler) http.Handler, more ...
method With (line 121) | func (b *Bundle) With(middleware func(http.Handler) http.Handler, more...
method Handle (line 137) | func (b *Bundle) Handle(pattern string, handler http.Handler) {
method HandleFiles (line 150) | func (b *Bundle) HandleFiles(pattern string, root http.FileSystem) {
method HandleFunc (line 174) | func (b *Bundle) HandleFunc(pattern string, handler http.HandlerFunc) {
method Handler (line 180) | func (b *Bundle) Handler(r *http.Request) (h http.Handler, pattern str...
method DisableNotFoundHandler (line 186) | func (b *Bundle) DisableNotFoundHandler() {}
method NotFoundHandler (line 191) | func (b *Bundle) NotFoundHandler(handler http.HandlerFunc) {
method register (line 203) | func (b *Bundle) register(pattern string, handler http.HandlerFunc) {
method Route (line 231) | func (b *Bundle) Route(configureFn func(*Bundle)) {
method HandleRoot (line 248) | func (b *Bundle) HandleRoot(method string, handler http.Handler) {
method HandleRootFunc (line 266) | func (b *Bundle) HandleRootFunc(method string, handler http.HandlerFun...
method wrapMiddleware (line 284) | func (b *Bundle) wrapMiddleware(handler http.Handler) http.Handler {
method clone (line 302) | func (b *Bundle) clone() *Bundle {
method wrapGlobal (line 324) | func (b *Bundle) wrapGlobal(handler http.Handler) http.Handler {
method lockRoot (line 337) | func (b *Bundle) lockRoot() { b.routesLocked = true }
function New (line 34) | func New(mux *http.ServeMux) *Bundle {
function Mount (line 39) | func Mount(mux *http.ServeMux, basePath string) *Bundle {
function Wrap (line 316) | func Wrap(handler http.Handler, mw1 func(http.Handler) http.Handler, mws...
type statusRecorder (line 341) | type statusRecorder struct
method Header (line 345) | func (r *statusRecorder) Header() http.Header {
method Write (line 349) | func (r *statusRecorder) Write([]byte) (int, error) {
method WriteHeader (line 353) | func (r *statusRecorder) WriteHeader(status int) {
FILE: vendor/github.com/go-stack/stack/stack.go
type Call (line 25) | type Call struct
method String (line 54) | func (c Call) String() string {
method MarshalText (line 60) | func (c Call) MarshalText() ([]byte, error) {
method Format (line 92) | func (c Call) Format(s fmt.State, verb rune) {
method Frame (line 155) | func (c Call) Frame() runtime.Frame {
method PC (line 163) | func (c Call) PC() uintptr {
function Caller (line 32) | func Caller(skip int) Call {
type CallStack (line 169) | type CallStack
method String (line 172) | func (cs CallStack) String() string {
method MarshalText (line 184) | func (cs CallStack) MarshalText() ([]byte, error) {
method Format (line 200) | func (cs CallStack) Format(s fmt.State, verb rune) {
method TrimBelow (line 234) | func (cs CallStack) TrimBelow(c Call) CallStack {
method TrimAbove (line 243) | func (cs CallStack) TrimAbove(c Call) CallStack {
method TrimRuntime (line 395) | func (cs CallStack) TrimRuntime() CallStack {
function Trace (line 213) | func Trace() CallStack {
function pkgIndex (line 254) | func pkgIndex(file, funcName string) int {
function pkgFilePath (line 334) | func pkgFilePath(frame *runtime.Frame) string {
function pkgPrefix (line 345) | func pkgPrefix(funcName string) string {
function pathSuffix (line 355) | func pathSuffix(path string) string {
function init (line 366) | func init() {
function inGoroot (line 381) | func inGoroot(c Call) bool {
FILE: vendor/github.com/google/uuid/dce.go
type Domain (line 14) | type Domain
method String (line 70) | func (d Domain) String() string {
constant Person (line 18) | Person = Domain(0)
constant Group (line 19) | Group = Domain(1)
constant Org (line 20) | Org = Domain(2)
function NewDCESecurity (line 32) | func NewDCESecurity(domain Domain, id uint32) (UUID, error) {
function NewDCEPerson (line 46) | func NewDCEPerson() (UUID, error) {
function NewDCEGroup (line 54) | func NewDCEGroup() (UUID, error) {
method Domain (line 60) | func (uuid UUID) Domain() Domain {
method ID (line 66) | func (uuid UUID) ID() uint32 {
FILE: vendor/github.com/google/uuid/hash.go
function NewHash (line 33) | func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID {
function NewMD5 (line 49) | func NewMD5(space UUID, data []byte) UUID {
function NewSHA1 (line 57) | func NewSHA1(space UUID, data []byte) UUID {
FILE: vendor/github.com/google/uuid/marshal.go
method MarshalText (line 10) | func (uuid UUID) MarshalText() ([]byte, error) {
method UnmarshalText (line 17) | func (uuid *UUID) UnmarshalText(data []byte) error {
method MarshalBinary (line 27) | func (uuid UUID) MarshalBinary() ([]byte, error) {
method UnmarshalBinary (line 32) | func (uuid *UUID) UnmarshalBinary(data []byte) error {
FILE: vendor/github.com/google/uuid/node.go
function NodeInterface (line 21) | func NodeInterface() string {
function SetNodeInterface (line 33) | func SetNodeInterface(name string) bool {
function setNodeInterface (line 39) | func setNodeInterface(name string) bool {
function NodeID (line 60) | func NodeID() []byte {
function SetNodeID (line 73) | func SetNodeID(id []byte) bool {
method NodeID (line 86) | func (uuid UUID) NodeID() []byte {
FILE: vendor/github.com/google/uuid/node_js.go
function getHardwareInterface (line 12) | func getHardwareInterface(name string) (string, []byte) { return "", nil }
FILE: vendor/github.com/google/uuid/node_net.go
function getHardwareInterface (line 19) | func getHardwareInterface(name string) (string, []byte) {
FILE: vendor/github.com/google/uuid/null.go
type NullUUID (line 29) | type NullUUID struct
method Scan (line 35) | func (nu *NullUUID) Scan(value interface{}) error {
method Value (line 52) | func (nu NullUUID) Value() (driver.Value, error) {
method MarshalBinary (line 61) | func (nu NullUUID) MarshalBinary() ([]byte, error) {
method UnmarshalBinary (line 70) | func (nu *NullUUID) UnmarshalBinary(data []byte) error {
method MarshalText (line 80) | func (nu NullUUID) MarshalText() ([]byte, error) {
method UnmarshalText (line 89) | func (nu *NullUUID) UnmarshalText(data []byte) error {
method MarshalJSON (line 101) | func (nu NullUUID) MarshalJSON() ([]byte, error) {
method UnmarshalJSON (line 110) | func (nu *NullUUID) UnmarshalJSON(data []byte) error {
FILE: vendor/github.com/google/uuid/sql.go
method Scan (line 15) | func (uuid *UUID) Scan(src interface{}) error {
method Value (line 57) | func (uuid UUID) Value() (driver.Value, error) {
FILE: vendor/github.com/google/uuid/time.go
type Time (line 15) | type Time
method UnixTime (line 35) | func (t Time) UnixTime() (sec, nsec int64) {
constant lillian (line 18) | lillian = 2299160
constant unix (line 19) | unix = 2440587
constant epoch (line 20) | epoch = unix - lillian
constant g1582 (line 21) | g1582 = epoch * 86400
constant g1582ns100 (line 22) | g1582ns100 = g1582 * 10000000
function GetTime (line 45) | func GetTime() (Time, uint16, error) {
function getTime (line 51) | func getTime() (Time, uint16, error) {
function ClockSequence (line 76) | func ClockSequence() int {
function clockSequence (line 82) | func clockSequence() int {
function SetClockSequence (line 91) | func SetClockSequence(seq int) {
function setClockSequence (line 97) | func setClockSequence(seq int) {
method Time (line 112) | func (uuid UUID) Time() Time {
method ClockSequence (line 132) | func (uuid UUID) ClockSequence() int {
FILE: vendor/github.com/google/uuid/util.go
function randomBits (line 12) | func randomBits(b []byte) {
function xtob (line 39) | func xtob(x1, x2 byte) (byte, bool) {
FILE: vendor/github.com/google/uuid/uuid.go
type UUID (line 20) | type UUID
method String (line 244) | func (uuid UUID) String() string {
method URN (line 252) | func (uuid UUID) URN() string {
method Variant (line 272) | func (uuid UUID) Variant() Variant {
method Version (line 286) | func (uuid UUID) Version() Version {
type Version (line 23) | type Version
method String (line 290) | func (v Version) String() string {
type Variant (line 26) | type Variant
method String (line 297) | func (v Variant) String() string {
constant Invalid (line 30) | Invalid = Variant(iota)
constant RFC4122 (line 31) | RFC4122
constant Reserved (line 32) | Reserved
constant Microsoft (line 33) | Microsoft
constant Future (line 34) | Future
constant randPoolSize (line 37) | randPoolSize = 16 * 16
type invalidLengthError (line 47) | type invalidLengthError struct
method Error (line 49) | func (err invalidLengthError) Error() string {
function IsInvalidLengthError (line 54) | func IsInvalidLengthError(err error) bool {
function Parse (line 68) | func Parse(s string) (UUID, error) {
function ParseBytes (line 120) | func ParseBytes(b []byte) (UUID, error) {
function MustParse (line 166) | func MustParse(s string) UUID {
function FromBytes (line 176) | func FromBytes(b []byte) (uuid UUID, err error) {
function Must (line 182) | func Must(uuid UUID, err error) UUID {
function Validate (line 195) | func Validate(s string) error {
function encodeHex (line 259) | func encodeHex(dst []byte, uuid UUID) {
function SetRand (line 319) | func SetRand(r io.Reader) {
function EnableRandPool (line 338) | func EnableRandPool() {
function DisableRandPool (line 348) | func DisableRandPool() {
type UUIDs (line 356) | type UUIDs
method Strings (line 359) | func (uuids UUIDs) Strings() []string {
FILE: vendor/github.com/google/uuid/version1.go
function NewUUID (line 19) | func NewUUID() (UUID, error) {
FILE: vendor/github.com/google/uuid/version4.go
function New (line 13) | func New() UUID {
function NewString (line 21) | func NewString() string {
function NewRandom (line 39) | func NewRandom() (UUID, error) {
function NewRandomFromReader (line 47) | func NewRandomFromReader(r io.Reader) (UUID, error) {
function newRandomFromPool (line 58) | func newRandomFromPool() (UUID, error) {
FILE: vendor/github.com/google/uuid/version6.go
function NewV6 (line 21) | func NewV6() (UUID, error) {
FILE: vendor/github.com/google/uuid/version7.go
function NewV7 (line 23) | func NewV7() (UUID, error) {
function NewV7FromReader (line 35) | func NewV7FromReader(r io.Reader) (UUID, error) {
function makeV7 (line 48) | func makeV7(uuid []byte) {
constant nanoPerMilli (line 83) | nanoPerMilli = 1000000
function getV7Time (line 88) | func getV7Time() (milli, seq int64) {
FILE: vendor/github.com/gorilla/css/scanner/scanner.go
type tokenType (line 16) | type tokenType
method String (line 19) | func (t tokenType) String() string {
type Token (line 24) | type Token struct
method String (line 32) | func (t *Token) String() string {
constant TokenError (line 46) | TokenError tokenType = iota
constant TokenEOF (line 47) | TokenEOF
constant TokenIdent (line 49) | TokenIdent
constant TokenAtKeyword (line 50) | TokenAtKeyword
constant TokenString (line 51) | TokenString
constant TokenHash (line 52) | TokenHash
constant TokenNumber (line 53) | TokenNumber
constant TokenPercentage (line 54) | TokenPercentage
constant TokenDimension (line 55) | TokenDimension
constant TokenURI (line 56) | TokenURI
constant TokenUnicodeRange (line 57) | TokenUnicodeRange
constant TokenCDO (line 58) | TokenCDO
constant TokenCDC (line 59) | TokenCDC
constant TokenS (line 60) | TokenS
constant TokenComment (line 61) | TokenComment
constant TokenFunction (line 62) | TokenFunction
constant TokenIncludes (line 63) | TokenIncludes
constant TokenDashMatch (line 64) | TokenDashMatch
constant TokenPrefixMatch (line 65) | TokenPrefixMatch
constant TokenSuffixMatch (line 66) | TokenSuffixMatch
constant TokenSubstringMatch (line 67) | TokenSubstringMatch
constant TokenChar (line 68) | TokenChar
constant TokenBOM (line 69) | TokenBOM
function init (line 176) | func init() {
function New (line 192) | func New(input string) *Scanner {
type Scanner (line 207) | type Scanner struct
method Next (line 221) | func (s *Scanner) Next() *Token {
method updatePosition (line 320) | func (s *Scanner) updatePosition(text string) {
method emitToken (line 333) | func (s *Scanner) emitToken(t tokenType, v string) *Token {
method emitSimple (line 343) | func (s *Scanner) emitSimple(t tokenType, v string) *Token {
method emitPrefixOrChar (line 355) | func (s *Scanner) emitPrefixOrChar(t tokenType, prefix string) *Token {
FILE: vendor/github.com/gorilla/websocket/client.go
function NewClient (line 40) | func NewClient(netConn net.Conn, u *url.URL, requestHeader http.Header, ...
type Dialer (line 54) | type Dialer struct
method Dial (line 116) | func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn...
method DialContext (line 160) | func (d *Dialer) DialContext(ctx context.Context, urlStr string, reque...
function hostPortNoPort (line 122) | func hostPortNoPort(u *url.URL) (hostPort, hostNoPort string) {
function cloneTLSConfig (line 429) | func cloneTLSConfig(cfg *tls.Config) *tls.Config {
FILE: vendor/github.com/gorilla/websocket/compression.go
constant minCompressionLevel (line 16) | minCompressionLevel = -2
constant maxCompressionLevel (line 17) | maxCompressionLevel = flate.BestCompression
constant defaultCompressionLevel (line 18) | defaultCompressionLevel = 1
function decompressNoContextTakeover (line 28) | func decompressNoContextTakeover(r io.Reader) io.ReadCloser {
function isValidCompressionLevel (line 40) | func isValidCompressionLevel(level int) bool {
function compressNoContextTakeover (line 44) | func compressNoContextTakeover(w io.WriteCloser, level int) io.WriteClos...
type truncWriter (line 58) | type truncWriter struct
method Write (line 64) | func (w *truncWriter) Write(p []byte) (int, error) {
type flateWriteWrapper (line 92) | type flateWriteWrapper struct
method Write (line 98) | func (w *flateWriteWrapper) Write(p []byte) (int, error) {
method Close (line 105) | func (w *flateWriteWrapper) Close() error {
type flateReadWrapper (line 122) | type flateReadWrapper struct
method Read (line 126) | func (r *flateReadWrapper) Read(p []byte) (int, error) {
method Close (line 140) | func (r *flateReadWrapper) Close() error {
FILE: vendor/github.com/gorilla/websocket/conn.go
constant finalBit (line 24) | finalBit = 1 << 7
constant rsv1Bit (line 25) | rsv1Bit = 1 << 6
constant rsv2Bit (line 26) | rsv2Bit = 1 << 5
constant rsv3Bit (line 27) | rsv3Bit = 1 << 4
constant maskBit (line 30) | maskBit = 1 << 7
constant maxFrameHeaderSize (line 32) | maxFrameHeaderSize = 2 + 8 + 4
constant maxControlFramePayloadSize (line 33) | maxControlFramePayloadSize = 125
constant writeWait (line 35) | writeWait = time.Second
constant defaultReadBufferSize (line 37) | defaultReadBufferSize = 4096
constant defaultWriteBufferSize (line 38) | defaultWriteBufferSize = 4096
constant continuationFrame (line 40) | continuationFrame = 0
constant noFrame (line 41) | noFrame = -1
constant CloseNormalClosure (line 46) | CloseNormalClosure = 1000
constant CloseGoingAway (line 47) | CloseGoingAway = 1001
constant CloseProtocolError (line 48) | CloseProtocolError = 1002
constant CloseUnsupportedData (line 49) | CloseUnsupportedData = 1003
constant CloseNoStatusReceived (line 50) | CloseNoStatusReceived = 1005
constant CloseAbnormalClosure (line 51) | CloseAbnormalClosure = 1006
constant CloseInvalidFramePayloadData (line 52) | CloseInvalidFramePayloadData = 1007
constant ClosePolicyViolation (line 53) | ClosePolicyViolation = 1008
constant CloseMessageTooBig (line 54) | CloseMessageTooBig = 1009
constant CloseMandatoryExtension (line 55) | CloseMandatoryExtension = 1010
constant CloseInternalServerErr (line 56) | CloseInternalServerErr = 1011
constant CloseServiceRestart (line 57) | CloseServiceRestart = 1012
constant CloseTryAgainLater (line 58) | CloseTryAgainLater = 1013
constant CloseTLSHandshake (line 59) | CloseTLSHandshake = 1015
constant TextMessage (line 66) | TextMessage = 1
constant BinaryMessage (line 69) | BinaryMessage = 2
constant CloseMessage (line 74) | CloseMessage = 8
constant PingMessage (line 78) | PingMessage = 9
constant PongMessage (line 82) | PongMessage = 10
type netError (line 94) | type netError struct
method Error (line 100) | func (e *netError) Error() string { return e.msg }
method Temporary (line 101) | func (e *netError) Temporary() bool { return e.temporary }
method Timeout (line 102) | func (e *netError) Timeout() bool { return e.timeout }
type CloseError (line 105) | type CloseError struct
method Error (line 113) | func (e *CloseError) Error() string {
function IsCloseError (line 151) | func IsCloseError(err error, codes ...int) bool {
function IsUnexpectedCloseError (line 164) | func IsUnexpectedCloseError(err error, expectedCodes ...int) bool {
function newMaskKey (line 184) | func newMaskKey() [4]byte {
function hideTempErr (line 189) | func hideTempErr(err error) error {
function isControl (line 196) | func isControl(frameType int) bool {
function isData (line 200) | func isData(frameType int) bool {
function isValidReceivedCloseCode (line 223) | func isValidReceivedCloseCode(code int) bool {
type BufferPool (line 229) | type BufferPool interface
type writePoolData (line 239) | type writePoolData struct
type Conn (line 242) | type Conn struct
method setReadRemaining (line 328) | func (c *Conn) setReadRemaining(n int64) error {
method Subprotocol (line 338) | func (c *Conn) Subprotocol() string {
method Close (line 344) | func (c *Conn) Close() error {
method LocalAddr (line 349) | func (c *Conn) LocalAddr() net.Addr {
method RemoteAddr (line 354) | func (c *Conn) RemoteAddr() net.Addr {
method writeFatal (line 360) | func (c *Conn) writeFatal(err error) error {
method read (line 370) | func (c *Conn) read(n int) ([]byte, error) {
method write (line 379) | func (c *Conn) write(frameType int, deadline time.Time, buf0, buf1 []b...
method writeBufs (line 405) | func (c *Conn) writeBufs(bufs ...[]byte) error {
method WriteControl (line 413) | func (c *Conn) WriteControl(messageType int, data []byte, deadline tim...
method beginMessage (line 475) | func (c *Conn) beginMessage(mw *messageWriter, messageType int) error {
method NextWriter (line 518) | func (c *Conn) NextWriter(messageType int) (io.WriteCloser, error) {
method WritePreparedMessage (line 735) | func (c *Conn) WritePreparedMessage(pm *PreparedMessage) error {
method WriteMessage (line 758) | func (c *Conn) WriteMessage(messageType int, data []byte) error {
method SetWriteDeadline (line 787) | func (c *Conn) SetWriteDeadline(t time.Time) error {
method advanceFrame (line 794) | func (c *Conn) advanceFrame() (int, error) {
method handleProtocolError (line 979) | func (c *Conn) handleProtocolError(message string) error {
method NextReader (line 998) | func (c *Conn) NextReader() (messageType int, r io.Reader, err error) {
method ReadMessage (line 1091) | func (c *Conn) ReadMessage() (messageType int, p []byte, err error) {
method SetReadDeadline (line 1105) | func (c *Conn) SetReadDeadline(t time.Time) error {
method SetReadLimit (line 1112) | func (c *Conn) SetReadLimit(limit int64) {
method CloseHandler (line 1117) | func (c *Conn) CloseHandler() func(code int, text string) error {
method SetCloseHandler (line 1135) | func (c *Conn) SetCloseHandler(h func(code int, text string) error) {
method PingHandler (line 1147) | func (c *Conn) PingHandler() func(appData string) error {
method SetPingHandler (line 1158) | func (c *Conn) SetPingHandler(h func(appData string) error) {
method PongHandler (line 1174) | func (c *Conn) PongHandler() func(appData string) error {
method SetPongHandler (line 1185) | func (c *Conn) SetPongHandler(h func(appData string) error) {
method NetConn (line 1195) | func (c *Conn) NetConn() net.Conn {
method UnderlyingConn (line 1202) | func (c *Conn) UnderlyingConn() net.Conn {
method EnableWriteCompression (line 1209) | func (c *Conn) EnableWriteCompression(enable bool) {
method SetCompressionLevel (line 1217) | func (c *Conn) SetCompressionLevel(level int) error {
function newConn (line 285) | func newConn(conn net.Conn, isServer bool, readBufferSize, writeBufferSi...
type messageWriter (line 532) | type messageWriter struct
method endMessage (line 540) | func (w *messageWriter) endMessage(err error) error {
method flushFrame (line 556) | func (w *messageWriter) flushFrame(final bool, extra []byte) error {
method ncopy (line 643) | func (w *messageWriter) ncopy(max int) (int, error) {
method Write (line 657) | func (w *messageWriter) Write(p []byte) (int, error) {
method WriteString (line 684) | func (w *messageWriter) WriteString(p string) (int, error) {
method ReadFrom (line 702) | func (w *messageWriter) ReadFrom(r io.Reader) (nn int64, err error) {
method Close (line 727) | func (w *messageWriter) Close() error {
type messageReader (line 1036) | type messageReader struct
method Read (line 1038) | func (r *messageReader) Read(b []byte) (int, error) {
method Close (line 1085) | func (r *messageReader) Close() error {
function FormatCloseMessage (line 1227) | func FormatCloseMessage(closeCode int, text string) []byte {
FILE: vendor/github.com/gorilla/websocket/join.go
function JoinMessages (line 15) | func JoinMessages(c *Conn, term string) io.Reader {
type joinReader (line 19) | type joinReader struct
method Read (line 25) | func (r *joinReader) Read(p []byte) (int, error) {
FILE: vendor/github.com/gorilla/websocket/json.go
function WriteJSON (line 15) | func WriteJSON(c *Conn, v interface{}) error {
method WriteJSON (line 23) | func (c *Conn) WriteJSON(v interface{}) error {
function ReadJSON (line 40) | func ReadJSON(c *Conn, v interface{}) error {
method ReadJSON (line 49) | func (c *Conn) ReadJSON(v interface{}) error {
FILE: vendor/github.com/gorilla/websocket/mask.go
constant wordSize (line 12) | wordSize = int(unsafe.Sizeof(uintptr(0)))
function maskBytes (line 14) | func maskBytes(key [4]byte, pos int, b []byte) int {
FILE: vendor/github.com/gorilla/websocket/mask_safe.go
function maskBytes (line 10) | func maskBytes(key [4]byte, pos int, b []byte) int {
FILE: vendor/github.com/gorilla/websocket/prepared.go
type PreparedMessage (line 19) | type PreparedMessage struct
method frame (line 62) | func (pm *PreparedMessage) frame(key prepareKey) (int, []byte, error) {
type prepareKey (line 27) | type prepareKey struct
type preparedFrame (line 34) | type preparedFrame struct
function NewPreparedMessage (line 43) | func NewPreparedMessage(messageType int, data []byte) (*PreparedMessage,...
type prepareConn (line 96) | type prepareConn struct
method Write (line 101) | func (pc *prepareConn) Write(p []byte) (int, error) { return pc...
method SetWriteDeadline (line 102) | func (pc *prepareConn) SetWriteDeadline(t time.Time) error { return nil }
FILE: vendor/github.com/gorilla/websocket/proxy.go
type netDialerFunc (line 17) | type netDialerFunc
method Dial (line 19) | func (fn netDialerFunc) Dial(network, addr string) (net.Conn, error) {
function init (line 23) | func init() {
type httpProxyDialer (line 29) | type httpProxyDialer struct
method Dial (line 34) | func (hpd *httpProxyDialer) Dial(network string, addr string) (net.Con...
FILE: vendor/github.com/gorilla/websocket/server.go
type HandshakeError (line 18) | type HandshakeError struct
method Error (line 22) | func (e HandshakeError) Error() string { return e.message }
type Upgrader (line 28) | type Upgrader struct
method returnError (line 77) | func (u *Upgrader) returnError(w http.ResponseWriter, r *http.Request,...
method selectSubprotocol (line 101) | func (u *Upgrader) selectSubprotocol(r *http.Request, responseHeader h...
method Upgrade (line 125) | func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, res...
function checkSameOrigin (line 89) | func checkSameOrigin(r *http.Request) bool {
function Upgrade (line 297) | func Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http...
function Subprotocols (line 311) | func Subprotocols(r *http.Request) []string {
function IsWebSocketUpgrade (line 325) | func IsWebSocketUpgrade(r *http.Request) bool {
function bufioReaderSize (line 331) | func bufioReaderSize(originalReader io.Reader, br *bufio.Reader) int {
type writeHook (line 344) | type writeHook struct
method Write (line 348) | func (wh *writeHook) Write(p []byte) (int, error) {
function bufioWriterBuffer (line 354) | func bufioWriterBuffer(originalWriter io.Writer, bw *bufio.Writer) []byte {
FILE: vendor/github.com/gorilla/websocket/tls_handshake.go
function doHandshake (line 11) | func doHandshake(ctx context.Context, tlsConn *tls.Conn, cfg *tls.Config...
FILE: vendor/github.com/gorilla/websocket/tls_handshake_116.go
function doHandshake (line 11) | func doHandshake(ctx context.Context, tlsConn *tls.Conn, cfg *tls.Config...
FILE: vendor/github.com/gorilla/websocket/util.go
function computeAcceptKey (line 19) | func computeAcceptKey(challengeKey string) string {
function generateChallengeKey (line 26) | func generateChallengeKey() (string, error) {
function skipSpace (line 117) | func skipSpace(s string) (rest string) {
function nextToken (line 129) | func nextToken(s string) (token, rest string) {
function nextTokenOrQuoted (line 141) | func nextTokenOrQuoted(s string) (value string, rest string) {
function equalASCIIFold (line 178) | func equalASCIIFold(s, t string) bool {
function tokenListContainsValue (line 202) | func tokenListContainsValue(header http.Header, name string, value strin...
function parseExtensions (line 228) | func parseExtensions(header http.Header) []map[string]string {
function isValidChallengeKey (line 286) | func isValidChallengeKey(s string) bool {
FILE: vendor/github.com/gorilla/websocket/x_net_proxy.go
type proxy_direct (line 21) | type proxy_direct struct
method Dial (line 26) | func (proxy_direct) Dial(network, addr string) (net.Conn, error) {
type proxy_PerHost (line 32) | type proxy_PerHost struct
method Dial (line 53) | func (p *proxy_PerHost) Dial(network, addr string) (c net.Conn, err er...
method dialerForRequest (line 62) | func (p *proxy_PerHost) dialerForRequest(host string) proxy_Dialer {
method AddFromString (line 100) | func (p *proxy_PerHost) AddFromString(s string) {
method AddIP (line 129) | func (p *proxy_PerHost) AddIP(ip net.IP) {
method AddNetwork (line 136) | func (p *proxy_PerHost) AddNetwork(net *net.IPNet) {
method AddZone (line 142) | func (p *proxy_PerHost) AddZone(zone string) {
method AddHost (line 153) | func (p *proxy_PerHost) AddHost(host string) {
function proxy_NewPerHost (line 44) | func proxy_NewPerHost(defaultDialer, bypass proxy_Dialer) *proxy_PerHost {
type proxy_Dialer (line 161) | type proxy_Dialer interface
type proxy_Auth (line 167) | type proxy_Auth struct
function proxy_FromEnvironment (line 173) | func proxy_FromEnvironment() proxy_Dialer {
function proxy_RegisterDialerType (line 205) | func proxy_RegisterDialerType(scheme string, f func(*url.URL, proxy_Dial...
function proxy_FromURL (line 214) | func proxy_FromURL(u *url.URL, forward proxy_Dialer) (proxy_Dialer, erro...
type proxy_envOnce (line 253) | type proxy_envOnce struct
method Get (line 259) | func (e *proxy_envOnce) Get() string {
method init (line 264) | func (e *proxy_envOnce) init() {
function proxy_SOCKS5 (line 275) | func proxy_SOCKS5(network, addr string, auth *proxy_Auth, forward proxy_...
type proxy_socks5 (line 289) | type proxy_socks5 struct
method Dial (line 323) | func (s *proxy_socks5) Dial(network, addr string) (net.Conn, error) {
method connect (line 344) | func (s *proxy_socks5) connect(conn net.Conn, target string) error {
constant proxy_socks5Version (line 295) | proxy_socks5Version = 5
constant proxy_socks5AuthNone (line 298) | proxy_socks5AuthNone = 0
constant proxy_socks5AuthPassword (line 299) | proxy_socks5AuthPassword = 2
constant proxy_socks5Connect (line 302) | proxy_socks5Connect = 1
constant proxy_socks5IP4 (line 305) | proxy_socks5IP4 = 1
constant proxy_socks5Domain (line 306) | proxy_socks5Domain = 3
constant proxy_socks5IP6 (line 307) | proxy_socks5IP6 = 4
FILE: vendor/github.com/mattn/go-isatty/isatty_bsd.go
function IsTerminal (line 11) | func IsTerminal(fd uintptr) bool {
function IsCygwinTerminal (line 18) | func IsCygwinTerminal(fd uintptr) bool {
FILE: vendor/github.com/mattn/go-isatty/isatty_others.go
function IsTerminal (line 9) | func IsTerminal(fd uintptr) bool {
function IsCygwinTerminal (line 15) | func IsCygwinTerminal(fd uintptr) bool {
FILE: vendor/github.com/mattn/go-isatty/isatty_plan9.go
function IsTerminal (line 11) | func IsTerminal(fd uintptr) bool {
function IsCygwinTerminal (line 21) | func IsCygwinTerminal(fd uintptr) bool {
FILE: vendor/github.com/mattn/go-isatty/isatty_solaris.go
function IsTerminal (line 12) | func IsTerminal(fd uintptr) bool {
function IsCygwinTerminal (line 19) | func IsCygwinTerminal(fd uintptr) bool {
FILE: vendor/github.com/mattn/go-isatty/isatty_tcgets.go
function IsTerminal (line 11) | func IsTerminal(fd uintptr) bool {
function IsCygwinTerminal (line 18) | func IsCygwinTerminal(fd uintptr) bool {
FILE: vendor/github.com/mattn/go-isatty/isatty_windows.go
constant objectNameInfo (line 15) | objectNameInfo uintptr = 1
constant fileNameInfo (line 16) | fileNameInfo = 2
constant fileTypePipe (line 17) | fileTypePipe = 3
function init (line 29) | func init() {
function IsTerminal (line 37) | func IsTerminal(fd uintptr) bool {
function isCygwinPipeName (line 46) | func isCygwinPipeName(name string) bool {
function getFileNameByHandle (line 83) | func getFileNameByHandle(fd uintptr) (string, error) {
function IsCygwinTerminal (line 100) | func IsCygwinTerminal(fd uintptr) bool {
FILE: vendor/github.com/microcosm-cc/bluemonday/css/handlers.go
function multiSplit (line 328) | func multiSplit(value string, seps ...string) []string {
function recursiveCheck (line 340) | func recursiveCheck(value []string, funcs []func(string) bool) bool {
function in (line 352) | func in(value []string, arr []string) bool {
function splitValues (line 367) | func splitValues(value string) []string {
function GetDefaultHandler (line 376) | func GetDefaultHandler(attr string) func(string) bool {
function BaseHandler (line 384) | func BaseHandler(value string) bool {
function AlignContentHandler (line 388) | func AlignContentHandler(value string) bool {
function AlignItemsHandler (line 395) | func AlignItemsHandler(value string) bool {
function AlignSelfHandler (line 402) | func AlignSelfHandler(value string) bool {
function AllHandler (line 409) | func AllHandler(value string) bool {
function AnimationHandler (line 415) | func AnimationHandler(value string) bool {
function AnimationDelayHandler (line 434) | func AnimationDelayHandler(value string) bool {
function AnimationDirectionHandler (line 443) | func AnimationDirectionHandler(value string) bool {
function AnimationDurationHandler (line 449) | func AnimationDurationHandler(value string) bool {
function AnimationFillModeHandler (line 458) | func AnimationFillModeHandler(value string) bool {
function AnimationIterationCountHandler (line 464) | func AnimationIterationCountHandler(value string) bool {
function AnimationNameHandler (line 473) | func AnimationNameHandler(value string) bool {
function AnimationPlayStateHandler (line 477) | func AnimationPlayStateHandler(value string) bool {
function TimingFunctionHandler (line 483) | func TimingFunctionHandler(value string) bool {
function BackfaceVisibilityHandler (line 495) | func BackfaceVisibilityHandler(value string) bool {
function BackgroundHandler (line 501) | func BackgroundHandler(value string) bool {
function BackgroundAttachmentHandler (line 528) | func BackgroundAttachmentHandler(value string) bool {
function BackgroundClipHandler (line 534) | func BackgroundClipHandler(value string) bool {
function BackgroundBlendModeHandler (line 540) | func BackgroundBlendModeHandler(value string) bool {
function ImageHandler (line 547) | func ImageHandler(value string) bool {
function BackgroundOriginHandler (line 556) | func BackgroundOriginHandler(value string) bool {
function BackgroundPositionHandler (line 562) | func BackgroundPositionHandler(value string) bool {
function BackgroundRepeatHandler (line 571) | func BackgroundRepeatHandler(value string) bool {
function BackgroundSizeHandler (line 577) | func BackgroundSizeHandler(value string) bool {
function BorderHandler (line 591) | func BorderHandler(value string) bool {
function BorderSideHandler (line 605) | func BorderSideHandler(value string) bool {
function BorderSideRadiusHandler (line 619) | func BorderSideRadiusHandler(value string) bool {
function BorderSideStyleHandler (line 636) | func BorderSideStyleHandler(value string) bool {
function BorderSideWidthHandler (line 642) | func BorderSideWidthHandler(value string) bool {
function BorderCollapseHandler (line 651) | func BorderCollapseHandler(value string) bool {
function BorderImageHandler (line 657) | func BorderImageHandler(value string) bool {
function BorderImageOutsetHandler (line 673) | func BorderImageOutsetHandler(value string) bool {
function BorderImageRepeatHandler (line 682) | func BorderImageRepeatHandler(value string) bool {
function BorderImageSliceHandler (line 688) | func BorderImageSliceHandler(value string) bool {
function BorderImageWidthHandler (line 703) | func BorderImageWidthHandler(value string) bool {
function BorderRadiusHandler (line 712) | func BorderRadiusHandler(value string) bool {
function BorderSpacingHandler (line 727) | func BorderSpacingHandler(value string) bool {
function BorderStyleHandler (line 742) | func BorderStyleHandler(value string) bool {
function BorderWidthHandler (line 757) | func BorderWidthHandler(value string) bool {
function SideHandler (line 772) | func SideHandler(value string) bool {
function BoxDecorationBreakHandler (line 781) | func BoxDecorationBreakHandler(value string) bool {
function BoxShadowHandler (line 787) | func BoxShadowHandler(value string) bool {
function BoxSizingHandler (line 815) | func BoxSizingHandler(value string) bool {
function BreakBeforeAfterHandler (line 821) | func BreakBeforeAfterHandler(value string) bool {
function BreakInsideHandler (line 827) | func BreakInsideHandler(value string) bool {
function CaptionSideHandler (line 833) | func CaptionSideHandler(value string) bool {
function CaretColorHandler (line 839) | func CaretColorHandler(value string) bool {
function ClearHandler (line 859) | func ClearHandler(value string) bool {
function ClipHandler (line 865) | func ClipHandler(value string) bool {
function ColorHandler (line 874) | func ColorHandler(value string) bool {
function ColumnCountHandler (line 894) | func ColumnCountHandler(value string) bool {
function ColumnFillHandler (line 903) | func ColumnFillHandler(value string) bool {
function ColumnGapHandler (line 909) | func ColumnGapHandler(value string) bool {
function ColumnRuleHandler (line 918) | func ColumnRuleHandler(value string) bool {
function ColumnRuleWidthHandler (line 932) | func ColumnRuleWidthHandler(value string) bool {
function ColumnSpanHandler (line 941) | func ColumnSpanHandler(value string) bool {
function ColumnWidthHandler (line 947) | func ColumnWidthHandler(value string) bool {
function ColumnsHandler (line 956) | func ColumnsHandler(value string) bool {
function CursorHandler (line 969) | func CursorHandler(value string) bool {
function DirectionHandler (line 975) | func DirectionHandler(value string) bool {
function DisplayHandler (line 981) | func DisplayHandler(value string) bool {
function EmptyCellsHandler (line 987) | func EmptyCellsHandler(value string) bool {
function FilterHandler (line 993) | func FilterHandler(value string) bool {
function FlexHandler (line 1030) | func FlexHandler(value string) bool {
function FlexBasisHandler (line 1043) | func FlexBasisHandler(value string) bool {
function FlexDirectionHandler (line 1052) | func FlexDirectionHandler(value string) bool {
function FlexFlowHandler (line 1058) | func FlexFlowHandler(value string) bool {
function FlexGrowHandler (line 1071) | func FlexGrowHandler(value string) bool {
function FlexWrapHandler (line 1080) | func FlexWrapHandler(value string) bool {
function FloatHandler (line 1086) | func FloatHandler(value string) bool {
function FontHandler (line 1092) | func FontHandler(value string) bool {
function FontFamilyHandler (line 1116) | func FontFamilyHandler(value string) bool {
function FontKerningHandler (line 1131) | func FontKerningHandler(value string) bool {
function FontLanguageOverrideHandler (line 1137) | func FontLanguageOverrideHandler(value string) bool {
function FontSizeHandler (line 1141) | func FontSizeHandler(value string) bool {
function FontSizeAdjustHandler (line 1150) | func FontSizeAdjustHandler(value string) bool {
function FontStretchHandler (line 1159) | func FontStretchHandler(value string) bool {
function FontStyleHandler (line 1165) | func FontStyleHandler(value string) bool {
function FontSynthesisHandler (line 1171) | func FontSynthesisHandler(value string) bool {
function FontVariantCapsHandler (line 1177) | func FontVariantCapsHandler(value string) bool {
function FontVariantHandler (line 1183) | func FontVariantHandler(value string) bool {
function FontVariantPositionHandler (line 1189) | func FontVariantPositionHandler(value string) bool {
function FontWeightHandler (line 1195) | func FontWeightHandler(value string) bool {
function GridHandler (line 1201) | func GridHandler(value string) bool {
function GridAreaHandler (line 1223) | func GridAreaHandler(value string) bool {
function GridAutoColumnsHandler (line 1235) | func GridAutoColumnsHandler(value string) bool {
function GridAutoFlowHandler (line 1244) | func GridAutoFlowHandler(value string) bool {
function GridColumnHandler (line 1250) | func GridColumnHandler(value string) bool {
function GridColumnGapHandler (line 1265) | func GridColumnGapHandler(value string) bool {
function LengthHandler (line 1269) | func LengthHandler(value string) bool {
function LineBreakHandler (line 1273) | func LineBreakHandler(value string) bool {
function GridAxisStartEndHandler (line 1279) | func GridAxisStartEndHandler(value string) bool {
function GridGapHandler (line 1291) | func GridGapHandler(value string) bool {
function GridRowHandler (line 1302) | func GridRowHandler(value string) bool {
function GridTemplateHandler (line 1313) | func GridTemplateHandler(value string) bool {
function GridTemplateAreasHandler (line 1329) | func GridTemplateAreasHandler(value string) bool {
function GridTemplateColumnsHandler (line 1337) | func GridTemplateColumnsHandler(value string) bool {
function GridTemplateRowsHandler (line 1352) | func GridTemplateRowsHandler(value string) bool {
function HangingPunctuationHandler (line 1367) | func HangingPunctuationHandler(value string) bool {
function HeightHandler (line 1373) | func HeightHandler(value string) bool {
function HyphensHandler (line 1382) | func HyphensHandler(value string) bool {
function ImageRenderingHandler (line 1388) | func ImageRenderingHandler(value string) bool {
function IsolationHandler (line 1394) | func IsolationHandler(value string) bool {
function JustifyContentHandler (line 1400) | func JustifyContentHandler(value string) bool {
function LetterSpacingHandler (line 1406) | func LetterSpacingHandler(value string) bool {
function LineHeightHandler (line 1415) | func LineHeightHandler(value string) bool {
function ListStyleHandler (line 1424) | func ListStyleHandler(value string) bool {
function ListStylePositionHandler (line 1438) | func ListStylePositionHandler(value string) bool {
function ListStyleTypeHandler (line 1444) | func ListStyleTypeHandler(value string) bool {
function MarginHandler (line 1450) | func MarginHandler(value string) bool {
function MarginSideHandler (line 1462) | func MarginSideHandler(value string) bool {
function MaxHeightWidthHandler (line 1471) | func MaxHeightWidthHandler(value string) bool {
function MinHeightWidthHandler (line 1480) | func MinHeightWidthHandler(value string) bool {
function MixBlendModeHandler (line 1489) | func MixBlendModeHandler(value string) bool {
function ObjectFitHandler (line 1495) | func ObjectFitHandler(value string) bool {
function ObjectPositionHandler (line 1501) | func ObjectPositionHandler(value string) bool {
function OpacityHandler (line 1516) | func OpacityHandler(value string) bool {
function OrderHandler (line 1525) | func OrderHandler(value string) bool {
function OutlineHandler (line 1534) | func OutlineHandler(value string) bool {
function OutlineOffsetHandler (line 1548) | func OutlineOffsetHandler(value string) bool {
function OutlineStyleHandler (line 1557) | func OutlineStyleHandler(value string) bool {
function OutlineWidthHandler (line 1563) | func OutlineWidthHandler(value string) bool {
function OverflowHandler (line 1572) | func OverflowHandler(value string) bool {
function OverflowXYHandler (line 1578) | func OverflowXYHandler(value string) bool {
function OverflowWrapHandler (line 1584) | func OverflowWrapHandler(value string) bool {
function OrphansHandler (line 1590) | func OrphansHandler(value string) bool {
function PaddingHandler (line 1594) | func PaddingHandler(value string) bool {
function PaddingSideHandler (line 1609) | func PaddingSideHandler(value string) bool {
function PageBreakBeforeAfterHandler (line 1618) | func PageBreakBeforeAfterHandler(value string) bool {
function PageBreakInsideHandler (line 1624) | func PageBreakInsideHandler(value string) bool {
function PerspectiveHandler (line 1630) | func PerspectiveHandler(value string) bool {
function PerspectiveOriginHandler (line 1639) | func PerspectiveOriginHandler(value string) bool {
function PointerEventsHandler (line 1658) | func PointerEventsHandler(value string) bool {
function PositionHandler (line 1664) | func PositionHandler(value string) bool {
function QuotesHandler (line 1670) | func QuotesHandler(value string) bool {
function ResizeHandler (line 1679) | func ResizeHandler(value string) bool {
function ScrollBehaviorHandler (line 1685) | func ScrollBehaviorHandler(value string) bool {
function TabSizeHandler (line 1691) | func TabSizeHandler(value string) bool {
function TableLayoutHandler (line 1700) | func TableLayoutHandler(value string) bool {
function TextAlignHandler (line 1706) | func TextAlignHandler(value string) bool {
function TextAlignLastHandler (line 1712) | func TextAlignLastHandler(value string) bool {
function TextCombineUprightHandler (line 1718) | func TextCombineUprightHandler(value string) bool {
function TextDecorationHandler (line 1727) | func TextDecorationHandler(value string) bool {
function TextDecorationLineHandler (line 1741) | func TextDecorationLineHandler(value string) bool {
function TextDecorationStyleHandler (line 1747) | func TextDecorationStyleHandler(value string) bool {
function TextIndentHandler (line 1753) | func TextIndentHandler(value string) bool {
function TextJustifyHandler (line 1762) | func TextJustifyHandler(value string) bool {
function TextOverflowHandler (line 1768) | func TextOverflowHandler(value string) bool {
function TextOrientationHandler (line 1777) | func TextOrientationHandler(value string) bool {
function TextShadowHandler (line 1783) | func TextShadowHandler(value string) bool {
function TextTransformHandler (line 1811) | func TextTransformHandler(value string) bool {
function TransformHandler (line 1817) | func TransformHandler(value string) bool {
function TransformOriginHandler (line 1864) | func TransformOriginHandler(value string) bool {
function TransformStyleHandler (line 1891) | func TransformStyleHandler(value string) bool {
function TransitionHandler (line 1897) | func TransitionHandler(value string) bool {
function TransitionDelayHandler (line 1913) | func TransitionDelayHandler(value string) bool {
function TransitionDurationHandler (line 1922) | func TransitionDurationHandler(value string) bool {
function TransitionPropertyHandler (line 1931) | func TransitionPropertyHandler(value string) bool {
function UnicodeBidiHandler (line 1940) | func UnicodeBidiHandler(value string) bool {
function UserSelectHandler (line 1946) | func UserSelectHandler(value string) bool {
function VerticalAlignHandler (line 1952) | func VerticalAlignHandler(value string) bool {
function VisiblityHandler (line 1961) | func VisiblityHandler(value string) bool {
function WhiteSpaceHandler (line 1967) | func WhiteSpaceHandler(value string) bool {
function WidthHandler (line 1973) | func WidthHandler(value string) bool {
function WordSpacingHandler (line 1982) | func WordSpacingHandler(value string) bool {
function WordBreakHandler (line 1991) | func WordBreakHandler(value string) bool {
function WordWrapHandler (line 1997) | func WordWrapHandler(value string) bool {
function WritingModeHandler (line 2003) | func WritingModeHandler(value string) bool {
function ZIndexHandler (line 2009) | func ZIndexHandler(value string) bool {
FILE: vendor/github.com/microcosm-cc/bluemonday/helpers.go
method AllowStandardURLs (line 128) | func (p *Policy) AllowStandardURLs() {
method AllowStandardAttributes (line 145) | func (p *Policy) AllowStandardAttributes() {
method AllowStyling (line 170) | func (p *Policy) AllowStyling() {
method AllowImages (line 179) | func (p *Policy) AllowImages() {
method AllowDataURIImages (line 206) | func (p *Policy) AllowDataURIImages() {
method AllowLists (line 232) | func (p *Policy) AllowLists() {
method AllowTables (line 246) | func (p *Policy) AllowTables() {
method AllowIFrames (line 296) | func (p *Policy) AllowIFrames(vals ...SandboxValue) {
FILE: vendor/github.com/microcosm-cc/bluemonday/policies.go
function StrictPolicy (line 38) | func StrictPolicy() *Policy {
function StripTagsPolicy (line 43) | func StripTagsPolicy() *Policy {
function UGCPolicy (line 54) | func UGCPolicy() *Policy {
FILE: vendor/github.com/microcosm-cc/bluemonday/policy.go
type Policy (line 47) | type Policy struct
method init (line 230) | func (p *Policy) init() {
method AllowAttrs (line 266) | func (p *Policy) AllowAttrs(attrNames ...string) *attrPolicyBuilder {
method AllowDataAttributes (line 293) | func (p *Policy) AllowDataAttributes() {
method AllowComments (line 309) | func (p *Policy) AllowComments() {
method AllowNoAttrs (line 317) | func (p *Policy) AllowNoAttrs() *attrPolicyBuilder {
method AllowStyles (line 431) | func (p *Policy) AllowStyles(propertyNames ...string) *stylePolicyBuil...
method AllowElements (line 558) | func (p *Policy) AllowElements(names ...string) *Policy {
method AllowElementsMatching (line 574) | func (p *Policy) AllowElementsMatching(regex *regexp.Regexp) *Policy {
method AllowURLSchemesMatching (line 584) | func (p *Policy) AllowURLSchemesMatching(r *regexp.Regexp) *Policy {
method RewriteSrc (line 611) | func (p *Policy) RewriteSrc(fn urlRewriter) *Policy {
method RequireNoFollowOnLinks (line 620) | func (p *Policy) RequireNoFollowOnLinks(require bool) *Policy {
method RequireNoFollowOnFullyQualifiedLinks (line 634) | func (p *Policy) RequireNoFollowOnFullyQualifiedLinks(require bool) *P...
method RequireNoReferrerOnLinks (line 646) | func (p *Policy) RequireNoReferrerOnLinks(require bool) *Policy {
method RequireNoReferrerOnFullyQualifiedLinks (line 660) | func (p *Policy) RequireNoReferrerOnFullyQualifiedLinks(require bool) ...
method RequireCrossOriginAnonymous (line 671) | func (p *Policy) RequireCrossOriginAnonymous(require bool) *Policy {
method AddTargetBlankToFullyQualifiedLinks (line 683) | func (p *Policy) AddTargetBlankToFullyQualifiedLinks(require bool) *Po...
method RequireParseableURLs (line 700) | func (p *Policy) RequireParseableURLs(require bool) *Policy {
method AllowRelativeURLs (line 710) | func (p *Policy) AllowRelativeURLs(require bool) *Policy {
method AllowURLSchemes (line 720) | func (p *Policy) AllowURLSchemes(schemes ...string) *Policy {
method AllowURLSchemeWithCustomPolicy (line 739) | func (p *Policy) AllowURLSchemeWithCustomPolicy(
method RequireSandboxOnIFrame (line 757) | func (p *Policy) RequireSandboxOnIFrame(vals ...SandboxValue) {
method AddSpaceWhenStrippingTag (line 817) | func (p *Policy) AddSpaceWhenStrippingTag(allow bool) *Policy {
method SkipElementsContent (line 826) | func (p *Policy) SkipElementsContent(names ...string) *Policy {
method AllowElementsContent (line 843) | func (p *Policy) AllowElementsContent(names ...string) *Policy {
method AllowUnsafe (line 865) | func (p *Policy) AllowUnsafe(allowUnsafe bool) *Policy {
method addDefaultElementsWithoutAttrs (line 875) | func (p *Policy) addDefaultElementsWithoutAttrs() {
method addDefaultSkipElementContent (line 976) | func (p *Policy) addDefaultSkipElementContent() {
type attrPolicy (line 168) | type attrPolicy struct
type stylePolicy (line 175) | type stylePolicy struct
type attrPolicyBuilder (line 189) | type attrPolicyBuilder struct
method AllowNoAttrs (line 332) | func (abp *attrPolicyBuilder) AllowNoAttrs() *attrPolicyBuilder {
method Matching (line 341) | func (abp *attrPolicyBuilder) Matching(regex *regexp.Regexp) *attrPoli...
method OnElements (line 350) | func (abp *attrPolicyBuilder) OnElements(elements ...string) *Policy {
method OnElementsMatching (line 383) | func (abp *attrPolicyBuilder) OnElementsMatching(regex *regexp.Regexp)...
method Globally (line 407) | func (abp *attrPolicyBuilder) Globally() *Policy {
type stylePolicyBuilder (line 197) | type stylePolicyBuilder struct
method Matching (line 448) | func (spb *stylePolicyBuilder) Matching(regex *regexp.Regexp) *stylePo...
method MatchingEnum (line 457) | func (spb *stylePolicyBuilder) MatchingEnum(enum ...string) *stylePoli...
method MatchingHandler (line 466) | func (spb *stylePolicyBuilder) MatchingHandler(handler func(string) bo...
method OnElements (line 475) | func (spb *stylePolicyBuilder) OnElements(elements ...string) *Policy {
method OnElementsMatching (line 505) | func (spb *stylePolicyBuilder) OnElementsMatching(regex *regexp.Regexp...
method Globally (line 531) | func (spb *stylePolicyBuilder) Globally() *Policy {
type urlPolicy (line 206) | type urlPolicy
type urlRewriter (line 208) | type urlRewriter
type SandboxValue (line 210) | type SandboxValue
constant SandboxAllowDownloads (line 213) | SandboxAllowDownloads SandboxValue = iota
constant SandboxAllowDownloadsWithoutUserActivation (line 214) | SandboxAllowDownloadsWithoutUserActivation
constant SandboxAllowForms (line 215) | SandboxAllowForms
constant SandboxAllowModals (line 216) | SandboxAllowModals
constant SandboxAllowOrientationLock (line 217) | SandboxAllowOrientationLock
constant SandboxAllowPointerLock (line 218) | SandboxAllowPointerLock
constant SandboxAllowPopups (line 219) | SandboxAllowPopups
constant SandboxAllowPopupsToEscapeSandbox (line 220) | SandboxAllowPopupsToEscapeSandbox
constant SandboxAllowPresentation (line 221) | SandboxAllowPresentation
constant SandboxAllowSameOrigin (line 222) | SandboxAllowSameOrigin
constant SandboxAllowScripts (line 223) | SandboxAllowScripts
constant SandboxAllowStorageAccessByUserActivation (line 224) | SandboxAllowStorageAccessByUserActivation
constant SandboxAllowTopNavigation (line 225) | SandboxAllowTopNavigation
constant SandboxAllowTopNavigationByUserActivation (line 226) | SandboxAllowTopNavigationByUserActivation
function NewPolicy (line 250) | func NewPolicy() *Policy {
FILE: vendor/github.com/microcosm-cc/bluemonday/sanitize.go
method Sanitize (line 60) | func (p *Policy) Sanitize(s string) string {
method SanitizeBytes (line 74) | func (p *Policy) SanitizeBytes(b []byte) []byte {
method SanitizeReader (line 87) | func (p *Policy) SanitizeReader(r io.Reader) *bytes.Buffer {
method SanitizeReaderToWriter (line 94) | func (p *Policy) SanitizeReaderToWriter(r io.Reader, w io.Writer) error {
type Query (line 99) | type Query struct
function parseQuery (line 105) | func parseQuery(query string) (values []Query, err error) {
function encodeQueries (line 149) | func encodeQueries(queries []Query) string {
function sanitizedURL (line 164) | func sanitizedURL(val string) (string, error) {
method sanitizeWithBuff (line 186) | func (p *Policy) sanitizeWithBuff(r io.Reader) *bytes.Buffer {
type asStringWriter (line 194) | type asStringWriter struct
method WriteString (line 198) | func (a *asStringWriter) WriteString(s string) (int, error) {
method sanitize (line 202) | func (p *Policy) sanitize(r io.Reader, w io.Writer) error {
method sanitizeAttrs (line 459) | func (p *Policy) sanitizeAttrs(
method sanitizeStyles (line 813) | func (p *Policy) sanitizeStyles(attr html.Attribute, elementName string)...
method allowNoAttrs (line 898) | func (p *Policy) allowNoAttrs(elementName string) bool {
method validURL (line 911) | func (p *Policy) validURL(rawurl string) (string, bool) {
function linkable (line 984) | func linkable(elementName string) bool {
function stringInSlice (line 1001) | func stringInSlice(needle string, haystack []string) bool {
function isDataAttribute (line 1010) | func isDataAttribute(val string) bool {
function removeUnicode (line 1029) | func removeUnicode(value string) string {
method matchRegex (line 1060) | func (p *Policy) matchRegex(elementName string) (map[string][]attrPolicy...
function normaliseElementName (line 1080) | func normaliseElementName(str string) string {
type stringWriterWriter (line 1093) | type stringWriterWriter interface
FILE: vendor/github.com/ncruces/go-strftime/parser.go
type parser (line 5) | type parser struct
method parse (line 10) | func (p *parser) parse(fmt string) error {
method literals (line 80) | func (p *parser) literals(literal string) error {
type literalErr (line 89) | type literalErr
method Error (line 91) | func (e literalErr) Error() string {
type formatError (line 95) | type formatError struct
method Error (line 100) | func (e formatError) Error() string {
method setDirective (line 104) | func (e *formatError) setDirective(str string, i, j int) {
FILE: vendor/github.com/ncruces/go-strftime/specifiers.go
function goLayout (line 6) | func goLayout(spec, flag byte, parsing bool) string {
function uts35Pattern (line 129) | func uts35Pattern(spec, flag byte) string {
function okModifier (line 233) | func okModifier(mod, spec byte) bool {
FILE: vendor/github.com/ncruces/go-strftime/strftime.go
function Format (line 11) | func Format(fmt string, t time.Time) string {
function AppendFormat (line 18) | func AppendFormat(dst []byte, fmt string, t time.Time) []byte {
function Parse (line 158) | func Parse(fmt, value string) (time.Time, error) {
function Layout (line 177) | func Layout(fmt string) (string, error) {
function layout (line 181) | func layout(fmt string, parsing bool) (string, error) {
function UTS35 (line 245) | func UTS35(fmt string) (string, error) {
function buffer (line 286) | func buffer(format string) (buf []byte) {
function year (line 298) | func year(y int) time.Time {
function appendWeekNumber (line 302) | func appendWeekNumber(dst []byte, t time.Time, flag byte, sunday bool) [...
function append12Hour (line 312) | func append12Hour(dst []byte, t time.Time, flag byte) []byte {
function appendInt1 (line 322) | func appendInt1(dst []byte, i int) []byte {
function appendInt2 (line 326) | func appendInt2(dst []byte, i int, flag byte) []byte {
constant smallsString (line 336) | smallsString = "" +
FILE: vendor/github.com/pmezard/go-difflib/difflib/difflib.go
function min (line 26) | func min(a, b int) int {
function max (line 33) | func max(a, b int) int {
function calculateRatio (line 40) | func calculateRatio(matches, length int) float64 {
type Match (line 47) | type Match struct
type OpCode (line 53) | type OpCode struct
type SequenceMatcher (line 87) | type SequenceMatcher struct
method SetSeqs (line 115) | func (m *SequenceMatcher) SetSeqs(a, b []string) {
method SetSeq1 (line 129) | func (m *SequenceMatcher) SetSeq1(a []string) {
method SetSeq2 (line 140) | func (m *SequenceMatcher) SetSeq2(b []string) {
method chainB (line 151) | func (m *SequenceMatcher) chainB() {
method isBJunk (line 192) | func (m *SequenceMatcher) isBJunk(s string) bool {
method findLongestMatch (line 221) | func (m *SequenceMatcher) findLongestMatch(alo, ahi, blo, bhi int) Mat...
method GetMatchingBlocks (line 305) | func (m *SequenceMatcher) GetMatchingBlocks() []Match {
method GetOpCodes (line 373) | func (m *SequenceMatcher) GetOpCodes() []OpCode {
method GetGroupedOpCodes (line 413) | func (m *SequenceMatcher) GetGroupedOpCodes(n int) [][]OpCode {
method Ratio (line 465) | func (m *SequenceMatcher) Ratio() float64 {
method QuickRatio (line 477) | func (m *SequenceMatcher) QuickRatio() float64 {
method RealQuickRatio (line 509) | func (m *SequenceMatcher) RealQuickRatio() float64 {
function NewMatcher (line 100) | func NewMatcher(a, b []string) *SequenceMatcher {
function NewMatcherWithJunk (line 106) | func NewMatcherWithJunk(a, b []string, autoJunk bool,
function formatRangeUnified (line 515) | func formatRangeUnified(start, stop int) string {
type UnifiedDiff (line 529) | type UnifiedDiff struct
function WriteUnifiedDiff (line 559) | func WriteUnifiedDiff(writer io.Writer, diff UnifiedDiff) error {
function GetUnifiedDiffString (line 635) | func GetUnifiedDiffString(diff UnifiedDiff) (string, error) {
function formatRangeContext (line 642) | func formatRangeContext(start, stop int) string {
type ContextDiff (line 655) | type ContextDiff
function WriteContextDiff (line 674) | func WriteContextDiff(writer io.Writer, diff ContextDiff) error {
function GetContextDiffString (line 760) | func GetContextDiffString(diff ContextDiff) (string, error) {
function SplitLines (line 768) | func SplitLines(s string) []string {
FILE: vendor/github.com/remyoudompheng/bigfft/arith_decl.go
function addVV (line 15) | func addVV(z, x, y []Word) (c Word)
function subVV (line 18) | func subVV(z, x, y []Word) (c Word)
function addVW (line 21) | func addVW(z, x []Word, y Word) (c Word)
function subVW (line 24) | func subVW(z, x []Word, y Word) (c Word)
function shlVU (line 27) | func shlVU(z, x []Word, s uint) (c Word)
function mulAddVWW (line 30) | func mulAddVWW(z, x []Word, y, r Word) (c Word)
function addMulVVW (line 33) | func addMulVVW(z, x []Word, y Word) (c Word)
FILE: vendor/github.com/remyoudompheng/bigfft/fermat.go
type fermat (line 12) | type fermat
method String (line 14) | func (n fermat) String() string { return nat(n).String() }
method norm (line 16) | func (z fermat) norm() {
method Shift (line 43) | func (z fermat) Shift(x fermat, k int) {
method ShiftHalf (line 101) | func (z fermat) ShiftHalf(x fermat, k int, tmp fermat) {
method Add (line 116) | func (z fermat) Add(x, y fermat) fermat {
method Sub (line 126) | func (z fermat) Sub(x, y fermat) fermat {
method Mul (line 144) | func (z fermat) Mul(x, y fermat) fermat {
function basicMul (line 206) | func basicMul(z, x, y fermat) {
FILE: vendor/github.com/remyoudompheng/bigfft/fft.go
constant _W (line 12) | _W = int(unsafe.Sizeof(big.Word(0)) * 8)
type nat (line 14) | type nat
method String (line 16) | func (n nat) String() string {
function Mul (line 32) | func Mul(x, y *big.Int) *big.Int {
function mulFFT (line 41) | func mulFFT(x, y *big.Int) *big.Int {
function fftmul (line 55) | func fftmul(x, y nat) nat {
function fftSize (line 74) | func fftSize(x, y nat) (k uint, m int) {
function valueSize (line 95) | func valueSize(k uint, m int, extra uint) int {
type poly (line 111) | type poly struct
method Int (line 136) | func (p *poly) Int() nat {
method Mul (line 169) | func (p *poly) Mul(q *poly) poly {
method Transform (line 192) | func (p *poly) Transform(n int) polValues {
method NTransform (line 236) | func (p *poly) NTransform(n int) polValues {
function polyFromNat (line 119) | func polyFromNat(x nat, k uint, m int) poly {
function trim (line 158) | func trim(n nat) nat {
type polValues (line 184) | type polValues struct
method InvTransform (line 212) | func (v *polValues) InvTransform() poly {
method InvNTransform (line 275) | func (v *polValues) InvNTransform() poly {
method Mul (line 358) | func (p *polValues) Mul(q *polValues) (r polValues) {
function fourier (line 302) | func fourier(dst []fermat, src []fermat, backward bool, n int, k uint) {
FILE: vendor/github.com/remyoudompheng/bigfft/scan.go
function FromDecimalString (line 11) | func FromDecimalString(s string) *big.Int {
type scanner (line 18) | type scanner struct
method chunkSize (line 23) | func (s *scanner) chunkSize(size int) (int, *big.Int) {
method power (line 35) | func (s *scanner) power(k uint) *big.Int {
method scan (line 51) | func (s *scanner) scan(z *big.Int, str string) {
constant quadraticScanThreshold (line 70) | quadraticScanThreshold = 1232
FILE: vendor/github.com/stretchr/testify/assert/assertion_compare.go
type compareResult (line 13) | type compareResult
constant compareLess (line 16) | compareLess compareResult = iota - 1
constant compareEqual (line 17) | compareEqual
constant compareGreater (line 18) | compareGreater
function compare (line 45) | func compare(obj1, obj2 interface{}, kind reflect.Kind) (compareResult, ...
function Greater (line 389) | func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...i...
function GreaterOrEqual (line 403) | func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndAr...
function Less (line 416) | func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...inte...
function LessOrEqual (line 430) | func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...
function Positive (line 442) | func Positive(t TestingT, e interface{}, msgAndArgs ...interface{}) bool {
function Negative (line 455) | func Negative(t TestingT, e interface{}, msgAndArgs ...interface{}) bool {
function compareTwoValues (line 464) | func compareTwoValues(t TestingT, e1 interface{}, e2 interface{}, allowe...
function containsValue (line 487) | func containsValue(values []compareResult, value compareResult) bool {
FILE: vendor/github.com/stretchr/testify/assert/assertion_format.go
function Conditionf (line 12) | func Conditionf(t TestingT, comp Comparison, msg string, args ...interfa...
function Containsf (line 25) | func Containsf(t TestingT, s interface{}, contains interface{}, msg stri...
function DirExistsf (line 34) | func DirExistsf(t TestingT, path string, msg string, args ...interface{}...
function ElementsMatchf (line 46) | func ElementsMatchf(t TestingT, listA interface{}, listB interface{}, ms...
function Emptyf (line 66) | func Emptyf(t TestingT, object interface{}, msg string, args ...interfac...
function Equalf (line 80) | func Equalf(t TestingT, expected interface{}, actual interface{}, msg st...
function EqualErrorf (line 92) | func EqualErrorf(t TestingT, theError error, errString string, msg strin...
function EqualExportedValuesf (line 109) | func EqualExportedValuesf(t TestingT, expected interface{}, actual inter...
function EqualValuesf (line 120) | func EqualValuesf(t TestingT, expected interface{}, actual interface{}, ...
function Errorf (line 131) | func Errorf(t TestingT, err error, msg string, args ...interface{}) bool {
function ErrorAsf (line 140) | func ErrorAsf(t TestingT, err error, target interface{}, msg string, arg...
function ErrorContainsf (line 152) | func ErrorContainsf(t TestingT, theError error, contains string, msg str...
function ErrorIsf (line 161) | func ErrorIsf(t TestingT, err error, target error, msg string, args ...i...
function Eventuallyf (line 172) | func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duratio...
function EventuallyWithTf (line 197) | func EventuallyWithTf(t TestingT, condition func(collect *CollectT), wai...
function Exactlyf (line 207) | func Exactlyf(t TestingT, expected interface{}, actual interface{}, msg ...
function Failf (line 215) | func Failf(t TestingT, failureMessage string, msg string, args ...interf...
function FailNowf (line 223) | func FailNowf(t TestingT, failureMessage string, msg string, args ...int...
function Falsef (line 233) | func Falsef(t TestingT, value bool, msg string, args ...interface{}) bool {
function FileExistsf (line 242) | func FileExistsf(t TestingT, path string, msg string, args ...interface{...
function Greaterf (line 254) | func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, ar...
function GreaterOrEqualf (line 267) | func GreaterOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg str...
function HTTPBodyContainsf (line 280) | func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method stri...
function HTTPBodyNotContainsf (line 293) | func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method s...
function HTTPErrorf (line 305) | func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url...
function HTTPRedirectf (line 317) | func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, ...
function HTTPStatusCodef (line 329) | func HTTPStatusCodef(t TestingT, handler http.HandlerFunc, method string...
function HTTPSuccessf (line 341) | func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, u...
function Implementsf (line 351) | func Implementsf(t TestingT, interfaceObject interface{}, object interfa...
function InDeltaf (line 361) | func InDeltaf(t TestingT, expected interface{}, actual interface{}, delt...
function InDeltaMapValuesf (line 369) | func InDeltaMapValuesf(t TestingT, expected interface{}, actual interfac...
function InDeltaSlicef (line 377) | func InDeltaSlicef(t TestingT, expected interface{}, actual interface{},...
function InEpsilonf (line 385) | func InEpsilonf(t TestingT, expected interface{}, actual interface{}, ep...
function InEpsilonSlicef (line 393) | func InEpsilonSlicef(t TestingT, expected interface{}, actual interface{...
function IsDecreasingf (line 405) | func IsDecreasingf(t TestingT, object interface{}, msg string, args ...i...
function IsIncreasingf (line 417) | func IsIncreasingf(t TestingT, object interface{}, msg string, args ...i...
function IsNonDecreasingf (line 429) | func IsNonDecreasingf(t TestingT, object interface{}, msg string, args ....
function IsNonIncreasingf (line 441) | func IsNonIncreasingf(t TestingT, object interface{}, msg string, args ....
function IsNotTypef (line 451) | func IsNotTypef(t TestingT, theType interface{}, object interface{}, msg...
function IsTypef (line 461) | func IsTypef(t TestingT, expectedType interface{}, object interface{}, m...
function JSONEqf (line 471) | func JSONEqf(t TestingT, expected string, actual string, msg string, arg...
function Lenf (line 482) | func Lenf(t TestingT, object interface{}, length int, msg string, args ....
function Lessf (line 494) | func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...
function LessOrEqualf (line 507) | func LessOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string...
function Negativef (line 518) | func Negativef(t TestingT, e interface{}, msg string, args ...interface{...
function Neverf (line 529) | func Neverf(t TestingT, condition func() bool, waitFor time.Duration, ti...
function Nilf (line 539) | func Nilf(t TestingT, object interface{}, msg string, args ...interface{...
function NoDirExistsf (line 548) | func NoDirExistsf(t TestingT, path string, msg string, args ...interface...
function NoErrorf (line 561) | func NoErrorf(t TestingT, err error, msg string, args ...interface{}) bo...
function NoFileExistsf (line 570) | func NoFileExistsf(t TestingT, path string, msg string, args ...interfac...
function NotContainsf (line 583) | func NotContainsf(t TestingT, s interface{}, contains interface{}, msg s...
function NotElementsMatchf (line 600) | func NotElementsMatchf(t TestingT, listA interface{}, listB interface{},...
function NotEmptyf (line 612) | func NotEmptyf(t TestingT, object interface{}, msg string, args ...inter...
function NotEqualf (line 625) | func NotEqualf(t TestingT, expected interface{}, actual interface{}, msg...
function NotEqualValuesf (line 635) | func NotEqualValuesf(t TestingT, expected interface{}, actual interface{...
function NotErrorAsf (line 644) | func NotErrorAsf(t TestingT, err error, target interface{}, msg string, ...
function NotErrorIsf (line 653) | func NotErrorIsf(t TestingT, err error, target error, msg string, args ....
function NotImplementsf (line 663) | func NotImplementsf(t TestingT, interfaceObject interface{}, object inte...
function NotNilf (line 673) | func NotNilf(t TestingT, object interface{}, msg string, args ...interfa...
function NotPanicsf (line 683) | func NotPanicsf(t TestingT, f PanicTestFunc, msg string, args ...interfa...
function NotRegexpf (line 694) | func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string,...
function NotSamef (line 707) | func NotSamef(t TestingT, expected interface{}, actual interface{}, msg ...
function NotSubsetf (line 723) | func NotSubsetf(t TestingT, list interface{}, subset interface{}, msg st...
function NotZerof (line 731) | func NotZerof(t TestingT, i interface{}, msg string, args ...interface{}...
function Panicsf (line 741) | func Panicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{...
function PanicsWithErrorf (line 753) | func PanicsWithErrorf(t TestingT, errString string, f PanicTestFunc, msg...
function PanicsWithValuef (line 764) | func PanicsWithValuef(t TestingT, expected interface{}, f PanicTestFunc,...
function Positivef (line 775) | func Positivef(t TestingT, e interface{}, msg string, args ...interface{...
function Regexpf (line 786) | func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, ar...
function Samef (line 799) | func Samef(t TestingT, expected interface{}, actual interface{}, msg str...
function Subsetf (line 815) | func Subsetf(t TestingT, list interface{}, subset interface{}, msg strin...
function Truef (line 825) | func Truef(t TestingT, value bool, msg string, args ...interface{}) bool {
function WithinDurationf (line 835) | func WithinDurationf(t TestingT, expected time.Time, actual time.Time, d...
function WithinRangef (line 845) | func WithinRangef(t TestingT, actual time.Time, start time.Time, end tim...
function YAMLEqf (line 853) | func YAMLEqf(t TestingT, expected string, actual string, msg string, arg...
function Zerof (line 861) | func Zerof(t TestingT, i interface{}, msg string, args ...interface{}) b...
FILE: vendor/github.com/stretchr/testify/assert/assertion_forward.go
method Condition (line 12) | func (a *Assertions) Condition(comp Comparison, msgAndArgs ...interface{...
method Conditionf (line 20) | func (a *Assertions) Conditionf(comp Comparison, msg string, args ...int...
method Contains (line 33) | func (a *Assertions) Contains(s interface{}, contains interface{}, msgAn...
method Containsf (line 46) | func (a *Assertions) Containsf(s interface{}, contains interface{}, msg ...
method DirExists (line 55) | func (a *Assertions) DirExists(path string, msgAndArgs ...interface{}) b...
method DirExistsf (line 64) | func (a *Assertions) DirExistsf(path string, msg string, args ...interfa...
method ElementsMatch (line 76) | func (a *Assertions) ElementsMatch(listA interface{}, listB interface{},...
method ElementsMatchf (line 88) | func (a *Assertions) ElementsMatchf(listA interface{}, listB interface{}...
method Empty (line 108) | func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}...
method Emptyf (line 128) | func (a *Assertions) Emptyf(object interface{}, msg string, args ...inte...
method Equal (line 142) | func (a *Assertions) Equal(expected interface{}, actual interface{}, msg...
method EqualError (line 154) | func (a *Assertions) EqualError(theError error, errString string, msgAnd...
method EqualErrorf (line 166) | func (a *Assertions) EqualErrorf(theError error, errString string, msg s...
method EqualExportedValues (line 183) | func (a *Assertions) EqualExportedValues(expected interface{}, actual in...
method EqualExportedValuesf (line 200) | func (a *Assertions) EqualExportedValuesf(expected interface{}, actual i...
method EqualValues (line 211) | func (a *Assertions) EqualValues(expected interface{}, actual interface{...
method EqualValuesf (line 222) | func (a *Assertions) EqualValuesf(expected interface{}, actual interface...
method Equalf (line 236) | func (a *Assertions) Equalf(expected interface{}, actual interface{}, ms...
method Error (line 247) | func (a *Assertions) Error(err error, msgAndArgs ...interface{}) bool {
method ErrorAs (line 256) | func (a *Assertions) ErrorAs(err error, target interface{}, msgAndArgs ....
method ErrorAsf (line 265) | func (a *Assertions) ErrorAsf(err error, target interface{}, msg string,...
method ErrorContains (line 277) | func (a *Assertions) ErrorContains(theError error, contains string, msgA...
method ErrorContainsf (line 289) | func (a *Assertions) ErrorContainsf(theError error, contains string, msg...
method ErrorIs (line 298) | func (a *Assertions) ErrorIs(err error, target error, msgAndArgs ...inte...
method ErrorIsf (line 307) | func (a *Assertions) ErrorIsf(err error, target error, msg string, args ...
method Errorf (line 318) | func (a *Assertions) Errorf(err error, msg string, args ...interface{}) ...
method Eventually (line 329) | func (a *Assertions) Eventually(condition func() bool, waitFor time.Dura...
method EventuallyWithT (line 354) | func (a *Assertions) EventuallyWithT(condition func(collect *CollectT), ...
method EventuallyWithTf (line 379) | func (a *Assertions) EventuallyWithTf(condition func(collect *CollectT),...
method Eventuallyf (line 390) | func (a *Assertions) Eventuallyf(condition func() bool, waitFor time.Dur...
method Exactly (line 400) | func (a *Assertions) Exactly(expected interface{}, actual interface{}, m...
method Exactlyf (line 410) | func (a *Assertions) Exactlyf(expected interface{}, actual interface{}, ...
method Fail (line 418) | func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface...
method FailNow (line 426) | func (a *Assertions) FailNow(failureMessage string, msgAndArgs ...interf...
method FailNowf (line 434) | func (a *Assertions) FailNowf(failureMessage string, msg string, args .....
method Failf (line 442) | func (a *Assertions) Failf(failureMessage string, msg string, args ...in...
method False (line 452) | func (a *Assertions) False(value bool, msgAndArgs ...interface{}) bool {
method Falsef (line 462) | func (a *Assertions) Falsef(value bool, msg string, args ...interface{})...
method FileExists (line 471) | func (a *Assertions) FileExists(path string, msgAndArgs ...interface{}) ...
method FileExistsf (line 480) | func (a *Assertions) FileExistsf(path string, msg string, args ...interf...
method Greater (line 492) | func (a *Assertions) Greater(e1 interface{}, e2 interface{}, msgAndArgs ...
method GreaterOrEqual (line 505) | func (a *Assertions) GreaterOrEqual(e1 interface{}, e2 interface{}, msgA...
method GreaterOrEqualf (line 518) | func (a *Assertions) GreaterOrEqualf(e1 interface{}, e2 interface{}, msg...
method Greaterf (line 530) | func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string...
method HTTPBodyContains (line 543) | func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method s...
method HTTPBodyContainsf (line 556) | func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method ...
method HTTPBodyNotContains (line 569) | func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, metho...
method HTTPBodyNotContainsf (line 582) | func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, meth...
method HTTPError (line 594) | func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, ...
method HTTPErrorf (line 606) | func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string,...
method HTTPRedirect (line 618) | func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method strin...
method HTTPRedirectf (line 630) | func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method stri...
method HTTPStatusCode (line 642) | func (a *Assertions) HTTPStatusCode(handler http.HandlerFunc, method str...
method HTTPStatusCodef (line 654) | func (a *Assertions) HTTPStatusCodef(handler http.HandlerFunc, method st...
method HTTPSuccess (line 666) | func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string...
method HTTPSuccessf (line 678) | func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method strin...
method Implements (line 688) | func (a *Assertions) Implements(interfaceObject interface{}, object inte...
method Implementsf (line 698) | func (a *Assertions) Implementsf(interfaceObject interface{}, object int...
method InDelta (line 708) | func (a *Assertions) InDelta(expected interface{}, actual interface{}, d...
method InDeltaMapValues (line 716) | func (a *Assertions) InDeltaMapValues(expected interface{}, actual inter...
method InDeltaMapValuesf (line 724) | func (a *Assertions) InDeltaMapValuesf(expected interface{}, actual inte...
method InDeltaSlice (line 732) | func (a *Assertions) InDeltaSlice(expected interface{}, actual interface...
method InDeltaSlicef (line 740) | func (a *Assertions) InDeltaSlicef(expected interface{}, actual interfac...
method InDeltaf (line 750) | func (a *Assertions) InDeltaf(expected interface{}, actual interface{}, ...
method InEpsilon (line 758) | func (a *Assertions) InEpsilon(expected interface{}, actual interface{},...
method InEpsilonSlice (line 766) | func (a *Assertions) InEpsilonSlice(expected interface{}, actual interfa...
method InEpsilonSlicef (line 774) | func (a *Assertions) InEpsilonSlicef(expected interface{}, actual interf...
method InEpsilonf (line 782) | func (a *Assertions) InEpsilonf(expected interface{}, actual interface{}...
method IsDecreasing (line 794) | func (a *Assertions) IsDecreasing(object interface{}, msgAndArgs ...inte...
method IsDecreasingf (line 806) | func (a *Assertions) IsDecreasingf(object interface{}, msg string, args ...
method IsIncreasing (line 818) | func (a *Assertions) IsIncreasing(object interface{}, msgAndArgs ...inte...
method IsIncreasingf (line 830) | func (a *Assertions) IsIncreasingf(object interface{}, msg string, args ...
method IsNonDecreasing (line 842) | func (a *Assertions) IsNonDecreasing(object interface{}, msgAndArgs ...i...
method IsNonDecreasingf (line 854) | func (a *Assertions) IsNonDecreasingf(object interface{}, msg string, ar...
method IsNonIncreasing (line 866) | func (a *Assertions) IsNonIncreasing(object interface{}, msgAndArgs ...i...
method IsNonIncreasingf (line 878) | func (a *Assertions) IsNonIncreasingf(object interface{}, msg string, ar...
method IsNotType (line 888) | func (a *Assertions) IsNotType(theType interface{}, object interface{}, ...
method IsNotTypef (line 898) | func (a *Assertions) IsNotTypef(theType interface{}, object interface{},...
method IsType (line 908) | func (a *Assertions) IsType(expectedType interface{}, object interface{}...
method IsTypef (line 918) | func (a *Assertions) IsTypef(expectedType interface{}, object interface{...
method JSONEq (line 928) | func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ....
method JSONEqf (line 938) | func (a *Assertions) JSONEqf(expected string, actual string, msg string,...
method Len (line 949) | func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...i...
method Lenf (line 960) | func (a *Assertions) Lenf(object interface{}, length int, msg string, ar...
method Less (line 972) | func (a *Assertions) Less(e1 interface{}, e2 interface{}, msgAndArgs ......
method LessOrEqual (line 985) | func (a *Assertions) LessOrEqual(e1 interface{}, e2 interface{}, msgAndA...
method LessOrEqualf (line 998) | func (a *Assertions) LessOrEqualf(e1 interface{}, e2 interface{}, msg st...
method Lessf (line 1010) | func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, a...
method Negative (line 1021) | func (a *Assertions) Negative(e interface{}, msgAndArgs ...interface{}) ...
method Negativef (line 1032) | func (a *Assertions) Negativef(e interface{}, msg string, args ...interf...
method Never (line 1043) | func (a *Assertions) Never(condition func() bool, waitFor time.Duration,...
method Neverf (line 1054) | func (a *Assertions) Neverf(condition func() bool, waitFor time.Duration...
method Nil (line 1064) | func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) ...
method Nilf (line 1074) | func (a *Assertions) Nilf(object interface{}, msg string, args ...interf...
method NoDirExists (line 1083) | func (a *Assertions) NoDirExists(path string, msgAndArgs ...interface{})...
method NoDirExistsf (line 1092) | func (a *Assertions) NoDirExistsf(path string, msg string, args ...inter...
method NoError (line 1105) | func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) bool {
method NoErrorf (line 1118) | func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}...
method NoFileExists (line 1127) | func (a *Assertions) NoFileExists(path string, msgAndArgs ...interface{}...
method NoFileExistsf (line 1136) | func (a *Assertions) NoFileExistsf(path string, msg string, args ...inte...
method NotContains (line 1149) | func (a *Assertions) NotContains(s interface{}, contains interface{}, ms...
method NotContainsf (line 1162) | func (a *Assertions) NotContainsf(s interface{}, contains interface{}, m...
method NotElementsMatch (line 1179) | func (a *Assertions) NotElementsMatch(listA interface{}, listB interface...
method NotElementsMatchf (line 1196) | func (a *Assertions) NotElementsMatchf(listA interface{}, listB interfac...
method NotEmpty (line 1208) | func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interfac...
method NotEmptyf (line 1220) | func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...i...
method NotEqual (line 1233) | func (a *Assertions) NotEqual(expected interface{}, actual interface{}, ...
method NotEqualValues (line 1243) | func (a *Assertions) NotEqualValues(expected interface{}, actual interfa...
method NotEqualValuesf (line 1253) | func (a *Assertions) NotEqualValuesf(expected interface{}, actual interf...
method NotEqualf (line 1266) | func (a *Assertions) NotEqualf(expected interface{}, actual interface{},...
method NotErrorAs (line 1275) | func (a *Assertions) NotErrorAs(err error, target interface{}, msgAndArg...
method NotErrorAsf (line 1284) | func (a *Assertions) NotErrorAsf(err error, target interface{}, msg stri...
method NotErrorIs (line 1293) | func (a *Assertions) NotErrorIs(err error, target error, msgAndArgs ...i...
method NotErrorIsf (line 1302) | func (a *Assertions) NotErrorIsf(err error, target error, msg string, ar...
method NotImplements (line 1312) | func (a *Assertions) NotImplements(interfaceObject interface{}, object i...
method NotImplementsf (line 1322) | func (a *Assertions) NotImplementsf(interfaceObject interface{}, object ...
method NotNil (line 1332) | func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{...
method NotNilf (line 1342) | func (a *Assertions) NotNilf(object interface{}, msg string, args ...int...
method NotPanics (line 1352) | func (a *Assertions) NotPanics(f PanicTestFunc, msgAndArgs ...interface{...
method NotPanicsf (line 1362) | func (a *Assertions) NotPanicsf(f PanicTestFunc, msg string, args ...int...
method NotRegexp (line 1373) | func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndAr...
method NotRegexpf (line 1384) | func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg str...
method NotSame (line 1397) | func (a *Assertions) NotSame(expected interface{}, actual interface{}, m...
method NotSamef (line 1410) | func (a *Assertions) NotSamef(expected interface{}, actual interface{}, ...
method NotSubset (line 1426) | func (a *Assertions) NotSubset(list interface{}, subset interface{}, msg...
method NotSubsetf (line 1442) | func (a *Assertions) NotSubsetf(list interface{}, subset interface{}, ms...
method NotZero (line 1450) | func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) b...
method NotZerof (line 1458) | func (a *Assertions) NotZerof(i interface{}, msg string, args ...interfa...
method Panics (line 1468) | func (a *Assertions) Panics(f PanicTestFunc, msgAndArgs ...interface{}) ...
method PanicsWithError (line 1480) | func (a *Assertions) PanicsWithError(errString string, f PanicTestFunc, ...
method PanicsWithErrorf (line 1492) | func (a *Assertions) PanicsWithErrorf(errString string, f PanicTestFunc,...
method PanicsWithValue (line 1503) | func (a *Assertions) PanicsWithValue(expected interface{}, f PanicTestFu...
method PanicsWithValuef (line 1514) | func (a *Assertions) PanicsWithValuef(expected interface{}, f PanicTestF...
method Panicsf (line 1524) | func (a *Assertions) Panicsf(f PanicTestFunc, msg string, args ...interf...
method Positive (line 1535) | func (a *Assertions) Positive(e interface{}, msgAndArgs ...interface{}) ...
method Positivef (line 1546) | func (a *Assertions) Positivef(e interface{}, msg string, args ...interf...
method Regexp (line 1557) | func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...
method Regexpf (line 1568) | func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string...
method Same (line 1581) | func (a *Assertions) Same(expected interface{}, actual interface{}, msgA...
method Samef (line 1594) | func (a *Assertions) Samef(expected interface{}, actual interface{}, msg...
method Subset (line 1610) | func (a *Assertions) Subset(list interface{}, subset interface{}, msgAnd...
method Subsetf (line 1626) | func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg s...
method True (line 1636) | func (a *Assertions) True(value bool, msgAndArgs ...interface{}) bool {
method Truef (line 1646) | func (a *Assertions) Truef(value bool, msg string, args ...interface{}) ...
method WithinDuration (line 1656) | func (a *Assertions) WithinDuration(expected time.Time, actual time.Time...
method WithinDurationf (line 1666) | func (a *Assertions) WithinDurationf(expected time.Time, actual time.Tim...
method WithinRange (line 1676) | func (a *Assertions) WithinRange(actual time.Time, start time.Time, end ...
method WithinRangef (line 1686) | func (a *Assertions) WithinRangef(actual time.Time, start time.Time, end...
method YAMLEq (line 1694) | func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ....
method YAMLEqf (line 1702) | func (a *Assertions) YAMLEqf(expected string, actual string, msg string,...
method Zero (line 1710) | func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) bool {
method Zerof (line 1718) | func (a *Assertions) Zerof(i interface{}, msg string, args ...interface{...
FILE: vendor/github.com/stretchr/testify/assert/assertion_order.go
function isOrdered (line 9) | func isOrdered(t TestingT, object interface{}, allowedComparesResults []...
function IsIncreasing (line 52) | func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interfac...
function IsNonIncreasing (line 61) | func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...inter...
function IsDecreasing (line 70) | func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interfac...
function IsNonDecreasing (line 79) | func IsNonDecreasing(t TestingT, object interface{}, msgAndArgs ...inter...
FILE: vendor/github.com/stretchr/testify/assert/assertions.go
type TestingT (line 30) | type TestingT interface
type ComparisonAssertionFunc (line 36) | type ComparisonAssertionFunc
type ValueAssertionFunc (line 40) | type ValueAssertionFunc
type BoolAssertionFunc (line 44) | type BoolAssertionFunc
type ErrorAssertionFunc (line 48) | type ErrorAssertionFunc
type Comparison (line 55) | type Comparison
function ObjectsAreEqual (line 64) | func ObjectsAreEqual(expected, actual interface{}) bool {
function copyExportedFields (line 86) | func copyExportedFields(expected interface{}) interface{} {
function ObjectsExportedFieldsAreEqual (line 156) | func ObjectsExportedFieldsAreEqual(expected, actual interface{}) bool {
function ObjectsAreEqualValues (line 164) | func ObjectsAreEqualValues(expected, actual interface{}) bool {
function isNumericType (line 201) | func isNumericType(t reflect.Type) bool {
function CallerInfo (line 212) | func CallerInfo() []string {
function isTest (line 293) | func isTest(name, prefix string) bool {
function messageFromMsgAndArgs (line 304) | func messageFromMsgAndArgs(msgAndArgs ...interface{}) string {
function indentMessageLines (line 325) | func indentMessageLines(message string, longestLabelLen int) string {
type failNower (line 340) | type failNower interface
function FailNow (line 345) | func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{...
function Fail (line 366) | func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) ...
type labeledContent (line 392) | type labeledContent struct
function labeledOutput (line 406) | func labeledOutput(content ...labeledContent) string {
function Implements (line 423) | func Implements(t TestingT, interfaceObject interface{}, object interfac...
function NotImplements (line 442) | func NotImplements(t TestingT, interfaceObject interface{}, object inter...
function isType (line 458) | func isType(expectedType, object interface{}) bool {
function IsType (line 465) | func IsType(t TestingT, expectedType, object interface{}, msgAndArgs ......
function IsNotType (line 478) | func IsNotType(t TestingT, theType, object interface{}, msgAndArgs ...in...
function Equal (line 495) | func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...inter...
function validateEqualArgs (line 517) | func validateEqualArgs(expected, actual interface{}) error {
function Same (line 534) | func Same(t TestingT, expected, actual interface{}, msgAndArgs ...interf...
function NotSame (line 561) | func NotSame(t TestingT, expected, actual interface{}, msgAndArgs ...int...
function samePointers (line 584) | func samePointers(first, second interface{}) (same bool, ok bool) {
function formatUnequalValues (line 605) | func formatUnequalValues(expected, actual interface{}) (e string, a stri...
function truncatingFormat (line 621) | func truncatingFormat(data interface{}) string {
function EqualValues (line 634) | func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs .....
function EqualExportedValues (line 660) | func EqualExportedValues(t TestingT, expected, actual interface{}, msgAn...
function Exactly (line 689) | func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...int...
function NotNil (line 707) | func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) b...
function isNil (line 718) | func isNil(object interface{}) bool {
function Nil (line 739) | func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
function isEmpty (line 750) | func isEmpty(object interface{}) bool {
function isEmptyValue (line 760) | func isEmptyValue(objValue reflect.Value) bool {
function Empty (line 790) | func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bo...
function NotEmpty (line 807) | func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{})...
function getLen (line 821) | func getLen(x interface{}) (length int, ok bool) {
function Len (line 833) | func Len(t TestingT, object interface{}, length int, msgAndArgs ...inter...
function True (line 851) | func True(t TestingT, value bool, msgAndArgs ...interface{}) bool {
function False (line 865) | func False(t TestingT, value bool, msgAndArgs ...interface{}) bool {
function NotEqual (line 882) | func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...in...
function NotEqualValues (line 901) | func NotEqualValues(t TestingT, expected, actual interface{}, msgAndArgs...
function containsElement (line 917) | func containsElement(list interface{}, element interface{}) (ok, found b...
function Contains (line 960) | func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interfa...
function NotContains (line 982) | func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...inte...
function Subset (line 1007) | func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interfac...
function NotSubset (line 1075) | func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...inter...
function ElementsMatch (line 1139) | func ElementsMatch(t TestingT, listA, listB interface{}, msgAndArgs ...i...
function isList (line 1161) | func isList(t TestingT, list interface{}, msgAndArgs ...interface{}) (ok...
function diffLists (line 1173) | func diffLists(listA, listB interface{}) (extraA, extraB []interface{}) {
function formatListDiff (line 1210) | func formatListDiff(listA, listB interface{}, extraA, extraB []interface...
function NotElementsMatch (line 1240) | func NotElementsMatch(t TestingT, listA, listB interface{}, msgAndArgs ....
function Condition (line 1264) | func Condition(t TestingT, comp Comparison, msgAndArgs ...interface{}) b...
type PanicTestFunc (line 1277) | type PanicTestFunc
function didPanic (line 1280) | func didPanic(f PanicTestFunc) (didPanic bool, message interface{}, stac...
function Panics (line 1300) | func Panics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {
function PanicsWithValue (line 1316) | func PanicsWithValue(t TestingT, expected interface{}, f PanicTestFunc, ...
function PanicsWithError (line 1337) | func PanicsWithError(t TestingT, errString string, f PanicTestFunc, msgA...
function NotPanics (line 1357) | func NotPanics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) b
Copy disabled (too large)
Download .json
Condensed preview — 2102 files, each showing path, character count, and a content snippet. Download the .json file for the full structured content (111,965K chars).
[
{
"path": ".dockerignore",
"chars": 13,
"preview": "node_modules\n"
},
{
"path": ".github/dependabot.yml",
"chars": 749,
"preview": "# To get started with Dependabot version updates, you'll need to specify which\n# package ecosystems to update and where "
},
{
"path": ".github/workflows/ci.yml",
"chars": 3544,
"preview": "name: build\non: [push, pull_request]\n\njobs:\n build:\n name: build\n runs-on: ubuntu-latest\n steps:\n - name:"
},
{
"path": ".github/workflows/e2e.yml",
"chars": 1083,
"preview": "name: e2e\n\non:\n push:\n branches: [master]\n pull_request:\n workflow_dispatch:\n\npermissions:\n contents: read\n\njobs:"
},
{
"path": ".github/workflows/release.yml",
"chars": 570,
"preview": "name: release\n\non:\n push:\n tags:\n - 'v*'\n\npermissions:\n contents: write\n\njobs:\n goreleaser:\n runs-on: ubun"
},
{
"path": ".gitignore",
"chars": 271,
"preview": "*.test\n*.prof\n.cover/\netc/ssl/\nssl/\ntarget/\nsecrets.bd\ndocroot\n*.cov\n.cover\ntarget\n/logs/\n/target/\n/var/\ndebug\ndebug.tes"
},
{
"path": ".golangci.yml",
"chars": 3644,
"preview": "version: \"2\"\nrun:\n concurrency: 4\nlinters:\n default: none\n enable:\n - asciicheck\n - bidichk\n - bodyclose\n "
},
{
"path": ".goreleaser.yml",
"chars": 2280,
"preview": "project_name: secrets\ndist: .bin\nbuilds:\n - id: secrets\n binary: \"secrets\"\n env:\n - CGO_ENABLED=0\n goos:\n"
},
{
"path": ".zed/tasks.json",
"chars": 932,
"preview": "[\n {\n \"label\": \"build: binary\",\n \"command\": \"make build\",\n \"cwd\": \"$ZED_WORKTREE_ROOT\"\n },\n {\n \"label\": \""
},
{
"path": "CHANGELOG.md",
"chars": 7221,
"preview": "# Changelog\n\nAll notable changes to this project are documented in this file.\n\n## [2.2.6] - 2026-04-01\n\n### Fixed\n- Fix "
},
{
"path": "CLAUDE.md",
"chars": 18603,
"preview": "# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.\n\n## "
},
{
"path": "Dockerfile",
"chars": 1090,
"preview": "ARG TZ=America/Chicago\n\nFROM umputun/baseimage:buildgo-latest AS build-backend\n\nARG CI\nARG GIT_BRANCH\nARG SKIP_TEST\nARG "
},
{
"path": "LICENSE",
"chars": 11337,
"preview": " Apache License\n Version 2.0, January 2004\n "
},
{
"path": "Makefile",
"chars": 2013,
"preview": "B=$(shell git rev-parse --abbrev-ref HEAD)\nBRANCH=$(subst /,-,$(B))\nGITREV=$(shell git describe --abbrev=7 --always --ta"
},
{
"path": "README.md",
"chars": 14965,
"preview": "# Safe Secrets - safe(r) and easy way to transfer sensitive data\n\n[\n\n// Notif"
},
{
"path": "app/main.go",
"chars": 7747,
"preview": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/signal\"\n\t\"syscall\"\n\t\"time\"\n\n\tlog \"github.com/go-pkgz/lgr\"\n\t\"github.c"
},
{
"path": "app/messager/crypt.go",
"chars": 2085,
"preview": "package messager\n\nimport (\n\t\"crypto/rand\"\n\t\"encoding/base64\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"strings\"\n\n\t\"golang.org/x/crypto/na"
},
{
"path": "app/messager/crypt_mock.go",
"chars": 2839,
"preview": "// Code generated by moq; DO NOT EDIT.\n// github.com/matryer/moq\n\npackage messager\n\nimport (\n\t\"sync\"\n)\n\n// Ensure, that "
},
{
"path": "app/messager/crypt_test.go",
"chars": 1772,
"preview": "package messager\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/"
},
{
"path": "app/messager/engine_mock.go",
"chars": 6539,
"preview": "// Code generated by moq; DO NOT EDIT.\n// github.com/matryer/moq\n\npackage messager\n\nimport (\n\t\"context\"\n\t\"sync\"\n\n\t\"githu"
},
{
"path": "app/messager/messager.go",
"chars": 12060,
"preview": "// Package messager package using injected engine.Store to save and load messages.\n// It does all encryption/decryption "
},
{
"path": "app/messager/messager_test.go",
"chars": 26904,
"preview": "package messager\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"g"
},
{
"path": "app/server/assets/efs.go",
"chars": 178,
"preview": "// Package assets provides embedded static files and templates\npackage assets\n\nimport \"embed\"\n\n// Files is embedded stat"
},
{
"path": "app/server/assets/html/index.tmpl.html",
"chars": 8474,
"preview": "{{define \"base\"}}\n <!DOCTYPE html>\n <html lang=\"en\" {{if ne .Theme \"auto\"}}data-theme=\"{{.Theme}}\"{{end}}>\n <he"
},
{
"path": "app/server/assets/html/pages/404.tmpl.html",
"chars": 81,
"preview": "{{define \"title\"}}Not Found{{end}}\n\n{{define \"main\"}}\n\n<h1>NOT FOUND</h1>\n{{end}}"
},
{
"path": "app/server/assets/html/pages/about.tmpl.html",
"chars": 2183,
"preview": "{{define \"title\"}}How it works{{end}}\n\n{{define \"main\"}}\n\n<div class=\"card\">\n <div class=\"card-header\">\n <h1 c"
},
{
"path": "app/server/assets/html/pages/home.tmpl.html",
"chars": 9046,
"preview": "{{define \"title\"}}Home{{end}}\n\n{{define \"main\"}}\n\n<div class=\"card\" id=\"form-card\">\n <div class=\"card-header\">\n "
},
{
"path": "app/server/assets/html/pages/message-error.tmpl.html",
"chars": 328,
"preview": "{{define \"title\"}}Message Unavailable{{end}}\n\n{{define \"main\"}}\n<div class=\"card error-card\">\n <div class=\"card-heade"
},
{
"path": "app/server/assets/html/pages/show-message.tmpl.html",
"chars": 10170,
"preview": "{{define \"title\"}}Your message{{end}}\n\n{{define \"main\"}}\n\n<div id=\"show-msg\" class=\"show-msg\">\n <div id=\"message-contai"
},
{
"path": "app/server/assets/html/partials/copy-button.tmpl.html",
"chars": 1132,
"preview": "{{define \"copy-button\"}}\n<button type=\"button\"\n class=\"main-btn copy-btn\"\n data-action=\"copy-text\"\n "
},
{
"path": "app/server/assets/html/partials/decoded-message.tmpl.html",
"chars": 2203,
"preview": "{{define \"decoded-message\"}}\n<div id=\"msg\" class=\"card\">\n <div class=\"card-header\">\n <h2 class=\"card-title car"
},
{
"path": "app/server/assets/html/partials/email-popup.tmpl.html",
"chars": 2967,
"preview": "{{define \"email-popup\"}}\n<div id=\"popup\" class=\"popup active\">\n <div class=\"popup-content email-popup\">\n <div "
},
{
"path": "app/server/assets/html/partials/email-sent.tmpl.html",
"chars": 1004,
"preview": "{{define \"email-sent\"}}\n<div id=\"popup\" class=\"popup active\">\n <div class=\"popup-content\">\n <div class=\"popup-"
},
{
"path": "app/server/assets/html/partials/error.tmpl.html",
"chars": 338,
"preview": "{{define \"error\"}}\n<div class=\"card error-card\">\n <div class=\"card-header\" style=\"text-align: center;\">\n <h2 c"
},
{
"path": "app/server/assets/html/partials/login-popup.tmpl.html",
"chars": 1215,
"preview": "{{define \"login-popup\"}}\n<div id=\"popup\" class=\"popup active\">\n <div class=\"popup-content login-popup\">\n <div "
},
{
"path": "app/server/assets/html/partials/no-pin-modal.tmpl.html",
"chars": 1225,
"preview": "{{define \"no-pin-modal\"}}\n{{if .AllowNoPin}}\n<div id=\"no-pin-modal\" class=\"popup\">\n <div class=\"popup-content no-pin-"
},
{
"path": "app/server/assets/html/partials/popup.tmpl.html",
"chars": 705,
"preview": "{{define \"popup\"}}\n<div id=\"popup\" class=\"popup active\">\n <div class=\"popup-content\">\n <div class=\"popup-heade"
},
{
"path": "app/server/assets/html/partials/secure-link.tmpl.html",
"chars": 3491,
"preview": "{{define \"title\"}}Share the message{{end}}\n\n{{define \"secure-link\"}}\n\n<div id=\"msg-link\" class=\"card\">\n <div class=\"c"
},
{
"path": "app/server/assets/static/css/main.css",
"chars": 40318,
"preview": "/* ==================== CSS Reset ==================== */\n*, *::before, *::after {\n padding: 0;\n margin: 0;\n bo"
},
{
"path": "app/server/assets/static/js/app.js",
"chars": 32232,
"preview": "// app.js - CSP-compatible application logic\n// all event handlers use data attributes instead of inline handlers\n'use s"
},
{
"path": "app/server/assets/static/js/crypto.js",
"chars": 9700,
"preview": "// crypto.js - client-side AES-128-GCM encryption for UI messages\n// uses Web Crypto API, requires HTTPS (or localhost)\n"
},
{
"path": "app/server/assets/static/js/htmx-response-targets.js",
"chars": 3722,
"preview": "(function() {\n /** @type {import(\"../htmx\").HtmxInternalApi} */\n var api\n\n var attrPrefix = 'hx-target-'\n\n // IE11 d"
},
{
"path": "app/server/auth.go",
"chars": 5011,
"preview": "package server\n\nimport (\n\t\"crypto/hmac\"\n\t\"crypto/sha256\"\n\t\"crypto/subtle\"\n\t\"encoding/base64\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"st"
},
{
"path": "app/server/auth_test.go",
"chars": 21993,
"preview": "package server\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github."
},
{
"path": "app/server/middleware.go",
"chars": 5408,
"preview": "package server\n\nimport (\n\t\"context\"\n\t\"crypto/hmac\"\n\t\"crypto/sha256\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"stri"
},
{
"path": "app/server/middleware_test.go",
"chars": 15469,
"preview": "package server\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/go-pkgz/lg"
},
{
"path": "app/server/mocks/email_sender_mock.go",
"chars": 3122,
"preview": "// Code generated by moq; DO NOT EDIT.\n// github.com/matryer/moq\n\npackage mocks\n\nimport (\n\t\"context\"\n\t\"sync\"\n\n\t\"github.c"
},
{
"path": "app/server/server.go",
"chars": 13943,
"preview": "// Package server provides rest-like api and serves static assets as well\npackage server\n\nimport (\n\t\"context\"\n\t\"crypto/s"
},
{
"path": "app/server/server_test.go",
"chars": 34303,
"preview": "package server\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"strings\"\n\t\"te"
},
{
"path": "app/server/validator/validator.go",
"chars": 2705,
"preview": "// Package validator provides functionality for validating and sanitizing data.\npackage validator\n\nimport (\n\t\"strconv\"\n\t"
},
{
"path": "app/server/validator/validator_test.go",
"chars": 9275,
"preview": "package validator\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestValidator_Valid(t *tes"
},
{
"path": "app/server/web.go",
"chars": 27306,
"preview": "package server\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"html/template\"\n\t\"io/fs\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/u"
},
{
"path": "app/server/web_test.go",
"chars": 71555,
"preview": "package server\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"io\"\n\t\"mime/multipart\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t"
},
{
"path": "app/store/sqlite.go",
"chars": 6942,
"preview": "package store\n\nimport (\n\t\"context\"\n\t\"crypto/rand\"\n\t\"database/sql\"\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\tlog"
},
{
"path": "app/store/sqlite_test.go",
"chars": 9685,
"preview": "package store\n\nimport (\n\t\"database/sql\"\n\t\"errors\"\n\t\"os\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert"
},
{
"path": "app/store/store.go",
"chars": 1158,
"preview": "// Package store defines and implements data store for sqlite and in-memory\npackage store\n\nimport (\n\t\"crypto/rand\"\n\t\"err"
},
{
"path": "app/store/store_test.go",
"chars": 730,
"preview": "package store\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc"
},
{
"path": "completions/secrets.bash",
"chars": 269,
"preview": "# bash completion for secrets (generated via go-flags)\n_secrets() {\n local args=(\"${COMP_WORDS[@]:1:$COMP_CWORD}\")\n "
},
{
"path": "completions/secrets.fish",
"chars": 183,
"preview": "# fish completion for secrets (generated via go-flags)\ncomplete -c secrets -a '(GO_FLAGS_COMPLETION=verbose secrets (com"
},
{
"path": "completions/secrets.zsh",
"chars": 800,
"preview": "#compdef secrets\n\n# zsh completion for secrets (generated via go-flags)\n_secrets() {\n local -a lines\n lines=(${(f)"
},
{
"path": "docker-compose-dev.yml",
"chars": 610,
"preview": "services:\n\n secrets:\n build: .\n image: umputun/secrets:dev\n container_name: secrets\n host"
},
{
"path": "docker-compose-reproxy.yml",
"chars": 1185,
"preview": "services:\n\n secrets:\n build: .\n image: umputun/secrets:latest\n container_name: secrets\n hostname: secrets\n "
},
{
"path": "docker-compose.yml",
"chars": 1578,
"preview": "version: '2'\nservices:\n\n secrets:\n build: .\n image: umputun/secrets:latest\n container_name: secr"
},
{
"path": "docs/plans/completed/2025-12-26-paranoid-mode-sqlite.md",
"chars": 19066,
"preview": "# Paranoid Mode + SQLite Implementation Plan\n\n**Goal:** Add zero-knowledge encryption mode (`--paranoid`) with client-si"
},
{
"path": "docs/plans/completed/2025-12-27-hybrid-encryption.md",
"chars": 14086,
"preview": "# Hybrid Encryption Mode Implementation Plan\n\n**Goal:** UI always uses client-side encryption, API uses server-side encr"
},
{
"path": "docs/plans/completed/2025-12-29-optional-pin.md",
"chars": 6332,
"preview": "# Optional PIN for Client-Side Encrypted Messages\n\n## Overview\n\nAllow users to skip PIN protection when creating secrets"
},
{
"path": "docs/plans/completed/2026-01-15-csp-inline-scripts-elimination.md",
"chars": 7138,
"preview": "# CSP-Compatible Frontend: Eliminate Inline Scripts\n\n## Overview\n- Refactor frontend to remove all inline JavaScript for"
},
{
"path": "e2e/auth_test.go",
"chars": 8540,
"preview": "//go:build e2e\n\npackage e2e\n\nimport (\n\t\"os\"\n\t\"os/exec\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"githu"
},
{
"path": "e2e/crypto_test.go",
"chars": 10262,
"preview": "//go:build e2e\n\npackage e2e\n\nimport (\n\t\"testing\"\n\n\t\"github.com/playwright-community/playwright-go\"\n\t\"github.com/stretchr"
},
{
"path": "e2e/e2e_test.go",
"chars": 22380,
"preview": "//go:build e2e\n\n// Package e2e contains end-to-end tests for the secrets web application.\n// Tests are organized into th"
},
{
"path": "e2e/email_test.go",
"chars": 5347,
"preview": "//go:build e2e\n\npackage e2e\n\nimport (\n\t\"os\"\n\t\"os/exec\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/asse"
},
{
"path": "e2e/file_test.go",
"chars": 8286,
"preview": "//go:build e2e\n\npackage e2e\n\nimport (\n\t\"os\"\n\t\"os/exec\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/asse"
},
{
"path": "e2e/hybrid_test.go",
"chars": 26862,
"preview": "//go:build e2e\n\npackage e2e\n\nimport (\n\t\"encoding/json\"\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\""
},
{
"path": "e2e/no_pin_test.go",
"chars": 16752,
"preview": "//go:build e2e\n\npackage e2e\n\nimport (\n\t\"os\"\n\t\"os/exec\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/playwright-community/"
},
{
"path": "go.mod",
"chars": 1649,
"preview": "module github.com/umputun/secrets/v2\n\ngo 1.25.0\n\nrequire (\n\tgithub.com/didip/tollbooth/v8 v8.0.1\n\tgithub.com/go-pkgz/lgr"
},
{
"path": "go.sum",
"chars": 13634,
"preview": "github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=\ngithub.com/aymerick/douceur v0.2.0/go"
},
{
"path": "secrets-nginx.conf",
"chars": 1576,
"preview": "server {\n listen 443 ssl;\n server_name _;\n\n ssl_certificate SSL_CERT;\n ssl_certificate_key SSL_K"
},
{
"path": "secrets.rest",
"chars": 330,
"preview": "### save message\n\nPOST http://localhost:8080/api/v1/message\nContent-Type: application/json\n\n{\n \"message\": \"my secret "
},
{
"path": "vendor/github.com/aymerick/douceur/LICENSE",
"chars": 1084,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2015 Aymerick JEHANNE\n\nPermission is hereby granted, free of charge, to any person "
},
{
"path": "vendor/github.com/aymerick/douceur/css/declaration.go",
"chars": 1512,
"preview": "package css\n\nimport \"fmt\"\n\n// Declaration represents a parsed style property\ntype Declaration struct {\n\tProperty string"
},
{
"path": "vendor/github.com/aymerick/douceur/css/rule.go",
"chars": 4951,
"preview": "package css\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\nconst (\n\tindentSpace = 2\n)\n\n// RuleKind represents a Rule kind\ntype RuleKind "
},
{
"path": "vendor/github.com/aymerick/douceur/css/stylesheet.go",
"chars": 441,
"preview": "package css\n\n// Stylesheet represents a parsed stylesheet\ntype Stylesheet struct {\n\tRules []*Rule\n}\n\n// NewStylesheet in"
},
{
"path": "vendor/github.com/aymerick/douceur/parser/parser.go",
"chars": 8802,
"preview": "package parser\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/gorilla/css/scanner\"\n\n\t\"github.com/aymerick"
},
{
"path": "vendor/github.com/davecgh/go-spew/LICENSE",
"chars": 766,
"preview": "ISC License\n\nCopyright (c) 2012-2016 Dave Collins <dave@davec.name>\n\nPermission to use, copy, modify, and/or distribute "
},
{
"path": "vendor/github.com/davecgh/go-spew/spew/bypass.go",
"chars": 4715,
"preview": "// Copyright (c) 2015-2016 Dave Collins <dave@davec.name>\n//\n// Permission to use, copy, modify, and distribute this sof"
},
{
"path": "vendor/github.com/davecgh/go-spew/spew/bypasssafe.go",
"chars": 1741,
"preview": "// Copyright (c) 2015-2016 Dave Collins <dave@davec.name>\n//\n// Permission to use, copy, modify, and distribute this sof"
},
{
"path": "vendor/github.com/davecgh/go-spew/spew/common.go",
"chars": 10364,
"preview": "/*\n * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>\n *\n * Permission to use, copy, modify, and distribute this "
},
{
"path": "vendor/github.com/davecgh/go-spew/spew/config.go",
"chars": 12842,
"preview": "/*\n * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>\n *\n * Permission to use, copy, modify, and distribute this "
},
{
"path": "vendor/github.com/davecgh/go-spew/spew/doc.go",
"chars": 8527,
"preview": "/*\n * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>\n *\n * Permission to use, copy, modify, and distribute this "
},
{
"path": "vendor/github.com/davecgh/go-spew/spew/dump.go",
"chars": 13794,
"preview": "/*\n * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>\n *\n * Permission to use, copy, modify, and distribute this "
},
{
"path": "vendor/github.com/davecgh/go-spew/spew/format.go",
"chars": 11314,
"preview": "/*\n * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>\n *\n * Permission to use, copy, modify, and distribute this "
},
{
"path": "vendor/github.com/davecgh/go-spew/spew/spew.go",
"chars": 5969,
"preview": "/*\n * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>\n *\n * Permission to use, copy, modify, and distribute this "
},
{
"path": "vendor/github.com/deckarep/golang-set/v2/.gitignore",
"chars": 257,
"preview": "# Compiled Object files, Static and Dynamic libs (Shared Objects)\n*.o\n*.a\n*.so\n\n# Folders\n_obj\n_test\n\n# Architecture spe"
},
{
"path": "vendor/github.com/deckarep/golang-set/v2/LICENSE",
"chars": 1168,
"preview": "Open Source Initiative OSI - The MIT License (MIT):Licensing\n\nThe MIT License (MIT)\nCopyright (c) 2013 - 2022 Ralph Cara"
},
{
"path": "vendor/github.com/deckarep/golang-set/v2/README.md",
"chars": 6128,
"preview": "\n[:Licensing\n\nThe MIT License (MIT)\nCopyright (c) 2013 - 2022 Ralph C"
},
{
"path": "vendor/github.com/deckarep/golang-set/v2/set.go",
"chars": 8420,
"preview": "/*\nOpen Source Initiative OSI - The MIT License (MIT):Licensing\n\nThe MIT License (MIT)\nCopyright (c) 2013 - 2022 Ralph C"
},
{
"path": "vendor/github.com/deckarep/golang-set/v2/sorted.go",
"chars": 1510,
"preview": "//go:build go1.21\n// +build go1.21\n\n/*\nOpen Source Initiative OSI - The MIT License (MIT):Licensing\n\nThe MIT License (MI"
},
{
"path": "vendor/github.com/deckarep/golang-set/v2/threadsafe.go",
"chars": 5858,
"preview": "/*\nOpen Source Initiative OSI - The MIT License (MIT):Licensing\n\nThe MIT License (MIT)\nCopyright (c) 2013 - 2022 Ralph C"
},
{
"path": "vendor/github.com/deckarep/golang-set/v2/threadunsafe.go",
"chars": 7259,
"preview": "/*\nOpen Source Initiative OSI - The MIT License (MIT):Licensing\n\nThe MIT License (MIT)\nCopyright (c) 2013 - 2022 Ralph C"
},
{
"path": "vendor/github.com/didip/tollbooth/v8/.gitignore",
"chars": 22,
"preview": "/debug\n/.vscode\n/.idea"
},
{
"path": "vendor/github.com/didip/tollbooth/v8/.golangci.yml",
"chars": 508,
"preview": "linters:\n enable:\n - revive\n - govet\n - unconvert\n - megacheck\n - gas\n - gocyclo\n - dupl\n - mis"
},
{
"path": "vendor/github.com/didip/tollbooth/v8/LICENSE",
"chars": 1080,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2015 Didip Kerabat\n\nPermission is hereby granted, free of charge, to any person obt"
},
{
"path": "vendor/github.com/didip/tollbooth/v8/README.md",
"chars": 8147,
"preview": "[](http://godoc.org/github.com/didip/tollbooth)\n[](https://travis-ci.org/dusti"
},
{
"path": "vendor/github.com/dustin/go-humanize/big.go",
"chars": 612,
"preview": "package humanize\n\nimport (\n\t\"math/big\"\n)\n\n// order of magnitude (to a max order)\nfunc oomm(n, b *big.Int, maxmag int) (f"
},
{
"path": "vendor/github.com/dustin/go-humanize/bigbytes.go",
"chars": 4850,
"preview": "package humanize\n\nimport (\n\t\"fmt\"\n\t\"math/big\"\n\t\"strings\"\n\t\"unicode\"\n)\n\nvar (\n\tbigIECExp = big.NewInt(1024)\n\n\t// BigByte "
},
{
"path": "vendor/github.com/dustin/go-humanize/bytes.go",
"chars": 2610,
"preview": "package humanize\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"strconv\"\n\t\"strings\"\n\t\"unicode\"\n)\n\n// IEC Sizes.\n// kibis of bits\nconst (\n\tBy"
},
{
"path": "vendor/github.com/dustin/go-humanize/comma.go",
"chars": 2476,
"preview": "package humanize\n\nimport (\n\t\"bytes\"\n\t\"math\"\n\t\"math/big\"\n\t\"strconv\"\n\t\"strings\"\n)\n\n// Comma produces a string form of the "
},
{
"path": "vendor/github.com/dustin/go-humanize/commaf.go",
"chars": 762,
"preview": "//go:build go1.6\n// +build go1.6\n\npackage humanize\n\nimport (\n\t\"bytes\"\n\t\"math/big\"\n\t\"strings\"\n)\n\n// BigCommaf produces a "
},
{
"path": "vendor/github.com/dustin/go-humanize/ftoa.go",
"chars": 986,
"preview": "package humanize\n\nimport (\n\t\"strconv\"\n\t\"strings\"\n)\n\nfunc stripTrailingZeros(s string) string {\n\tif !strings.ContainsRune"
},
{
"path": "vendor/github.com/dustin/go-humanize/humanize.go",
"chars": 276,
"preview": "/*\nPackage humanize converts boring ugly numbers to human-friendly strings and back.\n\nDurations can be turned into strin"
},
{
"path": "vendor/github.com/dustin/go-humanize/number.go",
"chars": 4318,
"preview": "package humanize\n\n/*\nSlightly adapted from the source to fit go-humanize.\n\nAuthor: https://github.com/gorhill\nSource: ht"
},
{
"path": "vendor/github.com/dustin/go-humanize/ordinals.go",
"chars": 371,
"preview": "package humanize\n\nimport \"strconv\"\n\n// Ordinal gives you the input number in a rank/ordinal format.\n//\n// Ordinal(3) -> "
},
{
"path": "vendor/github.com/dustin/go-humanize/si.go",
"chars": 2908,
"preview": "package humanize\n\nimport (\n\t\"errors\"\n\t\"math\"\n\t\"regexp\"\n\t\"strconv\"\n)\n\nvar siPrefixTable = map[float64]string{\n\t-30: \"q\", "
},
{
"path": "vendor/github.com/dustin/go-humanize/times.go",
"chars": 3239,
"preview": "package humanize\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"sort\"\n\t\"time\"\n)\n\n// Seconds-based time units\nconst (\n\tDay = 24 * time.H"
},
{
"path": "vendor/github.com/go-jose/go-jose/v3/LICENSE",
"chars": 11358,
"preview": "\n Apache License\n Version 2.0, January 2004\n "
},
{
"path": "vendor/github.com/go-jose/go-jose/v3/json/LICENSE",
"chars": 1479,
"preview": "Copyright (c) 2012 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or with"
},
{
"path": "vendor/github.com/go-jose/go-jose/v3/json/README.md",
"chars": 632,
"preview": "# Safe JSON\n\nThis repository contains a fork of the `encoding/json` package from Go 1.6.\n\nThe following changes were mad"
},
{
"path": "vendor/github.com/go-jose/go-jose/v3/json/decode.go",
"chars": 30187,
"preview": "// Copyright 2010 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "vendor/github.com/go-jose/go-jose/v3/json/encode.go",
"chars": 31517,
"preview": "// Copyright 2010 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license"
},
{
"path": "vendor/github.com/go-jose/go-jose/v3/json/indent.go",
"chars": 3438,
"preview": "// Copyright 2010 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license"
},
{
"path": "vendor/github.com/go-jose/go-jose/v3/json/scanner.go",
"chars": 16922,
"preview": "// Copyright 2010 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license"
},
{
"path": "vendor/github.com/go-jose/go-jose/v3/json/stream.go",
"chars": 11881,
"preview": "// Copyright 2010 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license"
},
{
"path": "vendor/github.com/go-jose/go-jose/v3/json/tags.go",
"chars": 1076,
"preview": "// Copyright 2011 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "vendor/github.com/go-pkgz/email/.gitignore",
"chars": 269,
"preview": "# Binaries for programs and plugins\n*.exe\n*.exe~\n*.dll\n*.so\n*.dylib\n\n# Test binary, built with `go test -c`\n*.test\n\n# Ou"
},
{
"path": "vendor/github.com/go-pkgz/email/.golangci.yml",
"chars": 855,
"preview": "version: \"2\"\nrun:\n timeout: 5m\n concurrency: 4\nlinters:\n default: none\n enable:\n - dupl\n - gochecknoinits\n "
},
{
"path": "vendor/github.com/go-pkgz/email/LICENSE",
"chars": 1064,
"preview": "MIT License\n\nCopyright (c) 2022 Umputun\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof"
},
{
"path": "vendor/github.com/go-pkgz/email/README.md",
"chars": 4010,
"preview": "# email sending library\n\n[](https://github.co"
},
{
"path": "vendor/github.com/go-pkgz/email/auth.go",
"chars": 1628,
"preview": "package email\n\nimport (\n\t\"errors\"\n\t\"net/smtp\"\n)\n\n// authMethod is SMTP authentication method\ntype authMethod string\n\n// "
},
{
"path": "vendor/github.com/go-pkgz/email/email.go",
"chars": 11386,
"preview": "// Package email provides email sender\npackage email\n\nimport (\n\t\"bytes\"\n\t\"crypto/tls\"\n\t\"encoding/base64\"\n\t\"errors\"\n\t\"fmt"
},
{
"path": "vendor/github.com/go-pkgz/email/options.go",
"chars": 1555,
"preview": "package email\n\nimport \"time\"\n\n// Option func type\ntype Option func(s *Sender)\n\n// SMTP sets SMTP client\nfunc SMTP(smtp S"
},
{
"path": "vendor/github.com/go-pkgz/expirable-cache/v3/LICENSE",
"chars": 1101,
"preview": "MIT License\n\nCopyright (c) 2020 Umputun\nCopyright (c) 2020 Dmitry Verhoturov\n\nPermission is hereby granted, free of char"
},
{
"path": "vendor/github.com/go-pkgz/expirable-cache/v3/cache.go",
"chars": 9709,
"preview": "// Package cache implements Cache similar to hashicorp/golang-lru\n//\n// Support LRC, LRU and TTL-based eviction.\n// Pack"
},
{
"path": "vendor/github.com/go-pkgz/expirable-cache/v3/options.go",
"chars": 1060,
"preview": "package cache\n\nimport \"time\"\n\ntype options[K comparable, V any] interface {\n\tWithTTL(ttl time.Duration) Cache[K, V]\n\tWit"
},
{
"path": "vendor/github.com/go-pkgz/notify/.golangci.yml",
"chars": 1250,
"preview": "version: \"2\"\nlinters:\n default: none\n enable:\n - bodyclose\n - copyloopvar\n - dupl\n - gochecknoinits\n - "
},
{
"path": "vendor/github.com/go-pkgz/notify/LICENSE",
"chars": 1064,
"preview": "MIT License\n\nCopyright (c) 2021 Umputun\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof"
},
{
"path": "vendor/github.com/go-pkgz/notify/README.md",
"chars": 6767,
"preview": "# Notify\n\n[](https://github.com/go-pkgz/noti"
},
{
"path": "vendor/github.com/go-pkgz/notify/email.go",
"chars": 4247,
"preview": "package notify\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/mail\"\n\t\"net/url\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/go-pkgz/email\"\n)\n\n// "
},
{
"path": "vendor/github.com/go-pkgz/notify/interface.go",
"chars": 944,
"preview": "// Package notify provides notification functionality.\npackage notify\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n)\n\n// Notif"
},
{
"path": "vendor/github.com/go-pkgz/notify/slack.go",
"chars": 2843,
"preview": "package notify\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"strings\"\n\n\t\"github.com/slack-go/slack\"\n)\n\n// Slack not"
},
{
"path": "vendor/github.com/go-pkgz/notify/telegram.go",
"chars": 14082,
"preview": "package notify\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\tneturl \"net/url\"\n\t\"str"
},
{
"path": "vendor/github.com/go-pkgz/notify/webhook.go",
"chars": 2270,
"preview": "package notify\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n\t\"time\"\n)\n\nconst webhookTimeO"
},
{
"path": "vendor/github.com/go-pkgz/repeater/.gitignore",
"chars": 192,
"preview": "# Binaries for programs and plugins\n*.exe\n*.exe~\n*.dll\n*.so\n*.dylib\n\n# Test binary, build with `go test -c`\n*.test\n\n# Ou"
},
{
"path": "vendor/github.com/go-pkgz/repeater/.golangci.yml",
"chars": 1619,
"preview": "linters-settings:\n govet:\n check-shadowing: true\n golint:\n min-confidence: 0.6\n gocyclo:\n min-complexity: 15"
},
{
"path": "vendor/github.com/go-pkgz/repeater/LICENSE",
"chars": 1064,
"preview": "MIT License\n\nCopyright (c) 2023 Umputun\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof"
},
{
"path": "vendor/github.com/go-pkgz/repeater/README.md",
"chars": 2243,
"preview": "# Repeater [](https://github.com/go-pkgz/r"
},
{
"path": "vendor/github.com/go-pkgz/repeater/repeater.go",
"chars": 1963,
"preview": "// Package repeater call fun till it returns no error, up to repeat some number of iterations and delays defined by stra"
},
{
"path": "vendor/github.com/go-pkgz/repeater/strategy/backoff.go",
"chars": 1348,
"preview": "package strategy\n\nimport (\n\t\"context\"\n\t\"math\"\n\t\"math/rand\"\n\t\"sync\"\n\t\"time\"\n)\n\n// Backoff implements strategy.Interface f"
},
{
"path": "vendor/github.com/go-pkgz/repeater/strategy/fixed.go",
"chars": 688,
"preview": "package strategy\n\nimport (\n\t\"context\"\n\t\"time\"\n)\n\n// FixedDelay implements strategy.Interface for fixed intervals up to m"
},
{
"path": "vendor/github.com/go-pkgz/repeater/strategy/strategy.go",
"chars": 772,
"preview": "// Package strategy defines repeater's strategy and implements some.\n// Strategy result is a channel acting like time.Ti"
},
{
"path": "vendor/github.com/go-pkgz/routegroup/.gitignore",
"chars": 117,
"preview": "# Coverage files\ncoverage.out\ncoverage.html\n*.cover\n\n# Test binaries\n*.test\n\n# Go workspace files\ngo.work\ngo.work.sum"
},
{
"path": "vendor/github.com/go-pkgz/routegroup/.golangci.yml",
"chars": 1099,
"preview": "version: \"2\"\nrun:\n concurrency: 4\nlinters:\n default: none\n enable:\n - copyloopvar\n - gochecknoinits\n - gocri"
},
{
"path": "vendor/github.com/go-pkgz/routegroup/LICENSE",
"chars": 1064,
"preview": "MIT License\n\nCopyright (c) 2024 Umputun\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof"
},
{
"path": "vendor/github.com/go-pkgz/routegroup/README.md",
"chars": 15312,
"preview": "## routegroup [](https://github.com/go-p"
},
{
"path": "vendor/github.com/go-pkgz/routegroup/group.go",
"chars": 12646,
"preview": "// Package routegroup provides a way to group routes and applies middleware to them.\n// Works with the standard library'"
},
{
"path": "vendor/github.com/go-stack/stack/LICENSE.md",
"chars": 1078,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2014 Chris Hines\n\nPermission is hereby granted, free of charge, to any person obtai"
},
{
"path": "vendor/github.com/go-stack/stack/README.md",
"chars": 1559,
"preview": "[](https://godoc.org/github.com/go-stack/stack)\n[ (2024-01-16)\n\n\n### Features\n\n* add Max U"
},
{
"path": "vendor/github.com/google/uuid/CONTRIBUTING.md",
"chars": 956,
"preview": "# How to contribute\n\nWe definitely welcome patches and contribution to this project!\n\n### Tips\n\nCommits must be formatte"
},
{
"path": "vendor/github.com/google/uuid/CONTRIBUTORS",
"chars": 105,
"preview": "Paul Borman <borman@google.com>\nbmatsuo\nshawnps\ntheory\njboverfelt\ndsymonds\ncd1\nwallclockbuilder\ndansouza\n"
},
{
"path": "vendor/github.com/google/uuid/LICENSE",
"chars": 1480,
"preview": "Copyright (c) 2009,2014 Google Inc. All rights reserved.\n\nRedistribution and use in source and binary forms, with or wit"
},
{
"path": "vendor/github.com/google/uuid/README.md",
"chars": 839,
"preview": "# uuid\nThe uuid package generates and inspects UUIDs based on\n[RFC 4122](https://datatracker.ietf.org/doc/html/rfc4122)\n"
},
{
"path": "vendor/github.com/google/uuid/dce.go",
"chars": 2072,
"preview": "// Copyright 2016 Google Inc. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license tha"
},
{
"path": "vendor/github.com/google/uuid/doc.go",
"chars": 407,
"preview": "// Copyright 2016 Google Inc. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license tha"
},
{
"path": "vendor/github.com/google/uuid/hash.go",
"chars": 1963,
"preview": "// Copyright 2016 Google Inc. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license tha"
},
{
"path": "vendor/github.com/google/uuid/marshal.go",
"chars": 907,
"preview": "// Copyright 2016 Google Inc. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license tha"
},
{
"path": "vendor/github.com/google/uuid/node.go",
"chars": 2323,
"preview": "// Copyright 2016 Google Inc. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license tha"
},
{
"path": "vendor/github.com/google/uuid/node_js.go",
"chars": 498,
"preview": "// Copyright 2017 Google Inc. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license tha"
},
{
"path": "vendor/github.com/google/uuid/node_net.go",
"chars": 949,
"preview": "// Copyright 2017 Google Inc. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license tha"
},
{
"path": "vendor/github.com/google/uuid/null.go",
"chars": 2461,
"preview": "// Copyright 2021 Google Inc. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license tha"
},
{
"path": "vendor/github.com/google/uuid/sql.go",
"chars": 1459,
"preview": "// Copyright 2016 Google Inc. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license tha"
},
{
"path": "vendor/github.com/google/uuid/time.go",
"chars": 3795,
"preview": "// Copyright 2016 Google Inc. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license tha"
},
{
"path": "vendor/github.com/google/uuid/util.go",
"chars": 1920,
"preview": "// Copyright 2016 Google Inc. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license tha"
},
{
"path": "vendor/github.com/google/uuid/uuid.go",
"chars": 9633,
"preview": "// Copyright 2018 Google Inc. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license tha"
},
{
"path": "vendor/github.com/google/uuid/version1.go",
"chars": 1257,
"preview": "// Copyright 2016 Google Inc. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license tha"
},
{
"path": "vendor/github.com/google/uuid/version4.go",
"chars": 2054,
"preview": "// Copyright 2016 Google Inc. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license tha"
},
{
"path": "vendor/github.com/google/uuid/version6.go",
"chars": 2213,
"preview": "// Copyright 2023 Google Inc. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license tha"
},
{
"path": "vendor/github.com/google/uuid/version7.go",
"chars": 3371,
"preview": "// Copyright 2023 Google Inc. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license tha"
},
{
"path": "vendor/github.com/gorilla/css/LICENSE",
"chars": 1482,
"preview": "Copyright (c) 2023 The Gorilla Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or"
},
{
"path": "vendor/github.com/gorilla/css/scanner/doc.go",
"chars": 1104,
"preview": "// Copyright 2012 The Gorilla Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// lic"
},
{
"path": "vendor/github.com/gorilla/css/scanner/scanner.go",
"chars": 10819,
"preview": "// Copyright 2012 The Gorilla Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// lic"
},
{
"path": "vendor/github.com/gorilla/websocket/.gitignore",
"chars": 266,
"preview": "# Compiled Object files, Static and Dynamic libs (Shared Objects)\n*.o\n*.a\n*.so\n\n# Folders\n_obj\n_test\n\n# Architecture spe"
}
]
// ... and 1902 more files (download for full content)
About this extraction
This page contains the full source code of the umputun/secrets GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 2102 files (230.4 MB), approximately 26.3M tokens, and a symbol index with 290148 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.