Full Code of o8oo8o/GoWebSSH for AI

main 2784fa78fb3e cached
997 files
12.8 MB
3.4M tokens
107986 symbols
1 requests
Copy disabled (too large) Download .txt
Showing preview only (13,596K chars total). Download the full file to get everything.
Repository: o8oo8o/GoWebSSH
Branch: main
Commit: 2784fa78fb3e
Files: 997
Total size: 12.8 MB

Directory structure:
gitextract_q8k6q315/

├── .github/
│   └── workflows/
│       └── build-and-release.yml
├── .gitignore
├── Dockerfile
├── LICENSE
├── README.md
├── gossh/
│   ├── Makefile
│   ├── app/
│   │   ├── config/
│   │   │   └── config.go
│   │   ├── middleware/
│   │   │   ├── db_check.go
│   │   │   ├── jwt_auth.go
│   │   │   ├── net_filter.go
│   │   │   ├── perm_check.go
│   │   │   └── sys_init.go
│   │   ├── model/
│   │   │   ├── cmd_note.go
│   │   │   ├── datetime.go
│   │   │   ├── db_init.go
│   │   │   ├── login_audit.go
│   │   │   ├── net_filter.go
│   │   │   ├── policy_conf.go
│   │   │   ├── ssh_conf.go
│   │   │   ├── sshd_cert.go
│   │   │   ├── sshd_conf.go
│   │   │   ├── sshd_user.go
│   │   │   └── web_user.go
│   │   ├── service/
│   │   │   ├── cmd_note.go
│   │   │   ├── db_conn.go
│   │   │   ├── login_audit.go
│   │   │   ├── net_filter.go
│   │   │   ├── policy_conf.go
│   │   │   ├── service_init.go
│   │   │   ├── ssh_conf.go
│   │   │   ├── ssh_conn.go
│   │   │   ├── ssh_sftp.go
│   │   │   ├── ssh_status.go
│   │   │   ├── sshd_cert.go
│   │   │   ├── sshd_server.go
│   │   │   ├── sshd_user.go
│   │   │   ├── sys_init.go
│   │   │   └── web_user.go
│   │   └── utils/
│   │       ├── crypto.go
│   │       └── utils.go
│   ├── crypto/
│   │   ├── blowfish/
│   │   │   ├── block.go
│   │   │   ├── cipher.go
│   │   │   └── const.go
│   │   ├── chacha20/
│   │   │   ├── chacha_arm64.go
│   │   │   ├── chacha_arm64.s
│   │   │   ├── chacha_generic.go
│   │   │   ├── chacha_noasm.go
│   │   │   ├── chacha_ppc64le.go
│   │   │   ├── chacha_ppc64le.s
│   │   │   ├── chacha_s390x.go
│   │   │   ├── chacha_s390x.s
│   │   │   └── xor.go
│   │   ├── chacha20poly1305/
│   │   │   ├── chacha20poly1305.go
│   │   │   ├── chacha20poly1305_amd64.go
│   │   │   ├── chacha20poly1305_amd64.s
│   │   │   ├── chacha20poly1305_generic.go
│   │   │   ├── chacha20poly1305_noasm.go
│   │   │   └── xchacha20poly1305.go
│   │   ├── curve25519/
│   │   │   ├── curve25519.go
│   │   │   ├── curve25519_compat.go
│   │   │   ├── curve25519_go120.go
│   │   │   └── internal/
│   │   │       └── field/
│   │   │           ├── fe.go
│   │   │           ├── fe_amd64.go
│   │   │           ├── fe_amd64.s
│   │   │           ├── fe_amd64_noasm.go
│   │   │           ├── fe_arm64.go
│   │   │           ├── fe_arm64.s
│   │   │           ├── fe_arm64_noasm.go
│   │   │           ├── fe_generic.go
│   │   │           ├── sync.checkpoint
│   │   │           └── sync.sh
│   │   ├── internal/
│   │   │   ├── alias/
│   │   │   │   ├── alias.go
│   │   │   │   └── alias_purego.go
│   │   │   ├── poly1305/
│   │   │   │   ├── mac_noasm.go
│   │   │   │   ├── poly1305.go
│   │   │   │   ├── sum_amd64.go
│   │   │   │   ├── sum_amd64.s
│   │   │   │   ├── sum_generic.go
│   │   │   │   ├── sum_ppc64le.go
│   │   │   │   ├── sum_ppc64le.s
│   │   │   │   ├── sum_s390x.go
│   │   │   │   └── sum_s390x.s
│   │   │   └── testenv/
│   │   │       ├── exec.go
│   │   │       ├── testenv_notunix.go
│   │   │       └── testenv_unix.go
│   │   └── ssh/
│   │       ├── agent/
│   │       │   ├── client.go
│   │       │   ├── forward.go
│   │       │   ├── keyring.go
│   │       │   └── server.go
│   │       ├── buffer.go
│   │       ├── certs.go
│   │       ├── channel.go
│   │       ├── cipher.go
│   │       ├── client.go
│   │       ├── client_auth.go
│   │       ├── common.go
│   │       ├── connection.go
│   │       ├── doc.go
│   │       ├── handshake.go
│   │       ├── internal/
│   │       │   └── bcrypt_pbkdf/
│   │       │       └── bcrypt_pbkdf.go
│   │       ├── kex.go
│   │       ├── keys.go
│   │       ├── knownhosts/
│   │       │   └── knownhosts.go
│   │       ├── mac.go
│   │       ├── messages.go
│   │       ├── mux.go
│   │       ├── server.go
│   │       ├── session.go
│   │       ├── ssh_gss.go
│   │       ├── streamlocal.go
│   │       ├── tcpip.go
│   │       ├── terminal/
│   │       │   └── terminal.go
│   │       └── transport.go
│   ├── gin/
│   │   ├── auth.go
│   │   ├── binding/
│   │   │   ├── binding.go
│   │   │   ├── default_validator.go
│   │   │   ├── form.go
│   │   │   ├── form_mapping.go
│   │   │   ├── header.go
│   │   │   ├── json.go
│   │   │   ├── multipart_form_mapping.go
│   │   │   ├── query.go
│   │   │   ├── uri.go
│   │   │   └── xml.go
│   │   ├── context.go
│   │   ├── debug.go
│   │   ├── errors.go
│   │   ├── fs.go
│   │   ├── gin.go
│   │   ├── ginS/
│   │   │   ├── README.md
│   │   │   └── gins.go
│   │   ├── internal/
│   │   │   ├── bytesconv/
│   │   │   │   └── bytesconv.go
│   │   │   └── json/
│   │   │       └── json.go
│   │   ├── jwt/
│   │   │   ├── README.md
│   │   │   ├── claims.go
│   │   │   ├── cmd/
│   │   │   │   └── jwt/
│   │   │   │       ├── README.md
│   │   │   │       └── main.go
│   │   │   ├── ecdsa.go
│   │   │   ├── ecdsa_utils.go
│   │   │   ├── ed25519.go
│   │   │   ├── ed25519_utils.go
│   │   │   ├── errors.go
│   │   │   ├── errors_go1_20.go
│   │   │   ├── errors_go_other.go
│   │   │   ├── hmac.go
│   │   │   ├── map_claims.go
│   │   │   ├── none.go
│   │   │   ├── parser.go
│   │   │   ├── parser_option.go
│   │   │   ├── registered_claims.go
│   │   │   ├── request/
│   │   │   │   ├── doc.go
│   │   │   │   ├── extractor.go
│   │   │   │   ├── oauth2.go
│   │   │   │   └── request.go
│   │   │   ├── rsa.go
│   │   │   ├── rsa_pss.go
│   │   │   ├── rsa_utils.go
│   │   │   ├── signing_method.go
│   │   │   ├── token.go
│   │   │   ├── token_option.go
│   │   │   ├── types.go
│   │   │   └── validator.go
│   │   ├── logger.go
│   │   ├── mode.go
│   │   ├── path.go
│   │   ├── recovery.go
│   │   ├── render/
│   │   │   ├── data.go
│   │   │   ├── html.go
│   │   │   ├── json.go
│   │   │   ├── reader.go
│   │   │   ├── redirect.go
│   │   │   ├── render.go
│   │   │   ├── text.go
│   │   │   └── xml.go
│   │   ├── response_writer.go
│   │   ├── routergroup.go
│   │   ├── sessions/
│   │   │   ├── context/
│   │   │   │   └── context.go
│   │   │   ├── cookie/
│   │   │   │   └── cookie.go
│   │   │   ├── memstore/
│   │   │   │   ├── cache.go
│   │   │   │   ├── memstore.go
│   │   │   │   └── store.go
│   │   │   ├── securecookie/
│   │   │   │   └── securecookie.go
│   │   │   ├── session_options_go1.10.go
│   │   │   ├── session_options_go1.11.go
│   │   │   ├── sessions/
│   │   │   │   ├── cookie.go
│   │   │   │   ├── cookie_go111.go
│   │   │   │   ├── doc.go
│   │   │   │   ├── lex.go
│   │   │   │   ├── options.go
│   │   │   │   ├── options_go111.go
│   │   │   │   ├── sessions.go
│   │   │   │   └── store.go
│   │   │   └── sessions.go
│   │   ├── sse/
│   │   │   ├── sse-decoder.go
│   │   │   ├── sse-encoder.go
│   │   │   └── writer.go
│   │   ├── tree.go
│   │   ├── utils.go
│   │   ├── validator/
│   │   │   ├── baked_in.go
│   │   │   ├── cache.go
│   │   │   ├── country_codes.go
│   │   │   ├── currency_codes.go
│   │   │   ├── errors.go
│   │   │   ├── field_level.go
│   │   │   ├── options.go
│   │   │   ├── postcode_regexes.go
│   │   │   ├── regexes.go
│   │   │   ├── struct_level.go
│   │   │   ├── util.go
│   │   │   ├── validator.go
│   │   │   └── validator_instance.go
│   │   └── version.go
│   ├── go.mod
│   ├── gorm/
│   │   ├── association.go
│   │   ├── callbacks/
│   │   │   ├── associations.go
│   │   │   ├── callbacks.go
│   │   │   ├── callmethod.go
│   │   │   ├── create.go
│   │   │   ├── delete.go
│   │   │   ├── helper.go
│   │   │   ├── interfaces.go
│   │   │   ├── preload.go
│   │   │   ├── query.go
│   │   │   ├── raw.go
│   │   │   ├── row.go
│   │   │   ├── transaction.go
│   │   │   └── update.go
│   │   ├── callbacks.go
│   │   ├── chainable_api.go
│   │   ├── clause/
│   │   │   ├── clause.go
│   │   │   ├── delete.go
│   │   │   ├── expression.go
│   │   │   ├── from.go
│   │   │   ├── group_by.go
│   │   │   ├── insert.go
│   │   │   ├── joins.go
│   │   │   ├── limit.go
│   │   │   ├── locking.go
│   │   │   ├── on_conflict.go
│   │   │   ├── order_by.go
│   │   │   ├── returning.go
│   │   │   ├── select.go
│   │   │   ├── set.go
│   │   │   ├── update.go
│   │   │   ├── values.go
│   │   │   ├── where.go
│   │   │   └── with.go
│   │   ├── driver/
│   │   │   ├── mysql/
│   │   │   │   ├── error_translator.go
│   │   │   │   ├── migrator.go
│   │   │   │   └── mysql.go
│   │   │   └── pgsql/
│   │   │       ├── error_translator.go
│   │   │       ├── migrator.go
│   │   │       └── postgres.go
│   │   ├── errors.go
│   │   ├── finisher_api.go
│   │   ├── gorm.go
│   │   ├── inflection/
│   │   │   └── inflections.go
│   │   ├── interfaces.go
│   │   ├── logger/
│   │   │   ├── logger.go
│   │   │   └── sql.go
│   │   ├── migrator/
│   │   │   ├── column_type.go
│   │   │   ├── index.go
│   │   │   ├── migrator.go
│   │   │   └── table_type.go
│   │   ├── migrator.go
│   │   ├── model.go
│   │   ├── now/
│   │   │   ├── main.go
│   │   │   ├── now.go
│   │   │   └── time.go
│   │   ├── prepare_stmt.go
│   │   ├── scan.go
│   │   ├── schema/
│   │   │   ├── constraint.go
│   │   │   ├── field.go
│   │   │   ├── index.go
│   │   │   ├── interfaces.go
│   │   │   ├── naming.go
│   │   │   ├── pool.go
│   │   │   ├── relationship.go
│   │   │   ├── schema.go
│   │   │   ├── serializer.go
│   │   │   └── utils.go
│   │   ├── soft_delete.go
│   │   ├── statement.go
│   │   └── utils/
│   │       ├── tests/
│   │       │   ├── dummy_dialecter.go
│   │       │   ├── models.go
│   │       │   └── utils.go
│   │       └── utils.go
│   ├── main.go
│   ├── mysql/
│   │   ├── atomic_bool.go
│   │   ├── atomic_bool_go118.go
│   │   ├── auth.go
│   │   ├── buffer.go
│   │   ├── collations.go
│   │   ├── conncheck.go
│   │   ├── conncheck_dummy.go
│   │   ├── connection.go
│   │   ├── connector.go
│   │   ├── const.go
│   │   ├── driver.go
│   │   ├── dsn.go
│   │   ├── errors.go
│   │   ├── fields.go
│   │   ├── infile.go
│   │   ├── nulltime.go
│   │   ├── packets.go
│   │   ├── result.go
│   │   ├── rows.go
│   │   ├── statement.go
│   │   ├── transaction.go
│   │   └── utils.go
│   ├── pgsql/
│   │   ├── array.go
│   │   ├── buf.go
│   │   ├── conn.go
│   │   ├── conn_go115.go
│   │   ├── conn_go18.go
│   │   ├── connector.go
│   │   ├── copy.go
│   │   ├── encode.go
│   │   ├── error.go
│   │   ├── hstore/
│   │   │   └── hstore.go
│   │   ├── krb.go
│   │   ├── notice.go
│   │   ├── notify.go
│   │   ├── oid/
│   │   │   ├── doc.go
│   │   │   ├── gen.go
│   │   │   └── types.go
│   │   ├── rows.go
│   │   ├── scram/
│   │   │   └── scram.go
│   │   ├── ssl.go
│   │   ├── ssl_permissions.go
│   │   ├── ssl_windows.go
│   │   ├── url.go
│   │   ├── user_other.go
│   │   ├── user_posix.go
│   │   ├── user_windows.go
│   │   └── uuid.go
│   ├── pty/
│   │   ├── asm_solaris_amd64.s
│   │   ├── cmd_windows.go
│   │   ├── doc.go
│   │   ├── ioctl.go
│   │   ├── ioctl_bsd.go
│   │   ├── ioctl_inner.go
│   │   ├── ioctl_legacy.go
│   │   ├── ioctl_solaris.go
│   │   ├── ioctl_unsupported.go
│   │   ├── pty_darwin.go
│   │   ├── pty_dragonfly.go
│   │   ├── pty_freebsd.go
│   │   ├── pty_linux.go
│   │   ├── pty_netbsd.go
│   │   ├── pty_openbsd.go
│   │   ├── pty_solaris.go
│   │   ├── pty_unsupported.go
│   │   ├── pty_windows.go
│   │   ├── run.go
│   │   ├── run_unix.go
│   │   ├── run_windows.go
│   │   ├── types.go
│   │   ├── types_dragonfly.go
│   │   ├── types_freebsd.go
│   │   ├── types_netbsd.go
│   │   ├── types_openbsd.go
│   │   ├── winsize.go
│   │   ├── winsize_unix.go
│   │   ├── winsize_windows.go
│   │   ├── ztypes_386.go
│   │   ├── ztypes_amd64.go
│   │   ├── ztypes_arm.go
│   │   ├── ztypes_arm64.go
│   │   ├── ztypes_dragonfly_amd64.go
│   │   ├── ztypes_freebsd_386.go
│   │   ├── ztypes_freebsd_amd64.go
│   │   ├── ztypes_freebsd_arm.go
│   │   ├── ztypes_freebsd_arm64.go
│   │   ├── ztypes_freebsd_ppc64.go
│   │   ├── ztypes_freebsd_riscv64.go
│   │   ├── ztypes_loong64.go
│   │   ├── ztypes_mipsx.go
│   │   ├── ztypes_netbsd_32bit_int.go
│   │   ├── ztypes_openbsd_32bit_int.go
│   │   ├── ztypes_ppc.go
│   │   ├── ztypes_ppc64.go
│   │   ├── ztypes_ppc64le.go
│   │   ├── ztypes_riscvx.go
│   │   ├── ztypes_s390x.go
│   │   └── ztypes_sparcx.go
│   ├── readme.md
│   ├── sftp/
│   │   ├── allocator.go
│   │   ├── attrs.go
│   │   ├── attrs_stubs.go
│   │   ├── attrs_unix.go
│   │   ├── client.go
│   │   ├── conn.go
│   │   ├── debug.go
│   │   ├── fuzz.go
│   │   ├── internal/
│   │   │   ├── encoding/
│   │   │   │   └── ssh/
│   │   │   │       └── filexfer/
│   │   │   │           ├── attrs.go
│   │   │   │           ├── buffer.go
│   │   │   │           ├── extended_packets.go
│   │   │   │           ├── extensions.go
│   │   │   │           ├── filexfer.go
│   │   │   │           ├── fx.go
│   │   │   │           ├── fxp.go
│   │   │   │           ├── handle_packets.go
│   │   │   │           ├── init_packets.go
│   │   │   │           ├── open_packets.go
│   │   │   │           ├── openssh/
│   │   │   │           │   ├── fsync.go
│   │   │   │           │   ├── hardlink.go
│   │   │   │           │   ├── openssh.go
│   │   │   │           │   ├── posix-rename.go
│   │   │   │           │   └── statvfs.go
│   │   │   │           ├── packets.go
│   │   │   │           ├── path_packets.go
│   │   │   │           ├── permissions.go
│   │   │   │           └── response_packets.go
│   │   │   └── sftpfs/
│   │   │       ├── filesystem.go
│   │   │       └── walk.go
│   │   ├── ls_formatting.go
│   │   ├── ls_plan9.go
│   │   ├── ls_stub.go
│   │   ├── ls_unix.go
│   │   ├── match.go
│   │   ├── packet-manager.go
│   │   ├── packet-typing.go
│   │   ├── packet.go
│   │   ├── pool.go
│   │   ├── release.go
│   │   ├── request-attrs.go
│   │   ├── request-errors.go
│   │   ├── request-example.go
│   │   ├── request-interfaces.go
│   │   ├── request-plan9.go
│   │   ├── request-server.go
│   │   ├── request-unix.go
│   │   ├── request.go
│   │   ├── request_windows.go
│   │   ├── server.go
│   │   ├── server_plan9.go
│   │   ├── server_statvfs_darwin.go
│   │   ├── server_statvfs_impl.go
│   │   ├── server_statvfs_linux.go
│   │   ├── server_statvfs_plan9.go
│   │   ├── server_statvfs_stubs.go
│   │   ├── server_unix.go
│   │   ├── server_windows.go
│   │   ├── sftp.go
│   │   ├── stat_plan9.go
│   │   ├── stat_posix.go
│   │   ├── syscall_fixed.go
│   │   └── syscall_good.go
│   ├── sqlite/
│   │   ├── ddlmod.go
│   │   ├── errors.go
│   │   ├── migrator.go
│   │   └── sqlite.go
│   ├── sys/
│   │   ├── cpu/
│   │   │   ├── asm_aix_ppc64.s
│   │   │   ├── byteorder.go
│   │   │   ├── cpu.go
│   │   │   ├── cpu_aix.go
│   │   │   ├── cpu_arm.go
│   │   │   ├── cpu_arm64.go
│   │   │   ├── cpu_arm64.s
│   │   │   ├── cpu_gc_arm64.go
│   │   │   ├── cpu_gc_s390x.go
│   │   │   ├── cpu_gc_x86.go
│   │   │   ├── 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_mips64x.go
│   │   │   ├── cpu_linux_noinit.go
│   │   │   ├── cpu_linux_ppc64x.go
│   │   │   ├── cpu_linux_s390x.go
│   │   │   ├── cpu_loong64.go
│   │   │   ├── 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_ppc64x.go
│   │   │   ├── cpu_riscv64.go
│   │   │   ├── cpu_s390x.go
│   │   │   ├── cpu_s390x.s
│   │   │   ├── cpu_wasm.go
│   │   │   ├── cpu_x86.go
│   │   │   ├── cpu_x86.s
│   │   │   ├── 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
│   │   ├── execabs/
│   │   │   ├── execabs.go
│   │   │   ├── execabs_go118.go
│   │   │   └── execabs_go119.go
│   │   ├── plan9/
│   │   │   ├── asm.s
│   │   │   ├── asm_plan9_386.s
│   │   │   ├── asm_plan9_amd64.s
│   │   │   ├── asm_plan9_arm.s
│   │   │   ├── const_plan9.go
│   │   │   ├── dir_plan9.go
│   │   │   ├── env_plan9.go
│   │   │   ├── errors_plan9.go
│   │   │   ├── mkall.sh
│   │   │   ├── mkerrors.sh
│   │   │   ├── mksyscall.go
│   │   │   ├── mksysnum_plan9.sh
│   │   │   ├── pwd_go15_plan9.go
│   │   │   ├── pwd_plan9.go
│   │   │   ├── race.go
│   │   │   ├── race0.go
│   │   │   ├── str.go
│   │   │   ├── syscall.go
│   │   │   ├── syscall_plan9.go
│   │   │   ├── zsyscall_plan9_386.go
│   │   │   ├── zsyscall_plan9_amd64.go
│   │   │   ├── zsyscall_plan9_arm.go
│   │   │   └── zsysnum_plan9.go
│   │   ├── unix/
│   │   │   ├── 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
│   │   │   ├── bluetooth_linux.go
│   │   │   ├── 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
│   │   │   ├── epoll_zos.go
│   │   │   ├── fcntl.go
│   │   │   ├── fcntl_darwin.go
│   │   │   ├── fcntl_linux_32bit.go
│   │   │   ├── fdset.go
│   │   │   ├── fstatfs_zos.go
│   │   │   ├── gccgo.go
│   │   │   ├── gccgo_c.c
│   │   │   ├── gccgo_linux_amd64.go
│   │   │   ├── ifreq_linux.go
│   │   │   ├── internal/
│   │   │   │   └── mkmerge/
│   │   │   │       └── mkmerge.go
│   │   │   ├── ioctl_linux.go
│   │   │   ├── ioctl_signed.go
│   │   │   ├── ioctl_unsigned.go
│   │   │   ├── ioctl_zos.go
│   │   │   ├── linux/
│   │   │   │   ├── Dockerfile
│   │   │   │   ├── mkall.go
│   │   │   │   ├── mksysnum.go
│   │   │   │   └── types.go
│   │   │   ├── mkall.sh
│   │   │   ├── mkasm.go
│   │   │   ├── mkerrors.sh
│   │   │   ├── mkpost.go
│   │   │   ├── mksyscall.go
│   │   │   ├── mksyscall_aix_ppc.go
│   │   │   ├── mksyscall_aix_ppc64.go
│   │   │   ├── mksyscall_solaris.go
│   │   │   ├── mksysctl_openbsd.go
│   │   │   ├── mksysnum.go
│   │   │   ├── 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
│   │   │   ├── 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
│   │   │   ├── types_aix.go
│   │   │   ├── types_darwin.go
│   │   │   ├── types_dragonfly.go
│   │   │   ├── types_freebsd.go
│   │   │   ├── types_netbsd.go
│   │   │   ├── types_openbsd.go
│   │   │   ├── types_solaris.go
│   │   │   ├── unveil_openbsd.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
│   │   │   ├── 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
│   │   ├── websocket/
│   │   │   ├── client.go
│   │   │   ├── dial.go
│   │   │   ├── hybi.go
│   │   │   ├── server.go
│   │   │   └── websocket.go
│   │   └── windows/
│   │       ├── aliases.go
│   │       ├── dll_windows.go
│   │       ├── empty.s
│   │       ├── env_windows.go
│   │       ├── eventlog.go
│   │       ├── exec_windows.go
│   │       ├── memory_windows.go
│   │       ├── mkerrors.bash
│   │       ├── mkknownfolderids.bash
│   │       ├── mksyscall.go
│   │       ├── mkwinsyscall/
│   │       │   └── mkwinsyscall.go
│   │       ├── race.go
│   │       ├── race0.go
│   │       ├── registry/
│   │       │   ├── key.go
│   │       │   ├── mksyscall.go
│   │       │   ├── syscall.go
│   │       │   ├── value.go
│   │       │   └── zsyscall_windows.go
│   │       ├── security_windows.go
│   │       ├── service.go
│   │       ├── setupapi_windows.go
│   │       ├── str.go
│   │       ├── svc/
│   │       │   ├── debug/
│   │       │   │   ├── log.go
│   │       │   │   └── service.go
│   │       │   ├── eventlog/
│   │       │   │   ├── install.go
│   │       │   │   └── log.go
│   │       │   ├── mgr/
│   │       │   │   ├── config.go
│   │       │   │   ├── mgr.go
│   │       │   │   ├── recovery.go
│   │       │   │   └── service.go
│   │       │   ├── security.go
│   │       │   └── service.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
│   ├── term/
│   │   ├── term.go
│   │   ├── term_plan9.go
│   │   ├── term_unix.go
│   │   ├── term_unix_bsd.go
│   │   ├── term_unix_other.go
│   │   ├── term_unsupported.go
│   │   ├── term_windows.go
│   │   └── terminal.go
│   ├── toml/
│   │   ├── README.md
│   │   ├── decode.go
│   │   ├── errors.go
│   │   ├── internal/
│   │   │   ├── characters/
│   │   │   │   ├── ascii.go
│   │   │   │   └── utf8.go
│   │   │   ├── cli/
│   │   │   │   └── cli.go
│   │   │   ├── danger/
│   │   │   │   ├── danger.go
│   │   │   │   └── typeid.go
│   │   │   ├── testsuite/
│   │   │   │   ├── add.go
│   │   │   │   ├── json.go
│   │   │   │   ├── parser.go
│   │   │   │   ├── rm.go
│   │   │   │   └── testsuite.go
│   │   │   └── tracker/
│   │   │       ├── key.go
│   │   │       ├── seen.go
│   │   │       └── tracker.go
│   │   ├── localtime.go
│   │   ├── marshaler.go
│   │   ├── strict.go
│   │   ├── types.go
│   │   ├── unmarshaler.go
│   │   └── unstable/
│   │       ├── ast.go
│   │       ├── builder.go
│   │       ├── doc.go
│   │       ├── kind.go
│   │       ├── parser.go
│   │       ├── scanner.go
│   │       └── unmarshaler.go
│   ├── webroot/
│   │   ├── assets/
│   │   │   ├── About-BpAaEtx1.js
│   │   │   ├── About-CLFeE-IU.css
│   │   │   ├── Manage-BTEK3ejV.css
│   │   │   ├── Manage-D_HsZWaT.js
│   │   │   ├── NotFound-Ts0Rt7lc.js
│   │   │   ├── SysInit-Lho0-Z3X.css
│   │   │   ├── SysInit-UcmoR0-x.js
│   │   │   ├── el-card-fwQOLwdi.css
│   │   │   ├── index-D6GWZ696.css
│   │   │   └── index-jH42E5tC.js
│   │   ├── index.html
│   │   └── readme.md
│   └── websocket/
│       ├── client.go
│       ├── compression.go
│       ├── conn.go
│       ├── doc.go
│       ├── join.go
│       ├── json.go
│       ├── mask.go
│       ├── mask_safe.go
│       ├── prepared.go
│       ├── proxy.go
│       ├── server.go
│       └── util.go
├── postman.json
├── sshd.dockerfile
└── webssh/
    ├── .gitignore
    ├── README.md
    ├── auto-imports.d.ts
    ├── components.d.ts
    ├── env.d.ts
    ├── index.html
    ├── package.json
    ├── src/
    │   ├── App.vue
    │   ├── components/
    │   │   ├── Account.vue
    │   │   ├── Connect.vue
    │   │   ├── LoginAudit.vue
    │   │   ├── NetFilter.vue
    │   │   ├── SshdCert.vue
    │   │   └── SshdUser.vue
    │   ├── main.ts
    │   ├── router/
    │   │   └── index.ts
    │   ├── stores/
    │   │   └── store.ts
    │   └── views/
    │       ├── About.vue
    │       ├── Empty.vue
    │       ├── Home.vue
    │       ├── Login.vue
    │       ├── Manage.vue
    │       ├── NotFound.vue
    │       └── SysInit.vue
    ├── tsconfig.app.json
    ├── tsconfig.json
    ├── tsconfig.node.json
    └── vite.config.ts

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/workflows/build-and-release.yml
================================================
name: Build & Release

on:
  push:
    tags:
      - 'v*'

jobs:
  build-release:
    runs-on: ubuntu-latest
    name: Build and Release for Multiple OS & Arch
    permissions:
      contents: write
    
    strategy:
      matrix:
        include:
          # Windows targets (64-bit only)
          - os: windows
            goos: windows
            arch: amd64
            suffix: .exe
          - os: windows
            goos: windows
            arch: arm64
            suffix: .exe
          
          # Linux targets (64-bit architectures)
          - os: linux
            goos: linux
            arch: amd64
            suffix: ''
          - os: linux
            goos: linux
            arch: arm64
            suffix: ''
          
          # macOS targets (64-bit only)
          - os: macos
            goos: darwin
            arch: amd64
            suffix: ''
          - os: macos
            goos: darwin
            arch: arm64
            suffix: ''

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Go
        uses: actions/setup-go@v5
        with:
          go-version: '1.24.5'

      - name: Prepare workspace
        run: |
          echo "📂 Workspace structure:"
          ls -la
          
          echo "📂 gossh directory content:"
          ls -la gossh
          
          # 确保目录存在
          if [ ! -d "gossh" ]; then
            echo "❌ Error: gossh directory not found!"
            exit 1
          fi
          
          # 进入gossh目录准备构建
          cd gossh
          
          # 更新依赖
          go mod tidy
          go mod download

      - name: Build for ${{ matrix.os }} (${{ matrix.arch }})
        run: |
          cd gossh
          
          # 静态编译
          CGO_ENABLED=0 GOOS=${{ matrix.goos }} GOARCH=${{ matrix.arch }} \
            go build -trimpath -ldflags="-s -w" -o GoWebSSH${{ matrix.suffix }}
          
          # 验证构建结果
          if [ -f "GoWebSSH${{ matrix.suffix }}" ]; then
            echo "✅ Build successful! Output file: GoWebSSH${{ matrix.suffix }}"
          else
            echo "❌ Build failed! No output file found in: $(pwd)"
            ls -la
            exit 1
          fi
          
          # 创建压缩包(在仓库根目录)
          zip -j ../GoWebSSH-${{ matrix.os }}-${{ matrix.arch }}.zip GoWebSSH${{ matrix.suffix }}

      - name: Create Release and Upload Assets
        uses: softprops/action-gh-release@v2
        with:
          name: ${{ github.ref_name }}
          tag_name: ${{ github.ref_name }}
          files: |
            GoWebSSH-*.zip


================================================
FILE: .gitignore
================================================
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage
*.lcov

# nyc test coverage
.nyc_output

# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# TypeScript v1 declaration files
typings/

# TypeScript cache
*.tsbuildinfo

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env
.env.test

# parcel-bundler cache (https://parceljs.org/)
.cache

# Next.js build output
.next

# Nuxt.js build / generate output
.nuxt
dist

# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and *not* Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public

# vuepress build output
.vuepress/dist

# Serverless directories
.serverless/

# FuseBox cache
.fusebox/

# DynamoDB Local files
.dynamodb/

# TernJS port file
.tern-port

######################
# OS generated files #
######################
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db

######################
# ide #
######################

.idea
*.iml
/gossh/go.sum
/gossh/gossh
/gossh/GoWebSSH.db


================================================
FILE: Dockerfile
================================================
# 第一阶段:构建
FROM golang:1.23.4 AS builder
WORKDIR /mnt
COPY gossh ./gossh
RUN cd /mnt/gossh && CGO_ENABLED=0 go build -o /mnt/gowebssh

# 第二阶段:运行
FROM alpine:3.21.0
WORKDIR /root/
VOLUME /var/lib/webssh
EXPOSE 8899
COPY --from=builder /mnt/gowebssh /bin/gowebssh
CMD ["/bin/gowebssh", "-WorkDir", "/var/lib/webssh"]

================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2021 o8oo8o

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
## GoWebSSH
<br/>

### 项目介绍:
* **Web版ssh客户端 + (sshd,sftp)服务端实现**
<br/>

### 概要:
* Golang 1.23 + (Vue3.5 + Vite6)  实现一个Web版单文件的(SSH+SSHD)
* 借助于Golang embed,打包以后只有一个文件,简单高效
* 使用及编译过程,超级简单,绝对保姆级
* 上一版主要本地运行,但是通过部分用户反馈,此项目定位改为服务器运行,所以此版本加入了很多企业场景中的功能
<br/>

### 联系我:
* **QQ:774309635**
<br/>

---
### Quick start(大象装进冰箱只需3步):
>  必须使用golang 1.21以上版本
* git clone https://github.com/o8oo8o/WebSSH.git
* cd WebSSH/gossh
* go build
* ./gossh
>  打开链接 http://127.0.0.1:8899/ 开始享用吧,第一次需要初始化
<br/>

### Docker 方式:
* git clone https://github.com/o8oo8o/WebSSH.git
* cd WebSSH
* docker build -f Dockerfile -t gowebssh:v2 .
* docker run -d --name webssh -p 8899:8899 -v gowebssh:/var/lib/webssh gowebssh:v2
<br/>

### 打赏我:
* **每一个开源项目的背后,都有一群默默付出、充满激情的开发者。他们用自己的业余时间,不断地优化代码、修复bug、撰写文档,只为让项目变得更好。如果您觉得我的项目对您有所帮助,如果您认可我的努力和付出,那么请考虑给予我一点小小的打赏,够买一瓶啤酒就行🍺,如果能同时打赏啤酒花生那更好🍺🥜,因为所有的代码都是喝完酒撸的。放上收款码的时候我是羞愧的,一个中年男人的最后的尊严和节操竟然没了😂,友情提示:打赏不退,怕被媳妇查到大额支出🥸,如果需要技术支持,需要收费哦**
<br/>
<br/>

![打赏二维码](https://gitee.com/o8oo8o/WebSSH/raw/main/img/pay.png)

<br/>

### 运行环境依赖:
* 需要MySQL8+及PostgreSQL12.2+或者直接使用内置SQLite数据库

### SSHD服务器功能:
* 可以配置只监听本地端口
* 支持Web配置sshd服务器账号密码及公钥
* 支持密码认证,公钥认证,增强登录过程的安全性
* 通过SFTP或SCP用户可以安全地在本地和远程服务器之间传输文件
<br/>

### Web客户端主要功能:
* 支持同时连接多个主机,支持重连、清屏功能
* 支持IPv4、IPv6
* 支持SSH证书登陆及证书密码
* 支持批量支持命令,当前终端及所有终端
* 支持命令收藏,方便重复执行命令,批量发送命令到所有会话
* 可以保存主机连接信息
* 支持直接通过Web上传下载文件
* 支持直接通过Web创建目录,删除文件及目录功能
* 支持手动输入路径
* 支持自定义终端字体大小、字体颜色、字体样式
* 支持自定义背景、光标颜色及光标样式
* 已保存的主机信息可直接编辑并连接
* 支持后台管理,强制断开连接
* 支持登陆日志审计,方便监控违规操作
* 支持访问控制,在公网场景中有效拦截非法访问
<br/>

### 为什么这么简单:
* 为了方便您使用,把golang编译的依赖已经整理好了,clone就一起下载了
* 前端已经编译完成,并把编译完成的静态资源拷贝到gossh/webroot目录中
* 可执行文件内嵌静态资源,方便你随性所欲的移动可执行文件
* 因内置sshd服务器,在受限的网络环境依然能通过web访问
<br/>

### 配置文件:
* 第一次运行会在用户home目录创建一个 .GoWebSSH 目录
* GoWebSSH.toml 可以配置server端口等信息
* cert.pem HTTPS服务器证书文件
* key.key  HTTPS服务器私钥文件
<br/>

### 注意: 
* 当程序检测到cert.pem 和 key.key 文件,会使用https协议,否则使用http协议
* 用户只需把证书文件和私钥文件放到 .GoWebSSH 目录就可以了
```shell
openssl genpkey -algorithm RSA -out key.key -pkeyopt rsa_keygen_bits:2048

openssl req -new -x509 -key key.key -out cert.pem -days 365 -subj "/C=CN/ST=bj/L=bj/O=gowebssh/OU=gowebssh/CN=gowebssh.com"
```
<br/>

### Systemd 方式启动: 
```shell
cat > /etc/systemd/system/gowebssh.service << "END"
##################################
[Unit]
Description=GoWebSSH Daemon
After=network.target
Wants=network-online.target

[Service]
Type=simple
User=root
Environment=TERM=xterm
Environment=XDG_SESSION_TYPE=tty
Environment=HOME=/root
PrivateTmp=true
LimitNOFILE=65535

# 执行程序路径
ExecStart=/usr/local/gossh

# auto restart
StartLimitIntervalSec=0
Restart=always
RestartSec=1

[Install]
WantedBy=multi-user.target
##################################
END

systemctl daemon-reload

systemctl start gowebssh.service

systemctl enable gowebssh.service

```
<br/>

---
### 演示截图:
![a](https://gitee.com/o8oo8o/WebSSH/raw/main/img/a.jpg)
![b](https://gitee.com/o8oo8o/WebSSH/raw/main/img/b.jpg)
![c](https://gitee.com/o8oo8o/WebSSH/raw/main/img/c.jpg)
![d](https://gitee.com/o8oo8o/WebSSH/raw/main/img/d.jpg)
![e](https://gitee.com/o8oo8o/WebSSH/raw/main/img/e.jpg)
![f](https://gitee.com/o8oo8o/WebSSH/raw/main/img/f.jpg)




================================================
FILE: gossh/Makefile
================================================

.PHONY: clean all

all: linux-amd64 linux-arm64 macos-amd64 macos-arm64 windows-amd64

linux-amd64:
	CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o WebSSH-linux-amd64

linux-arm64:
	CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o WebSSH-linux-arm64

macos-amd64:
	CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -o WebSSH-macos-amd64

macos-arm64:
	CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -o WebSSH-macos-arm64

windows-amd64:
	CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o WebSSH-windows-amd64.exe

WebSSH:
	go build -o WebSSH

clean:
	rm -f WebSSH-linux-amd64 WebSSH-linux-arm64 WebSSH-macos-amd64 WebSSH-macos-arm64 WebSSH-windows-amd64.exe


================================================
FILE: gossh/app/config/config.go
================================================
package config

import (
	"flag"
	"gossh/app/utils"
	"gossh/toml"
	"log/slog"
	"os"
	"path"
	"time"
)

type AppConfig struct {
	WebBaseDir    string        `json:"web_base_dir"  toml:"web_base_dir"`
	AppName       string        `json:"app_name"  toml:"app_name"`
	DbType        string        `json:"db_type" toml:"db_type"`
	DbDsn         string        `json:"db_dsn" toml:"db_dsn"`
	IsInit        bool          `json:"is_init" toml:"is_init"`
	JwtSecret     string        `json:"jwt_secret" toml:"jwt_secret"`
	AesSecret     string        `json:"aes_secret" toml:"aes_secret"`
	JwtExpire     time.Duration `json:"jwt_expire" toml:"jwt_expire"`
	StatusRefresh time.Duration `json:"status_refresh" toml:"status_refresh"`
	ClientCheck   time.Duration `json:"client_check" toml:"client_check"`
	SessionSecret string        `json:"session_secret" toml:"session_secret"`
	Address       string        `json:"address" toml:"address"`
	Port          string        `json:"port" toml:"port"`
	CertFile      string        `json:"cert_file" toml:"cert_file"`
	KeyFile       string        `json:"key_file" toml:"key_file"`
}

func (c *AppConfig) write() error {
	data, err := toml.Marshal(c)
	if err != nil {
		slog.Error("序列化TOML配置文件错误:", "err_msg", err)
		return err
	}

	err = os.WriteFile(confFileFullPath, data, os.FileMode(0777))
	if err != nil {
		slog.Error("写入默认配置文件错误:", "err_msg", err.Error())
		return err
	}
	return nil
}

var DefaultConfig = AppConfig{
	WebBaseDir:    "",
	AppName:       "GoWebSHH",
	DbType:        "mysql",
	DbDsn:         "",
	IsInit:        false,
	JwtSecret:     utils.RandString(64),
	AesSecret:     utils.RandString(32),
	SessionSecret: utils.RandString(64),
	JwtExpire:     time.Minute * 120,
	StatusRefresh: time.Second * 3,
	ClientCheck:   time.Second * 15,
	Address:       "",
	Port:          "8899",
	CertFile:      path.Join(WorkDir, "cert.pem"),
	KeyFile:       path.Join(WorkDir, "key.key"),
}

var UserHomeDir, _ = os.UserHomeDir()

var projectName = "GoWebSSH"

var confFileName = "GoWebSSH.toml"

var confPath = string(os.PathSeparator) + "." + projectName + string(os.PathSeparator)

// WorkDir 程序默认工作目录,在用户的home目录下 .GoWebSSH 目录
var WorkDir = path.Join(UserHomeDir, confPath)

var confFileFullPath = path.Join(WorkDir, confFileName)

func InitConfig() {
	defer func() {
		if err := recover(); err != nil {
			slog.Error("init config failed", "err_msg", err)
			os.Exit(255)
		}
	}()

	var configDir string
	var webBaseDir string
	flag.StringVar(&configDir, "ConfigDir", "", "ConfigDir")
	flag.StringVar(&webBaseDir, "WebBaseDir", "", "WebBaseDir")
	flag.Parse()
	DefaultConfig.WebBaseDir = configDir
	if configDir != "" {
		WorkDir = path.Join(configDir, confPath)
		confFileFullPath = path.Join(WorkDir, confFileName)
		DefaultConfig.CertFile = path.Join(WorkDir, "cert.pem")
		DefaultConfig.KeyFile = path.Join(WorkDir, "key.key")
	}
	slog.Info("use-config-file", "path", confFileFullPath)

	info, err := os.Stat(WorkDir)
	if os.IsNotExist(err) {
		err := os.MkdirAll(WorkDir, os.FileMode(0755))
		if err != nil {
			slog.Error("创建工作目录失败")
			return
		}
	}

	info, err = os.Stat(WorkDir)
	if !info.IsDir() {
		slog.Error("有一个和工作目录同名的目录", "dir", WorkDir)
		return
	}

	_, err = os.Stat(confFileFullPath)
	if os.IsNotExist(err) {
		if err := DefaultConfig.write(); err != nil {
			return
		}
	}

	data, err := os.ReadFile(confFileFullPath)
	if err != nil {
		slog.Error("读取配置文件错误:", "err_msg", err.Error())
		return
	}

	err = toml.Unmarshal(data, &DefaultConfig)
	if err != nil {
		slog.Error("TOML解析配置文件错误:", "err_msg", err.Error())
		return
	}

	// 修正webBaseDir
	if DefaultConfig.WebBaseDir != webBaseDir {
		DefaultConfig.WebBaseDir = webBaseDir
		if err := DefaultConfig.write(); err != nil {
			return
		}
	}
	slog.Debug("DefaultConfig:", "data", DefaultConfig)

}

func RewriteConfig(conf AppConfig) error {
	data, err := toml.Marshal(conf)
	if err != nil {
		slog.Error("序列化TOML配置文件错误:", "err_msg", err)
		return err
	}
	// 覆盖全局变量
	DefaultConfig = conf
	err = os.Remove(confFileFullPath)
	if err != nil {
		slog.Error("删除旧配置文件错误:", "err_msg", err.Error())
		return err
	}
	err = os.WriteFile(confFileFullPath, data, os.FileMode(0777))
	if err != nil {
		slog.Error("写入默认配置文件错误:", "err_msg", err.Error())
		return err
	}
	return nil
}


================================================
FILE: gossh/app/middleware/db_check.go
================================================
package middleware

import (
	"gossh/app/config"
	"gossh/app/model"
	"gossh/gin"
)

func DbCheck() gin.HandlerFunc {
	return func(c *gin.Context) {
		if !config.DefaultConfig.IsInit {
			c.Next()
			return
		}
		if model.Db != nil {
			tx := model.Db.Exec("select 1=1")
			if tx.Error == nil {
				c.Next()
			} else {
				err := model.DbMigrate(config.DefaultConfig.DbType, config.DefaultConfig.DbDsn)
				if err != nil {
					c.Abort()
					c.JSON(500, gin.H{"code": 500, "msg": "数据库连接错误:" + err.Error()})
					return
				}
			}
		}
		c.Next()
	}
}


================================================
FILE: gossh/app/middleware/jwt_auth.go
================================================
package middleware

import (
	"errors"
	"gossh/app/config"
	"gossh/gin"
	"gossh/gin/jwt"
	"strings"
	"time"
)

// JwtSecret 生成JWT签名的密钥
var JwtSecret = []byte(config.DefaultConfig.JwtSecret)

type JwtClaims struct {
	// 用户Id
	Id uint

	// 标准Claims结构体,可设置8个标准字段
	jwt.RegisteredClaims
}

// GenerateToken 登录成功后调用,传入SshUser结构体
func GenerateToken(id uint) (string, error) {

	// 两个小时有效期
	expirationTime := time.Now().Add(config.DefaultConfig.JwtExpire)
	claims := &JwtClaims{
		Id: id,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(expirationTime),
			Issuer:    "go_web_ssh",
		},
	}
	// 生成Token,指定签名算法和claims
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

	// 签名
	tokenString, err := token.SignedString(JwtSecret)
	if err != nil {
		return "", err
	}
	return tokenString, nil
}

func ParseToken(tokenString string) (*JwtClaims, error) {
	claims := &JwtClaims{}
	_, err := jwt.ParseWithClaims(tokenString, claims, func(t *jwt.Token) (any, error) {
		return JwtSecret, nil
	})
	// 若token只是过期claims是有数据的,若token无法解析claims无数据
	return claims, err
}

func RenewToken(claims *JwtClaims) (string, error) {
	// 若token过期不超过10分钟则给它续签
	if withinLimit(claims.ExpiresAt.Time.Unix(), 600) {
		return GenerateToken(claims.Id)
	}
	return "", errors.New("登录已过期")
}

// 计算过期时间是否超过l
func withinLimit(s, l int64) bool {
	return time.Now().Unix()-s < l
}

func JWTAuth() gin.HandlerFunc {
	return func(c *gin.Context) {
		auth := c.Request.Header.Get("Authorization")
		if len(auth) == 0 {
			// Websocket SSE 从请求参数取
			auth = c.Query("Authorization")
		}
		if len(auth) == 0 {
			// 无token直接拒绝
			c.Abort()
			c.JSON(401, gin.H{"code": 401, "msg": "请添加Authorization请求头"})
			return
		}
		// 校验token
		claims, err := ParseToken(auth)
		if err != nil {
			if strings.Contains(err.Error(), "token is expired") {
				// 若过期,调用续签函数
				newToken, _ := RenewToken(claims)
				if newToken != "" {
					// 续签成功返回头设置一个NewToken字段
					c.Header("NewToken", newToken)
					//c.Request.Header.Set("Authorization", newToken)
					c.Set("uid", claims.Id)
					c.Next()
					return
				}
			}
			// Token验证失败或续签失败直接拒绝请求
			c.Abort()
			c.JSON(401, gin.H{"code": 401, "msg": "未登录"})
			return
		}
		c.Set("uid", claims.Id)
		// token未过期继续执行其他中间件
		c.Next()
	}
}


================================================
FILE: gossh/app/middleware/net_filter.go
================================================
package middleware

import (
	"fmt"
	"gossh/app/config"
	"gossh/app/model"
	"gossh/gin"
	"log/slog"
	"net"
)

func check(ip net.IP) bool {
	var policyConf model.PolicyConf
	conf, err := policyConf.FindByID(1)
	if err != nil {
		slog.Error("get policyConf:", "err_msg", err.Error())
		return false
	}
	// 白名单检查
	if conf.NetPolicy == "Y" {
		// slog.Info("netFilterPolicy", "value", "Y")
		var filter model.NetFilter
		list, err := filter.FindAllPolicy("Y")
		if err != nil {
			slog.Error("FindAllPolicy:", "err_msg", err.Error())
		}
		isOK := false
		for _, item := range list {
			_, ipNet, err := net.ParseCIDR(item.Cidr)
			if err != nil {
				slog.Error("net.ParseCIDR:", "err_msg", err.Error())
				return false
			}
			if ipNet.Contains(ip) {
				isOK = true
				break
			}
		}
		return isOK
	}

	// 黑名单检查
	if conf.NetPolicy == "N" {
		// slog.Info("netFilterPolicy", "value", "N")
		var filter model.NetFilter
		list, err := filter.FindAllPolicy("N")
		if err != nil {
			slog.Error("FindAllPolicy:", "err_msg", err.Error())
		}
		isOK := true
		for _, item := range list {
			_, ipNet, err := net.ParseCIDR(item.Cidr)
			if err != nil {
				slog.Error("net.ParseCIDR:", "err_msg", err.Error())
				return false
			}
			if ipNet.Contains(ip) {
				isOK = false
				break
			}
		}
		return isOK
	}
	return false
}

func NetFilter() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 系统没有进行初始化,过滤功能不生效
		if !config.DefaultConfig.IsInit {
			c.Next()
			return
		}

		ip := net.ParseIP(c.RemoteIP())
		if !check(ip) {
			c.JSON(403, gin.H{"err_msg": fmt.Sprintf("Deny %s", ip.String())})
			c.Abort()
			return
		}
		c.Next()
	}
}


================================================
FILE: gossh/app/middleware/perm_check.go
================================================
package middleware

import (
	"fmt"
	"gossh/app/config"
	"gossh/app/model"
	"gossh/gin"
	"slices"
	"strings"
)

var checkRoute = []string{
	// "GET:/app/*filepath",
	// "GET:/web_base_dir",
	// "HEAD:/app/*filepath",

	// "GET:/api/ssh/conn",
	// "PATCH:/api/ssh/conn",
	// "POST:/api/ssh/exec",
	// "POST:/api/ssh/disconnect",
	// "POST:/api/ssh/create_session",

	// "GET:/api/conn_conf",
	// "GET:/api/conn_conf/:id",
	// "POST:/api/conn_conf",
	// "PUT:/api/conn_conf",
	// "DELETE:/api/conn_conf/:id",

	// "GET:/api/cmd_note",
	// "GET:/api/cmd_note/:id",
	// "POST:/api/cmd_note",
	// "PUT:/api/cmd_note",
	// "DELETE:/api/cmd_note/:id",

	// "GET:/api/sftp/download",
	// "POST:/api/sftp/create_dir",
	// "POST:/api/sftp/list",
	// "DELETE:/api/sftp/delete",
	// "PUT:/api/sftp/upload",

	// "PUT:/api/conn_manage/refresh_conn_time",
	// "POST:/api/login",
	// "PATCH:/api/user/pwd",

	"GET:/api/sshd_cert",
	"GET:/api/sshd_cert_text",
	"GET:/api/sshd_cert/:id",
	"GET:/api/sshd_user",
	"GET:/api/sshd_user/:id",
	"GET:/api/sys/is_init",
	"GET:/api/sys/config",
	"GET:/api/conn_manage/online_client",
	"GET:/api/policy_conf",
	"GET:/api/policy_conf/:id",
	"GET:/api/net_filter",
	"GET:/api/net_filter/:id",
	"GET:/api/user",
	"GET:/api/user/:id",
	"POST:/api/sshd_user",
	"POST:/api/sshd_cert",
	"POST:/api/sys/db_conn_check",
	"POST:/api/sys/init",
	"POST:/api/sys/config",
	"POST:/api/login_audit",
	"POST:/api/policy_conf",
	"POST:/api/net_filter",
	"POST:/api/user",
	"PUT:/api/sshd_user",
	"PUT:/api/sshd_cert",
	"PUT:/api/policy_conf",
	"PUT:/api/net_filter",
	"PUT:/api/user",
	"DELETE:/api/sshd_user/:id",
	"DELETE:/api/sshd_cert/:id",
	"DELETE:/api/policy_conf/:id",
	"DELETE:/api/net_filter/:id",
	"DELETE:/api/user/:id",
	"PATCH:/api/sshd_user/check_name_exists",
	"PATCH:/api/sshd_cert/check_name_exists",
	"PATCH:/api/user/check_name_exists",
}

func PremCheck(engine *gin.Engine) gin.HandlerFunc {
	return func(c *gin.Context) {
		/*
			for _, route := range engine.Routes() {
				path := route.Path
				method := route.Method
				fmt.Printf("Route==>: %s:%s\n", method, path)
			}
		*/
		var tmp = c.FullPath()
		var baseDir = strings.Trim(config.DefaultConfig.WebBaseDir, " ")
		if baseDir != "" && strings.HasPrefix(tmp, baseDir) {
			tmp = strings.TrimPrefix(tmp, baseDir)
		}

		full := fmt.Sprintf("%s:%s", c.Request.Method, tmp)
		// slog.Info("PermCheck", "base", baseDir, "path", full)
		if slices.Contains(checkRoute, full) {
			var wu model.WebUser
			u, err := wu.FindByID(c.GetUint("uid"))
			if err != nil || u.IsAdmin == "N" {
				c.JSON(200, gin.H{"code": 403, "msg": "权限检查失败,非管理员拒绝操作"})
				c.Abort()
				return
			}
		}
		c.Next()
	}
}


================================================
FILE: gossh/app/middleware/sys_init.go
================================================
package middleware

import (
	"gossh/app/config"
	"gossh/gin"
)

func SysInit() gin.HandlerFunc {
	return func(c *gin.Context) {
		if !config.DefaultConfig.IsInit {
			// 需要进行系统初始化
			c.Abort()
			c.JSON(401, gin.H{"code": 401, "msg": "请对系统进行初始化"})
			return
		}
		c.Next()
	}
}


================================================
FILE: gossh/app/model/cmd_note.go
================================================
package model

type CmdNote struct {
	ID      uint   `gorm:"column:id;primaryKey,autoIncrement" form:"id" json:"id"`
	Uid     uint   `gorm:"column:uid;not null;default:0" form:"uid" json:"uid"`
	CmdName string `gorm:"column:cmd_name;type:text" form:"cmd_name" binding:"required" json:"cmd_name"`
	CmdData string `gorm:"column:cmd_data;type:text" form:"cmd_data" binding:"required" json:"cmd_data"`

	CreatedAt DateTime `gorm:"created_at" json:"-"`
	UpdatedAt DateTime `gorm:"updated_at" json:"-"`
}

func (c CmdNote) Create(cmd *CmdNote) error {
	return Db.Create(cmd).Error
}

func (c CmdNote) FindByName(name string) (CmdNote, error) {
	var cmd CmdNote
	err := Db.First(&cmd, "name = ?", name).Error
	return cmd, err
}

func (c CmdNote) FindByID(id uint, uid uint) (CmdNote, error) {
	var cmd CmdNote
	err := Db.First(&cmd, "id = ? AND uid = ?", id, uid).Error
	return cmd, err
}

func (c CmdNote) FindAll(offset, limit int, uid uint) ([]CmdNote, error) {
	var list []CmdNote
	err := Db.Where("uid = ?", uid).Offset(offset).Limit(limit).Order("updated_at desc").Find(&list).Error
	return list, err
}

func (c CmdNote) UpdateById(id, uid uint, cmd *CmdNote) error {
	return Db.Model(&c).Where("id = ? AND uid = ?", id, uid).Updates(cmd).Error
}

func (c CmdNote) DeleteByID(id, uid uint) error {
	return Db.Unscoped().Delete(&c, "id = ? AND uid = ?", id, uid).Error
}


================================================
FILE: gossh/app/model/datetime.go
================================================
package model

import (
	"database/sql/driver"
	"fmt"
	"time"
)

const (
	TimeFormat = "2006-01-02 15:04:05"
)

type DateTime time.Time

func NewDateTime(str string) (DateTime, error) {
	now, err := time.ParseInLocation(TimeFormat, str, time.Local)
	if err != nil {
		return DateTime{}, fmt.Errorf("can not convert %v to date,must like format:yyyy-MM-dd HH:mm:ss,simple example : %v", str, TimeFormat)
	}
	t := DateTime(now)
	return t, nil
}

func (t DateTime) MarshalJSON() ([]byte, error) {
	return []byte(fmt.Sprintf(`"%s"`, time.Time(t).Format(TimeFormat))), nil
}

func (t *DateTime) UnmarshalJSON(b []byte) error {
	now, err := time.ParseInLocation(`"`+TimeFormat+`"`, string(b), time.Local)
	if err != nil {
		return fmt.Errorf("can not convert %v to date,must like format:yyyy-MM-dd HH:mm:ss,simple example : %v", string(b), TimeFormat)
	}
	*t = DateTime(now)
	return nil
}
func (t DateTime) Value() (driver.Value, error) {
	var zeroTime time.Time
	if time.Time(t).UnixNano() == zeroTime.UnixNano() {
		return nil, nil
	}
	return time.Time(t), nil
}
func (t *DateTime) Scan(v any) error {
	value, ok := v.(time.Time)
	if ok {
		*t = DateTime(value)
		return nil
	}
	return fmt.Errorf("can not convert %v to timestamp", v)
}

func (t *DateTime) ToTime() time.Time {
	return time.Time(*t)
}

func (t DateTime) String() string {
	return time.Time(t).Format(TimeFormat)
}


================================================
FILE: gossh/app/model/db_init.go
================================================
package model

import (
	"errors"
	"fmt"
	"gossh/app/config"
	"gossh/gorm"
	"gossh/gorm/driver/mysql"
	"gossh/gorm/driver/pgsql"
	"gossh/gorm/logger"
	_ "gossh/mysql"
	_ "gossh/pgsql"
	"gossh/sqlite"
	"log/slog"
	"os"
	"path"
	"path/filepath"
)

var Db *gorm.DB

func InitDatabase() {
	if !config.DefaultConfig.IsInit {
		slog.Warn("系统未初始化,跳过DbMigrate")
		return
	}
	err := DbMigrate(config.DefaultConfig.DbType, config.DefaultConfig.DbDsn)
	if err != nil {
		slog.Error("DbMigrate error", "err_msg", err.Error())
	}
}

func GetSqliteDb(dsn string) (*gorm.DB, error) {
	//loadInit()
	dbPath := path.Join(config.WorkDir, dsn)

	// 确保数据库目录存在
	if err := os.MkdirAll(filepath.Dir(dbPath), 0755); err != nil {
		return nil, fmt.Errorf("failed to create database directory: %v", err)
	}

	// 尝试打开数据库连接
	db, err := gorm.Open(sqlite.Open(dbPath), &gorm.Config{
		Logger: logger.Default.LogMode(logger.Warn),
	})
	if err != nil {
		return nil, fmt.Errorf("failed to connect to database: %v", err)
	}

	// 验证连接
	sqlDB, err := db.DB()
	if err != nil {
		return nil, fmt.Errorf("failed to get database instance: %v", err)
	}

	if err := sqlDB.Ping(); err != nil {
		return nil, fmt.Errorf("failed to ping database: %v", err)
	}

	return db, nil
}

func DbMigrate(dbType, dsn string) error {
	defer func() {
		if err := recover(); err != nil {
			slog.Error("DbMigrate error", "err_msg", err)
		}
	}()
	if dbType == "pgsql" {
		db, err := gorm.Open(pgsql.Open(dsn), &gorm.Config{
			Logger: logger.Default.LogMode(logger.Warn),
		})
		if err != nil {
			return err
		}
		err = db.Exec("select 1=1;").Error
		if err != nil {
			return err
		}
		Db = db
	}

	if dbType == "mysql" {
		db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
			Logger: logger.Default.LogMode(logger.Warn),
		})
		if err != nil {
			return err
		}
		err = db.Exec("select 1=1;").Error
		if err != nil {
			return err
		}
		Db = db
	}

	if dbType == "sqlite" {
		db, err := GetSqliteDb(dsn)
		if err != nil {
			return err
		}
		Db = db
	}

	if Db == nil {
		return errors.New("请检查数据库链接")
	}

	err := Db.AutoMigrate(
		SshConf{}, WebUser{}, CmdNote{},
		NetFilter{}, PolicyConf{}, LoginAudit{},
		SshdConf{}, SshdUser{}, SshdCert{})
	if err != nil {
		slog.Error("AutoMigrate error:", "err_msg", err.Error())
		return err
	}

	return nil
}


================================================
FILE: gossh/app/model/login_audit.go
================================================
package model

type LoginAudit struct {
	ID        uint     `gorm:"column:id;primaryKey,autoIncrement" form:"id" json:"id"`
	Name      string   `gorm:"column:name;not null;size:128" form:"name" binding:"required,min=1,max=128" json:"name"`
	Pwd       string   `gorm:"column:pwd;size:128" form:"pwd" binding:"required,min=1,max=128" json:"pwd"`
	ClientIp  string   `gorm:"column:client_ip;size:128" form:"client_ip" binding:"required,min=1,max=128" json:"client_ip"`
	UserAgent string   `gorm:"column:user_agent;size:512" form:"user_agent" binding:"required,min=0,max=512" json:"user_agent"`
	ErrMsg    string   `gorm:"column:err_msg;size:64" form:"err_msg" binding:"required,min=1,max=64" json:"err_msg"`
	IsSuccess string   `gorm:"column:is_success;not null;size:64;default:'N'" form:"is_success" binding:"required,min=1,max=64,oneof=Y N" json:"is_success"`
	OccurAt   DateTime `gorm:"column:occur_at;not null"  json:"occur_at"  form:"occur_at" binding:"required"`

	CreatedAt DateTime `gorm:"column:created_at" json:"-"`
	UpdatedAt DateTime `gorm:"column:updated_at" json:"-"`
}

func (c LoginAudit) Create(audit *LoginAudit) error {
	return Db.Create(audit).Error
}

func (c LoginAudit) Search(
	isSuccess, name, clientIp string,
	occurBegin, occurEnd DateTime, offset, limit int,
) ([]LoginAudit, int64, error) {
	var list []LoginAudit
	var db = Db
	if isSuccess != "" {
		db = db.Where("is_success = ?", isSuccess)
	}
	if name != "" {
		db = db.Where("name like ?", "%"+name+"%")
	}
	if clientIp != "" {
		db = db.Where("client_ip = ?", clientIp)
	}

	if occurBegin.String() != "0001-01-01 00:00:00" && occurEnd.String() != "0001-01-01 00:00:00" {
		db = db.Where("occur_at between  ? AND ?", occurBegin, occurEnd)
	}
	var count int64
	err := db.Model(&LoginAudit{}).Count(&count).Error
	if err != nil {
		return list, count, err
	}
	return list, count, db.Debug().Order("occur_at desc").Offset(offset).Limit(limit).Find(&list).Error
}

func (c LoginAudit) FindByID(id uint) (LoginAudit, error) {
	var audit LoginAudit
	err := Db.First(&audit, "id = ?", id).Error
	return audit, err
}

func (c LoginAudit) DeleteByID(id uint) error {
	return Db.Unscoped().Delete(&c, "id = ? AND is_root = ?", id, "N").Error
}


================================================
FILE: gossh/app/model/net_filter.go
================================================
package model

import "time"

type NetFilter struct {
	ID        uint     `gorm:"column:id;primaryKey,autoIncrement" form:"id" json:"id"`
	Name      string   `gorm:"column:name;not null" form:"name" json:"name" binding:"required"`
	Cidr      string   `gorm:"column:cidr;not null" form:"cidr" json:"cidr" binding:"required,cidr"`
	NetPolicy string   `gorm:"column:net_policy;not null;size:64;default:'Y'" form:"net_policy" binding:"required,min=1,max=64,oneof=Y N" json:"net_policy"`
	PolicyNo  uint     `gorm:"column:policy_no;not null;" form:"policy_no" json:"policy_no" binding:"required,gte=1,lte=65535"`
	ExpiryAt  DateTime `gorm:"column:expiry_at;not null"  json:"expiry_at"  form:"expiry_at" binding:"required"`

	CreatedAt DateTime `gorm:"column:created_at" json:"-"`
	UpdatedAt DateTime `gorm:"column:updated_at" json:"-"`
}

func (c NetFilter) Create(filter *NetFilter) error {
	return Db.Create(filter).Error
}

func (c NetFilter) FindByName(name string) (NetFilter, error) {
	var filter NetFilter
	err := Db.First(&filter, "name = ?", name).Error
	return filter, err
}

func (c NetFilter) FindByID(id uint) (NetFilter, error) {
	var filter NetFilter
	err := Db.First(&filter, "id = ? ", id).Error
	return filter, err
}

func (c NetFilter) FindAll(offset, limit int) ([]NetFilter, error) {
	var list []NetFilter
	err := Db.Offset(offset).Limit(limit).Order("policy_no asc, expiry_at, updated_at desc").Find(&list).Error
	return list, err
}

func (c NetFilter) FindAllPolicy(policy string) ([]NetFilter, error) {
	var list []NetFilter
	err := Db.Where("net_policy = ? AND expiry_at > ?", policy, time.Now()).Order("policy_no asc, expiry_at, updated_at desc").Find(&list).Error
	return list, err
}

func (c NetFilter) UpdateById(id uint, filter *NetFilter) error {
	return Db.Model(&c).Where("id = ?", id).Updates(filter).Error
}

func (c NetFilter) DeleteByID(id uint) error {
	return Db.Unscoped().Delete(&c, "id = ?", id).Error
}


================================================
FILE: gossh/app/model/policy_conf.go
================================================
package model

type PolicyConf struct {
	ID        uint   `gorm:"column:id;primaryKey,autoIncrement" form:"id" json:"id"`
	NetPolicy string `gorm:"column:net_policy;not null;size:64;default:'Y'" form:"net_policy" binding:"required,min=1,max=64,oneof=Y N" json:"net_policy"`

	CreatedAt DateTime `gorm:"column:created_at" json:"-"`
	UpdatedAt DateTime `gorm:"column:updated_at" json:"-"`
}

func (c PolicyConf) Create(conf *PolicyConf) error {
	return Db.Create(conf).Error
}

func (c PolicyConf) FindByID(id uint) (PolicyConf, error) {
	var conf PolicyConf
	err := Db.First(&conf, "id = ? ", id).Error
	return conf, err
}

func (c PolicyConf) FindAll(offset, limit int) ([]PolicyConf, error) {
	var list []PolicyConf
	err := Db.Offset(offset).Limit(limit).Order("updated_at desc").Find(&list).Error
	return list, err
}

func (c PolicyConf) UpdateById(id uint, conf *PolicyConf) error {
	return Db.Model(&c).Where("id = ?", id).Updates(conf).Error
}

func (c PolicyConf) DeleteByID(id uint) error {
	return Db.Unscoped().Delete(&c, "id = ?", id).Error
}


================================================
FILE: gossh/app/model/ssh_conf.go
================================================
package model

import (
	"errors"
	"gossh/app/config"
	"gossh/app/utils"
	"gossh/gorm"
)

type SshConf struct {
	ID          uint   `gorm:"column:id;primaryKey,autoIncrement" form:"id" json:"id"`
	Uid         uint   `gorm:"column:uid;not null;default:0" form:"uid" json:"uid"`
	Name        string `gorm:"column:name;not null;size:64" form:"name" binding:"required,min=1,max=63" json:"name"`
	Address     string `gorm:"column:address;size:128" form:"address" binding:"required,min=1,max=128" json:"address"`
	User        string `gorm:"column:user;size:128" form:"user" binding:"required,min=1,max=128" json:"user"`
	Pwd         string `gorm:"column:pwd;not null;size:4096;default:''" form:"pwd" binding:"max=4096" json:"pwd"`
	AuthType    string `gorm:"column:auth_type;not null;size:32;default:'pwd'" form:"auth_type" binding:"required,min=1,max=32,oneof=pwd cert" json:"auth_type"`
	NetType     string `gorm:"column:net_type;not null;size:32;default:'tcp4'" form:"net_type" binding:"required,min=1,max=32,oneof=tcp4 tcp6" json:"net_type"`
	CertData    string `gorm:"column:cert_data;type:text" form:"cert_data" json:"cert_data"`
	CertPwd     string `gorm:"column:cert_pwd;not null;size:128;default:''" form:"cert_pwd" binding:"max=128" json:"cert_pwd"`
	Port        uint16 `gorm:"column:port;not null;default:22" form:"port" binding:"required,gte=1,lte=65535" json:"port"`
	FontSize    uint16 `gorm:"column:font_size;not null;default:14" form:"font_size" binding:"required,gte=8,lte=48" json:"font_size"`
	Background  string `gorm:"column:background;not null;size:128;default:'#000000'" form:"background" binding:"required,hexcolor" json:"background"`
	Foreground  string `gorm:"column:foreground;not null;size:128;default:'#FFFFFF'" form:"foreground" binding:"required,hexcolor" json:"foreground"`
	CursorColor string `gorm:"column:cursor_color;not null;size:128;default:'#FFFFFF'" form:"cursor_color" binding:"required,hexcolor" json:"cursor_color"`
	FontFamily  string `gorm:"column:font_family;not null;size:128;default:'Courier'" form:"font_family" binding:"min=1,max=128" json:"font_family"`
	CursorStyle string `gorm:"column:cursor_style;not null;size:128;default:'block'" form:"cursor_style" binding:"min=1,max=128" json:"cursor_style"`
	Shell       string `gorm:"column:shell;not null;size:64;default:'sh'" form:"shell" binding:"min=1,max=128" json:"shell"`
	PtyType     string `gorm:"column:pty_type;not null;size:64;default:'xterm-256color'" form:"pty_type" binding:"min=1,max=128" json:"pty_type"`
	InitCmd     string `gorm:"column:init_cmd;type:text" form:"init_cmd" json:"init_cmd"`
	InitBanner  string `gorm:"column:init_banner;type:text" form:"init_banner" json:"init_banner"`

	CreatedAt DateTime `gorm:"column:created_at" json:"-"`
	UpdatedAt DateTime `gorm:"column:updated_at" json:"-"`
}

func (c *SshConf) Create(conf *SshConf) error {
	return Db.Create(conf).Error
}

func (c *SshConf) FindByID(id uint, uid uint) (SshConf, error) {
	var conf SshConf
	err := Db.First(&conf, "id = ? AND uid = ?", id, uid).Error
	return conf, err
}

func (c *SshConf) FindAll(offset, limit int, uid uint) ([]SshConf, error) {
	var list []SshConf
	err := Db.Where("uid = ?", uid).Offset(offset).Limit(limit).Order("updated_at desc").Find(&list).Error
	return list, err
}

func (_ *SshConf) UpdateById(id, uid uint, conf *SshConf) error {
	return Db.Model(&conf).Where("id = ? AND uid = ?", id, uid).Select("*").Omit("id", "uid").Updates(conf).Error
}

func (c *SshConf) DeleteByID(id, uid uint) error {
	return Db.Unscoped().Delete(&c, "id = ? AND uid = ?", id, uid).Error
}

// BeforeCreate Hook
func (c *SshConf) BeforeCreate(_ *gorm.DB) error {
	_, err := c.sshConfEncrypt()
	return err
}

// BeforeUpdate Hook
func (c *SshConf) BeforeUpdate(_ *gorm.DB) error {
	_, err := c.sshConfEncrypt()
	return err
}

// AfterFind Hook
func (c *SshConf) AfterFind(_ *gorm.DB) error {
	var err error
	c.Pwd, err = utils.DecryptString(c.Pwd, config.DefaultConfig.AesSecret)
	if err != nil {
		return errors.New("解密密码错误," + err.Error())
	}
	c.CertPwd, err = utils.DecryptString(c.CertPwd, config.DefaultConfig.AesSecret)
	if err != nil {
		return errors.New("解密证书密码错误,," + err.Error())
	}
	c.CertData, err = utils.DecryptString(c.CertData, config.DefaultConfig.AesSecret)
	if err != nil {
		return errors.New("解密密证书数据错误," + err.Error())
	}
	return nil
}

func (c *SshConf) sshConfEncrypt() (*SshConf, error) {
	var err error
	c.Pwd, err = utils.EncryptString(c.Pwd, config.DefaultConfig.AesSecret)
	if err != nil {
		return c, errors.New("加密密码错误," + err.Error())
	}
	c.CertPwd, err = utils.EncryptString(c.CertPwd, config.DefaultConfig.AesSecret)
	if err != nil {
		return c, errors.New("加密证书密码错误," + err.Error())
	}
	c.CertData, err = utils.EncryptString(c.CertData, config.DefaultConfig.AesSecret)
	if err != nil {
		return c, errors.New("加密证书数据错误," + err.Error())
	}
	return c, nil
}


================================================
FILE: gossh/app/model/sshd_cert.go
================================================
package model

import "time"

type SshdCert struct {
	ID       uint     `gorm:"column:id;primaryKey,autoIncrement" form:"id" json:"id"`
	DescInfo string   `gorm:"column:desc_info;size:64" form:"desc_info" binding:"required,min=1,max=64" json:"desc_info"`
	Name     string   `gorm:"column:name;uniqueIndex;not null;size:64" form:"name" binding:"required,min=1,max=63" json:"name"`
	PubKey   string   `gorm:"column:pub_key;type:text;not null;" form:"pub_key" binding:"required,min=16" json:"pub_key"`
	IsEnable string   `gorm:"column:is_enable;not null;size:64;default:'Y'" form:"is_enable" binding:"required,min=1,max=64,oneof=Y N" json:"is_enable"`
	ExpiryAt DateTime `gorm:"column:expiry_at;not null"  json:"expiry_at"  form:"expiry_at" binding:"required"`

	CreatedAt DateTime `gorm:"column:created_at" json:"-"`
	UpdatedAt DateTime `gorm:"column:updated_at" json:"-"`
}

func (c *SshdCert) Create(user *SshdCert) error {
	return Db.Create(user).Error
}

func (c *SshdCert) FindByName(name string) (SshdCert, error) {
	var user SshdCert
	err := Db.Find(&user, "name = ?", name).Error
	return user, err
}

func (c *SshdCert) FindByID(id uint) (SshdCert, error) {
	var user SshdCert
	err := Db.First(&user, "id = ?", id).Error
	return user, err
}

func (c *SshdCert) FindAll(limit, offset int) ([]SshdCert, error) {
	var list []SshdCert
	err := Db.Limit(limit).Offset(offset).Find(&list).Error
	return list, err
}

func (c *SshdCert) GetAuthorizedKeys() (string, error) {
	var authorizedKeys = ""
	var list []string
	err := Db.Model(c).Select("pub_key").Where("is_enable = ? AND expiry_at > ?", "Y", time.Now()).Find(&list).Error
	if err != nil {
		return "", err
	}

	for _, v := range list {
		authorizedKeys += v + "\n"
	}
	return authorizedKeys, err
}

func (c *SshdCert) UpdateById(id uint, user *SshdCert) error {
	return Db.Model(&c).Where("id = ?", id).Select("*").Omit("id").Updates(user).Error
}

func (c *SshdCert) DeleteByID(id uint) error {
	return Db.Unscoped().Delete(&c, "id = ?", id).Error
}


================================================
FILE: gossh/app/model/sshd_conf.go
================================================
package model

import (
	"gossh/app/config"
	"gossh/app/utils"
	"gossh/gorm"
)

type SshdConf struct {
	ID            uint     `gorm:"column:id;primaryKey,autoIncrement" form:"id" json:"id"`
	Name          string   `gorm:"column:name;uniqueIndex;not null;size:64" form:"name" binding:"required,min=1,max=63" json:"name"`
	Host          string   `gorm:"column:host;size:128" form:"host" binding:"required,min=1,max=128" json:"host"`
	Port          uint16   `gorm:"column:port;uniqueIndex;not null" form:"port" binding:"required,gte=1,lte=65535" json:"port"`
	Shell         string   `gorm:"column:shell;not null;size:64;default:''" form:"shell" binding:"min=1,max=128" json:"shell"`
	KeyFile       string   `gorm:"column:key_file;not null;type:text" form:"key_file" json:"key_file"`
	KeySeed       string   `gorm:"column:key_seed;not null;size:4096;default:''" form:"key_seed" binding:"max=4096" json:"key_seed"`
	KeepAlive     uint16   `gorm:"column:keep_alive;not null;default:60" form:"keep_alive" binding:"required,gte=10,lte=360" json:"keep_alive"`
	LoadEnv       string   `gorm:"column:load_env;not null;size:64;default:'Y'" form:"load_env" binding:"required,min=1,max=64,oneof=Y N" json:"load_env"`
	AuthType      string   `gorm:"column:auth_type;not null;size:32;default:'all'" form:"auth_type" binding:"required,min=1,max=32,oneof=all pwd cert" json:"auth_type"`
	ServerVersion string   `gorm:"column:server_version;not null;size:64;default:'SSH-2.0-OpenSSH'" form:"name" binding:"required,min=10,max=63" json:"server_version"`
	CreatedAt     DateTime `gorm:"column:created_at" json:"-"`
	UpdatedAt     DateTime `gorm:"column:updated_at" json:"-"`
}

func (c *SshdConf) Create(conf *SshdConf) error {
	return Db.Create(conf).Error
}

func (c *SshdConf) FindByName(name string) (SshdConf, error) {
	var conf SshdConf
	err := Db.Find(&conf, "name = ?", name).Error
	return conf, err
}

func (c *SshdConf) FindByID(id uint) (SshdConf, error) {
	var conf SshdConf
	err := Db.First(&conf, "id = ?", id).Error
	return conf, err
}

func (c *SshdConf) UpdateByName(name string, conf *SshdConf) error {
	return Db.Model(&c).Where("name = ?", name).Select("*").Omit("id", "name").Updates(conf).Error
}

func (c *SshdConf) DeleteByName(name string) error {
	return Db.Unscoped().Delete(&c, "name = ?", name).Error
}

// BeforeCreate Hook
func (c *SshdConf) BeforeCreate(_ *gorm.DB) error {
	var err error
	c.KeyFile, err = utils.EncryptString(c.KeyFile, config.DefaultConfig.AesSecret)
	return err
}

// BeforeUpdate Hook
func (c *SshdConf) BeforeUpdate(_ *gorm.DB) error {
	var err error
	c.KeyFile, err = utils.EncryptString(c.KeyFile, config.DefaultConfig.AesSecret)
	return err
}

// AfterFind Hook
func (c *SshdConf) AfterFind(_ *gorm.DB) error {
	var err error
	c.KeyFile, err = utils.DecryptString(c.KeyFile, config.DefaultConfig.AesSecret)
	return err
}


================================================
FILE: gossh/app/model/sshd_user.go
================================================
package model

import (
	"errors"
	"fmt"
	"gossh/app/config"
	"gossh/app/utils"
	"gossh/gorm"
	"time"
)

type SshdUser struct {
	ID       uint     `gorm:"column:id;primaryKey,autoIncrement" form:"id" json:"id"`
	Name     string   `gorm:"column:name;uniqueIndex;not null;size:64" form:"name" binding:"required,min=1,max=63" json:"name"`
	Pwd      string   `gorm:"column:pwd;size:64" form:"pwd" binding:"required,min=1,max=64" json:"pwd"`
	DescInfo string   `gorm:"column:desc_info;size:64" form:"desc_info" binding:"required,min=1,max=64" json:"desc_info"`
	IsEnable string   `gorm:"column:is_enable;not null;size:64;default:'Y'" form:"is_enable" binding:"required,min=1,max=64,oneof=Y N" json:"is_enable"`
	WorkDir  string   `gorm:"column:work_dir;size:4096;default:''" form:"work_dir" binding:"max=4096" json:"work_dir"`
	ExpiryAt DateTime `gorm:"column:expiry_at;not null"  json:"expiry_at"  form:"expiry_at" binding:"required"`

	CreatedAt DateTime `gorm:"column:created_at" json:"-"`
	UpdatedAt DateTime `gorm:"column:updated_at" json:"-"`
}

func (c *SshdUser) Create(user *SshdUser) error {
	return Db.Create(user).Error
}

func (c *SshdUser) FindByNameAndPwd(name, pwd string) (SshdUser, error) {
	var user SshdUser
	err := Db.First(&user, "name = ? AND is_enable = ?", name, "Y").Error
	if err != nil {
		return SshdUser{}, err
	}
	if user.Pwd != pwd {
		return SshdUser{}, errors.New("password error")
	}

	if user.ExpiryAt.ToTime().Unix() < time.Now().Unix() {
		return user, errors.New(fmt.Sprintf("sshd user '%s' expired", name))
	}
	return user, err
}

func (c *SshdUser) FindByName(name string) (SshdUser, error) {
	var user SshdUser
	err := Db.Find(&user, "name = ?", name).Error
	return user, err
}

func (c *SshdUser) FindByID(id uint) (SshdUser, error) {
	var user SshdUser
	err := Db.First(&user, "id = ?", id).Error
	return user, err
}

func (c *SshdUser) FindAll(limit, offset int) ([]SshdUser, error) {
	var list []SshdUser
	err := Db.Limit(limit).Offset(offset).Find(&list).Error
	return list, err
}

func (c *SshdUser) UpdateById(id uint, user *SshdUser) error {
	return Db.Model(&c).Where("id = ?", id).Select("*").Omit("id").Updates(user).Error
}

func (c *SshdUser) DeleteByID(id uint) error {
	return Db.Unscoped().Delete(&c, "id = ?", id).Error
}

// BeforeCreate Hook
func (c *SshdUser) BeforeCreate(_ *gorm.DB) error {
	var err error
	c.Pwd, err = utils.EncryptString(c.Pwd, config.DefaultConfig.AesSecret)
	return err
}

// BeforeUpdate Hook
func (c *SshdUser) BeforeUpdate(_ *gorm.DB) error {
	var err error
	c.Pwd, err = utils.EncryptString(c.Pwd, config.DefaultConfig.AesSecret)
	return err
}

// AfterFind Hook
func (c *SshdUser) AfterFind(_ *gorm.DB) error {
	var err error
	c.Pwd, err = utils.DecryptString(c.Pwd, config.DefaultConfig.AesSecret)
	return err
}


================================================
FILE: gossh/app/model/web_user.go
================================================
package model

import (
	"errors"
	"gossh/app/config"
	"gossh/app/utils"
	"gossh/gorm"
)

type WebUser struct {
	ID       uint     `gorm:"column:id;primaryKey,autoIncrement" form:"id" json:"id"`
	Name     string   `gorm:"column:name;uniqueIndex;not null;size:64" form:"name" binding:"required,min=1,max=63" json:"name"`
	Pwd      string   `gorm:"column:pwd;size:64" form:"pwd" binding:"required,min=1,max=64" json:"pwd"`
	DescInfo string   `gorm:"column:desc_info;size:64" form:"desc_info" binding:"required,min=1,max=64" json:"desc_info"`
	IsAdmin  string   `gorm:"column:is_admin;not null;size:64;default:'N'" form:"is_admin" binding:"required,min=1,max=64,oneof=Y N" json:"is_admin"`
	IsEnable string   `gorm:"column:is_enable;not null;size:64;default:'Y'" form:"is_enable" binding:"required,min=1,max=64,oneof=Y N" json:"is_enable"`
	IsRoot   string   `gorm:"column:is_root;not null;size:64;default:'N'" form:"is_root"  json:"is_root"`
	ExpiryAt DateTime `gorm:"column:expiry_at;not null"  json:"expiry_at"  form:"expiry_at" binding:"required"`

	CreatedAt DateTime `gorm:"column:created_at" json:"-"`
	UpdatedAt DateTime `gorm:"column:updated_at" json:"-"`
}

func (c *WebUser) Create(user *WebUser) error {
	return Db.Create(user).Error
}

func (c *WebUser) FindByNameAndPwd(name, pwd string) (WebUser, error) {
	var user WebUser
	err := Db.First(&user, "name = ?", name).Error
	if err != nil {
		return WebUser{}, err
	}
	if user.Pwd != pwd {
		return WebUser{}, errors.New("password error")
	}
	return user, err
}

func (c *WebUser) FindByName(name string) (WebUser, error) {
	var user WebUser
	err := Db.Find(&user, "name = ?", name).Error
	return user, err
}

func (c *WebUser) FindByID(id uint) (WebUser, error) {
	var user WebUser
	err := Db.First(&user, "id = ?", id).Error
	return user, err
}

func (c *WebUser) FindAll(limit, offset int) ([]WebUser, error) {
	var list []WebUser
	err := Db.Where("is_root = ?", "N").Limit(limit).Offset(offset).Find(&list).Error
	return list, err
}

func (c *WebUser) UpdateById(id uint, user *WebUser) error {
	return Db.Model(&c).Where("id = ? AND is_root = ?", id, "N").Select("*").Omit("id", "is_root").Updates(user).Error
}

func (c *WebUser) UpdatePassword(id uint, user *WebUser) error {
	return Db.Model(&c).Where("id = ?", id).Select("*").Omit("id").Updates(user).Error
}

func (c *WebUser) DeleteByID(id uint) error {
	return Db.Unscoped().Delete(&c, "id = ? AND is_root = ?", id, "N").Error
}

// BeforeCreate Hook
func (c *WebUser) BeforeCreate(_ *gorm.DB) error {
	var err error
	c.Pwd, err = utils.EncryptString(c.Pwd, config.DefaultConfig.AesSecret)
	return err
}

// BeforeUpdate Hook
func (c *WebUser) BeforeUpdate(_ *gorm.DB) error {
	var err error
	c.Pwd, err = utils.EncryptString(c.Pwd, config.DefaultConfig.AesSecret)
	return err
}

// AfterFind Hook
func (c *WebUser) AfterFind(_ *gorm.DB) error {
	var err error
	c.Pwd, err = utils.DecryptString(c.Pwd, config.DefaultConfig.AesSecret)
	return err
}


================================================
FILE: gossh/app/service/cmd_note.go
================================================
package service

import (
	"gossh/app/model"
	"gossh/gin"
	"strconv"
)

func CmdNoteCreate(c *gin.Context) {
	var cmd model.CmdNote
	if err := c.ShouldBind(&cmd); err != nil {
		c.JSON(200, gin.H{"code": 1, "msg": err.Error()})
		return
	}
	cmd.Uid = c.GetUint("uid")
	err := cmd.Create(&cmd)
	if err != nil {
		c.JSON(200, gin.H{"code": 2, "msg": err.Error()})
		return
	}
	CmdNoteFindAll(c)
}

func CmdNoteFindByID(c *gin.Context) {
	id, err := strconv.Atoi(c.Param("id"))
	if err != nil {
		c.JSON(200, gin.H{"code": 2, "msg": err.Error()})
		return
	}
	var cmd model.CmdNote
	data, err := cmd.FindByID(uint(id), c.GetUint("uid"))
	if err != nil {
		c.JSON(200, gin.H{"code": 2, "msg": err.Error()})
		return
	}
	c.JSON(200, gin.H{"code": 0, "msg": "ok", "data": data})
}

func CmdNoteFindAll(c *gin.Context) {
	limit, err := strconv.Atoi(c.DefaultQuery("limit", "10000"))
	if err != nil {
		c.JSON(200, gin.H{"code": 2, "msg": err.Error()})
		return
	}
	offset, err := strconv.Atoi(c.DefaultQuery("offset", "0"))
	if err != nil {
		c.JSON(200, gin.H{"code": 2, "msg": err.Error()})
		return
	}

	var cmd model.CmdNote
	data, err := cmd.FindAll(offset, limit, c.GetUint("uid"))
	if err != nil {
		c.JSON(200, gin.H{"code": 2, "msg": err.Error()})
		return
	}
	c.JSON(200, gin.H{"code": 0, "msg": "ok", "data": data})
}

func CmdNoteUpdateById(c *gin.Context) {
	var cmd model.CmdNote
	if err := c.ShouldBind(&cmd); err != nil {
		c.JSON(200, gin.H{"code": 1, "msg": err.Error()})
		return
	}
	err := cmd.UpdateById(cmd.ID, c.GetUint("uid"), &cmd)
	if err != nil {
		c.JSON(200, gin.H{"code": 2, "msg": err.Error()})
		return
	}
	CmdNoteFindAll(c)
}

func CmdNoteDeleteById(c *gin.Context) {
	id, err := strconv.Atoi(c.Param("id"))
	if err != nil {
		c.JSON(200, gin.H{"code": 2, "msg": err.Error()})
		return
	}
	var cmd model.CmdNote
	err = cmd.DeleteByID(uint(id), c.GetUint("uid"))
	if err != nil {
		c.JSON(200, gin.H{"code": 2, "msg": err.Error()})
		return
	}
	CmdNoteFindAll(c)
}


================================================
FILE: gossh/app/service/db_conn.go
================================================
package service

import (
	"gossh/app/config"
	"gossh/app/model"
	"gossh/gin"
	"gossh/gorm"
	"gossh/gorm/driver/mysql"
	"gossh/gorm/driver/pgsql"
	_ "gossh/mysql"
	_ "gossh/pgsql"
	"log/slog"
)

type DbConnConf struct {
	DbDsn  string `form:"db_dsn" binding:"required,min=1,max=65535" json:"db_dsn"`
	DbType string `form:"db_type" binding:"required,oneof=sqlite pgsql mysql" json:"db_type"`
}

func DbConnCheck(c *gin.Context) {
	if config.DefaultConfig.IsInit {
		c.JSON(200, gin.H{"code": 1, "msg": "系统已经完成初始化配置"})
		return
	}

	var dbConf DbConnConf
	if err := c.ShouldBind(&dbConf); err != nil {
		c.JSON(200, gin.H{"code": 1, "msg": err.Error()})
		return
	}
	err := DbConnTestCheck(dbConf)
	if err != nil {
		c.JSON(200, gin.H{"code": 1, "msg": err.Error()})
		return
	}
	c.JSON(200, gin.H{"code": 0, "msg": "连接成功"})
}

func DbConnTestCheck(dbConf DbConnConf) error {
	slog.Info("DB link check", "db_type", dbConf.DbType, "db_dsn", dbConf.DbDsn)
	if dbConf.DbType == "pgsql" {
		Db, err := gorm.Open(pgsql.Open(dbConf.DbDsn), &gorm.Config{})
		if err != nil {
			return err
		}
		err = Db.Exec("select 1=1;").Error
		if err != nil {
			return err
		}
	}

	if dbConf.DbType == "mysql" {
		Db, err := gorm.Open(mysql.Open(dbConf.DbDsn), &gorm.Config{})
		if err != nil {
			return err
		}
		err = Db.Exec("select 1=1;").Error
		if err != nil {
			return err
		}
	}

	if dbConf.DbType == "sqlite" {
		Db, err := model.GetSqliteDb(dbConf.DbDsn)
		if err != nil {
			return err
		}
		err = Db.Exec("select 1=1;").Error
		if err != nil {
			return err
		}
	}
	return nil
}


================================================
FILE: gossh/app/service/login_audit.go
================================================
package service

import (
	"gossh/app/model"
	"gossh/gin"
	"strconv"
)

func AuditFindByID(c *gin.Context) {
	id, err := strconv.Atoi(c.Param("id"))
	if err != nil {
		c.JSON(200, gin.H{"code": 2, "msg": err.Error()})
		return
	}
	var audit model.LoginAudit
	data, err := audit.FindByID(uint(id))
	if err != nil {
		c.JSON(200, gin.H{"code": 2, "msg": err.Error()})
		return
	}
	c.JSON(200, gin.H{"code": 0, "msg": "ok", "data": data})
}

func LoginAuditSearch(c *gin.Context) {
	type Param struct {
		OccurBegin model.DateTime `json:"occur_begin"  form:"occur_begin"`
		OccurEnd   model.DateTime `json:"occur_end"  form:"occur_end"`
		Offset     int            `form:"offset" json:"offset" binding:"min=0"`
		Limit      int            `form:"limit" json:"limit" binding:"max=1000"`
		Name       string         `form:"name" binding:"max=64" json:"name"`
		ClientIp   string         `form:"client_ip" binding:"max=128" json:"client_ip"`
		IsSuccess  string         `form:"is_success" binding:"max=1" json:"is_success"`
	}
	var p Param
	if err := c.ShouldBind(&p); err != nil {
		c.JSON(200, gin.H{"code": 1, "msg": err.Error()})
		return
	}
	if p.Limit == 0 {
		p.Limit = 100
	}
	var audit model.LoginAudit
	data, count, err := audit.Search(p.IsSuccess, p.Name, p.ClientIp, p.OccurBegin, p.OccurEnd, p.Offset, p.Limit)
	if err != nil {
		c.JSON(200, gin.H{"code": 1, "msg": err.Error()})
		return
	}
	c.JSON(200, gin.H{"code": 0, "msg": "ok", "data": data, "count": count})
}

func LoginAuditDeleteById(c *gin.Context) {
	id, err := strconv.Atoi(c.Param("id"))
	if err != nil {
		c.JSON(200, gin.H{"code": 2, "msg": err.Error()})
		return
	}
	var audit model.LoginAudit
	err = audit.DeleteByID(uint(id))
	if err != nil {
		c.JSON(200, gin.H{"code": 2, "msg": err.Error()})
		return
	}
}


================================================
FILE: gossh/app/service/net_filter.go
================================================
package service

import (
	"gossh/app/model"
	"gossh/gin"
	"strconv"
)

func NetFilterCreate(c *gin.Context) {
	var netFilter model.NetFilter
	if err := c.ShouldBind(&netFilter); err != nil {
		c.JSON(200, gin.H{"code": 1, "msg": err.Error()})
		return
	}

	err := netFilter.Create(&netFilter)
	if err != nil {
		c.JSON(200, gin.H{"code": 3, "msg": err.Error()})
		return
	}
	NetFilterFindAll(c)
}

func NetFilterFindByID(c *gin.Context) {
	id, err := strconv.Atoi(c.Param("id"))
	if err != nil {
		c.JSON(200, gin.H{"code": 2, "msg": err.Error()})
		return
	}
	var netFilter model.NetFilter
	data, err := netFilter.FindByID(uint(id))
	if err != nil {
		c.JSON(200, gin.H{"code": 2, "msg": err.Error()})
		return
	}
	c.JSON(200, gin.H{"code": 0, "msg": "ok", "data": data})
}

func NetFilterFindAll(c *gin.Context) {
	limit, err := strconv.Atoi(c.DefaultQuery("limit", "10000"))
	if err != nil {
		c.JSON(200, gin.H{"code": 2, "msg": err.Error()})
		return
	}

	offset, err := strconv.Atoi(c.DefaultQuery("offset", "0"))
	if err != nil {
		c.JSON(200, gin.H{"code": 2, "msg": err.Error()})
		return
	}

	var netFilter model.NetFilter
	data, err := netFilter.FindAll(offset, limit)
	if err != nil {
		c.JSON(200, gin.H{"code": 2, "msg": err.Error()})
		return
	}
	c.JSON(200, gin.H{"code": 0, "msg": "ok", "data": data})
}

func NetFilterUpdateById(c *gin.Context) {
	var netFilter model.NetFilter
	if err := c.ShouldBind(&netFilter); err != nil {
		c.JSON(200, gin.H{"code": 1, "msg": err.Error()})
		return
	}
	err := netFilter.UpdateById(netFilter.ID, &netFilter)
	if err != nil {
		c.JSON(200, gin.H{"code": 2, "msg": err.Error()})
		return
	}
	NetFilterFindAll(c)
}

func NetFilterDeleteById(c *gin.Context) {
	id, err := strconv.Atoi(c.Param("id"))
	if err != nil {
		c.JSON(200, gin.H{"code": 2, "msg": err.Error()})
		return
	}
	var netFilter model.NetFilter
	err = netFilter.DeleteByID(uint(id))
	if err != nil {
		c.JSON(200, gin.H{"code": 2, "msg": err.Error()})
		return
	}
	NetFilterFindAll(c)
}


================================================
FILE: gossh/app/service/policy_conf.go
================================================
package service

import (
	"gossh/app/model"
	"gossh/gin"
	"strconv"
)

func PolicyConfCreate(c *gin.Context) {
	var conf model.PolicyConf
	if err := c.ShouldBind(&conf); err != nil {
		c.JSON(200, gin.H{"code": 1, "msg": err.Error()})
		return
	}

	err := conf.Create(&conf)
	if err != nil {
		c.JSON(200, gin.H{"code": 3, "msg": err.Error()})
		return
	}
	PolicyConfFindAll(c)
}

func PolicyConfFindByID(c *gin.Context) {
	id, err := strconv.Atoi(c.Param("id"))
	if err != nil {
		c.JSON(200, gin.H{"code": 2, "msg": err.Error()})
		return
	}
	var conf model.PolicyConf
	data, err := conf.FindByID(uint(id))
	if err != nil {
		c.JSON(200, gin.H{"code": 2, "msg": err.Error()})
		return
	}
	c.JSON(200, gin.H{"code": 0, "msg": "ok", "data": data})
}

func PolicyConfFindAll(c *gin.Context) {
	limit, err := strconv.Atoi(c.DefaultQuery("limit", "10000"))
	if err != nil {
		c.JSON(200, gin.H{"code": 2, "msg": err.Error()})
		return
	}

	offset, err := strconv.Atoi(c.DefaultQuery("offset", "0"))
	if err != nil {
		c.JSON(200, gin.H{"code": 2, "msg": err.Error()})
		return
	}

	var conf model.PolicyConf
	data, err := conf.FindAll(offset, limit)
	if err != nil {
		c.JSON(200, gin.H{"code": 2, "msg": err.Error()})
		return
	}
	c.JSON(200, gin.H{"code": 0, "msg": "ok", "data": data})
}

func PolicyConfUpdateById(c *gin.Context) {
	var conf model.PolicyConf
	if err := c.ShouldBind(&conf); err != nil {
		c.JSON(200, gin.H{"code": 1, "msg": err.Error()})
		return
	}
	err := conf.UpdateById(conf.ID, &conf)
	if err != nil {
		c.JSON(200, gin.H{"code": 2, "msg": err.Error()})
		return
	}

	data, err := conf.FindByID(conf.ID)
	if err != nil {
		c.JSON(200, gin.H{"code": 2, "msg": err.Error()})
		return
	}
	c.JSON(200, gin.H{"code": 0, "msg": "ok", "data": data})
}

func PolicyConfDeleteById(c *gin.Context) {
	id, err := strconv.Atoi(c.Param("id"))
	if err != nil {
		c.JSON(200, gin.H{"code": 2, "msg": err.Error()})
		return
	}
	var conf model.PolicyConf
	err = conf.DeleteByID(uint(id))
	if err != nil {
		c.JSON(200, gin.H{"code": 2, "msg": err.Error()})
		return
	}
	PolicyConfFindAll(c)
}


================================================
FILE: gossh/app/service/service_init.go
================================================
package service

import (
	"gossh/app/config"
	"io"
	"log/slog"
	"sync"
	"time"
)

// OnlineClients 存储的客户端信息
var OnlineClients = sync.Map{}

func DeleteOnlineClient(sessionId string) {
	defer func() {
		if err := recover(); err != nil {
			slog.Error("DeleteOnlineClient recover error:", "err_msg", err)
		}
	}()
	cli, ok := OnlineClients.Load(sessionId)
	if !ok || cli == nil {
		slog.Info("OnlineClient sessionId not exist")
		return
	}

	conn, ok := cli.(*SshConn)
	if !ok || conn == nil {
		slog.Error("DeleteOnlineClient type Asset error")
		return
	}

	// 从map 中删除会话
	defer OnlineClients.Delete(sessionId)

	// 关闭 ssh 客户端
	defer func() {
		err := conn.sshClient.Close()
		if err == io.EOF {
			slog.Info("sshClient.Close EOF")
			return
		}
		if err != nil {
			slog.Error("DeleteOnlineClient.Close sshClient error:", "err_msg", err)
		}
	}()

	// 关闭 sftp 客户端
	defer func() {
		err := conn.sftpClient.Close()
		if err == io.EOF {
			slog.Info("sftpClient.Close EOF")
			return
		}
		if err != nil {
			slog.Error("DeleteOnlineClient.Close sftpClient error:", "err_msg", err)
		}
	}()

	// 关闭 ssh 会话
	defer func() {
		err := conn.sshSession.Close()
		if err == io.EOF {
			slog.Info("sshSession.Close EOF")
			return
		}
		if err != nil {
			slog.Error("DeleteOnlineClient.Close sshSession error:", "err_msg", err)
		}
	}()

	// 关闭 websocket
	defer func() {
		err := conn.ws.Close()
		if err != nil {
			slog.Error("DeleteOnlineClient.Close ws error:", "err_msg", err)
		}
	}()

}

// 清理不活跃的会话
func cleanNoActiveSession() {
	defer func() {
		if err := recover(); err != nil {
			slog.Error("cleanNoActiveSession error:", "err_msg", err)
		}
	}()
	OnlineClients.Range(func(key, value any) bool {
		// 对键进行类型断言
		if sessionId, ok := key.(string); ok {
			// 对值进行类型断言
			if conn, ok := value.(*SshConn); ok {
				if conn.LastActiveTime.Add(time.Minute).Before(time.Now()) {
					slog.Info("clean not active session:", "sid", sessionId)
					DeleteOnlineClient(sessionId)
				}
			}
		}
		return true
	})
}

func initApp() {
	defer func() {
		if err := recover(); err != nil {
			slog.Error("service init error")
		}
	}()
	if config.DefaultConfig.IsInit {
		isStartSshd <- true
	}
	for {
		cleanNoActiveSession()
		time.Sleep(config.DefaultConfig.ClientCheck)
	}
}

func InitSessionClean() {
	go initApp()
}


================================================
FILE: gossh/app/service/ssh_conf.go
================================================
package service

import (
	"gossh/app/model"
	"gossh/gin"
	"strconv"
)

func ConfCreate(c *gin.Context) {
	var config model.SshConf
	if err := c.ShouldBind(&config); err != nil {
		c.JSON(200, gin.H{"code": 1, "msg": err.Error()})
		return
	}
	config.Uid = c.GetUint("uid")
	err := config.Create(&config)
	if err != nil {
		c.JSON(200, gin.H{"code": 2, "msg": err.Error()})
		return
	}
	ConfFindAll(c)
}

func ConfFindByID(c *gin.Context) {
	id, err := strconv.Atoi(c.Param("id"))
	if err != nil {
		c.JSON(200, gin.H{"code": 2, "msg": err.Error()})
		return
	}
	var config model.SshConf
	data, err := config.FindByID(uint(id), c.GetUint("uid"))
	if err != nil {
		c.JSON(200, gin.H{"code": 2, "msg": err.Error()})
		return
	}
	c.JSON(200, gin.H{"code": 0, "msg": "ok", "data": data})
}

func ConfFindAll(c *gin.Context) {
	limit, err := strconv.Atoi(c.DefaultQuery("limit", "10000"))
	if err != nil {
		c.JSON(200, gin.H{"code": 2, "msg": err.Error()})
		return
	}
	offset, err := strconv.Atoi(c.DefaultQuery("offset", "0"))
	if err != nil {
		c.JSON(200, gin.H{"code": 2, "msg": err.Error()})
		return
	}

	var config model.SshConf
	data, err := config.FindAll(offset, limit, c.GetUint("uid"))
	if err != nil {
		c.JSON(200, gin.H{"code": 2, "msg": err.Error()})
		return
	}
	c.JSON(200, gin.H{"code": 0, "msg": "ok", "data": data})
}

func ConfUpdateById(c *gin.Context) {
	var config model.SshConf
	if err := c.ShouldBind(&config); err != nil {
		c.JSON(200, gin.H{"code": 1, "msg": err.Error()})
		return
	}
	err := config.UpdateById(config.ID, c.GetUint("uid"), &config)
	if err != nil {
		c.JSON(200, gin.H{"code": 2, "msg": err.Error()})
		return
	}
	// c.JSON(200, gin.H{"code": 0, "msg": "ok"})
	ConfFindAll(c)
}

func ConfDeleteById(c *gin.Context) {
	id, err := strconv.Atoi(c.Param("id"))
	if err != nil {
		c.JSON(200, gin.H{"code": 2, "msg": err.Error()})
		return
	}
	var config model.SshConf
	err = config.DeleteByID(uint(id), c.GetUint("uid"))
	if err != nil {
		c.JSON(200, gin.H{"code": 2, "msg": err.Error()})
		return
	}
	// c.JSON(200, gin.H{"code": 0, "msg": "ok"})
	ConfFindAll(c)
}


================================================
FILE: gossh/app/service/ssh_conn.go
================================================
package service

import (
	"encoding/json"
	"fmt"
	"gossh/app/model"
	"gossh/app/utils"
	"gossh/crypto/ssh"
	"gossh/gin"
	"gossh/sftp"
	"gossh/websocket"
	"io"
	"log/slog"
	"net/http"
	"strconv"
	"strings"
	"time"
)

type SshConn struct {
	*model.SshConf

	//会话ID
	SessionId string `json:"session_id"`

	// 最后活跃时间,心跳
	LastActiveTime time.Time `json:"last_active_time"`

	// 创建连接的时间
	StartTime time.Time `json:"start_time"`

	// 客户端IP
	ClientIP string `json:"client_ip"`

	//ssh客户端
	sshClient *ssh.Client

	//sftp客户端
	sftpClient *sftp.Client

	//ssh会话
	sshSession *ssh.Session

	// websocket 连接
	ws *websocket.Conn
}

// MarshalJSON 重写序列化方法
func (s *SshConn) MarshalJSON() ([]byte, error) {
	type Alias SshConn
	return json.Marshal(&struct {
		Alias
		LastActiveTime string `json:"last_active_time"`
		StartTime      string `json:"start_time"`
		Pwd            string `json:"pwd"`
		CertData       string `json:"cert_data"`
		CertPwd        string `json:"cert_pwd"`
		CreatedAt      uint   ` json:"created_at"`
		UpdatedAt      uint   ` json:"updated_at"`
		DeletedAt      uint   ` json:"deleted_at"`
	}{
		Alias:          (Alias)(*s),
		LastActiveTime: s.LastActiveTime.Format("2006-01-02 15:04:05"),
		StartTime:      s.StartTime.Format("2006-01-02 15:04:05"),
		Pwd:            "",
		CertData:       "",
		CertPwd:        "",
		CreatedAt:      0,
		UpdatedAt:      0,
		DeletedAt:      0,
	})
}

// 连接主机
func (s *SshConn) connect(clientIp string) error {
	defer func() {
		if err := recover(); err != nil {
			slog.Error("ssh connect error:", "err_msg", err)
		}
	}()
	s.ClientIP = clientIp

	config := ssh.ClientConfig{
		User: s.User,
		Auth: []ssh.AuthMethod{
			ssh.Password(s.Pwd),
			ssh.KeyboardInteractive(func(name, instruction string, questions []string, echos []bool) ([]string, error) {
				answers := make([]string, len(questions))
				for i := range answers {
					answers[i] = s.Pwd
				}
				return answers, nil
			}),
		},
		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
		Timeout:         30 * time.Second,
	}
	// 证书认证方式
	if s.AuthType == "cert" {
		privateKeyPassword := []byte(s.CertPwd)
		privateKeyBytes := []byte(s.CertData)
		if s.CertPwd != "" {
			// 使用证书有证书密码登陆
			signer, err := ssh.ParsePrivateKeyWithPassphrase(privateKeyBytes, privateKeyPassword)
			if err != nil {
				slog.Error("解析带密码私钥Key错误:", "err_msg", err.Error())
				return err
			}
			config.Auth = []ssh.AuthMethod{
				ssh.PublicKeys(signer),
			}
		} else {
			// 使用证书空密码登陆
			signer, err := ssh.ParsePrivateKey(privateKeyBytes)
			if err != nil {
				slog.Error("解析私钥Key错误:", "err_msg", err.Error())
				return err
			}
			config.Auth = []ssh.AuthMethod{
				ssh.PublicKeys(signer),
			}
		}
	}

	addr := fmt.Sprintf("%s:%d", s.Address, s.Port)
	if s.NetType == "tcp6" {
		addr = fmt.Sprintf("[%s]:%d", s.Address, s.Port)
	}
	sshClient, err := ssh.Dial(s.NetType, addr, &config)
	if err != nil {
		return err
	}

	s.sshClient = sshClient
	//使用sshClient构建sftpClient
	var sftpClient *sftp.Client
	if sftpClient, err = sftp.NewClient(sshClient); err != nil {
		slog.Error("create sftp sshClient error:", "err_msg", err)
	}
	s.sftpClient = sftpClient
	sshSession, err := s.sshClient.NewSession()
	if err != nil {
		slog.Error("sshClient.NewSession error:", "err_msg", err.Error())
		return err
	}
	s.sshSession = sshSession
	return nil
}

// RunTerminal 运行一个终端
func (s *SshConn) RunTerminal(shell string, stdout, stderr io.Writer, stdin io.Reader, w, h int, ws *websocket.Conn) error {
	defer func() {
		DeleteOnlineClient(s.SessionId)
		if err := recover(); err != nil {
			slog.Error("RunTerminal error:", "err_msg", err)
		}
	}()
	var err error

	s.ws = ws
	s.sshSession.Stdout = stdout
	s.sshSession.Stderr = stderr
	s.sshSession.Stdin = stdin
	modes := ssh.TerminalModes{}
	if err := s.sshSession.RequestPty(s.PtyType, h, w, modes); err != nil {
		slog.Error("sshSession.RequestPty error:", "err_msg", err.Error())
		ws.WriteMessage(websocket.BinaryMessage, []byte("sshSession.RequestPty error:"+err.Error()))
		return err
	}

	if err = s.sshSession.Shell(); err != nil {
		slog.Error("sshSession.Shell error:", "err_msg", err.Error())
		return err
	}

	if err = s.sshSession.Wait(); err != nil {
		if strings.Contains(err.Error(), "remote command exited without exit status or exit signal") {
			slog.Info("sshSession.Wait remote command exited without exit status or exit signal")
			return err
		}
		slog.Error("sshSession.Wait error:", "err_msg", err.Error())
		return err
	}

	return nil
}

// ResizeWindow  调整终端大小
func (s *SshConn) ResizeWindow(c *gin.Context) {
	defer func() {
		if err := recover(); err != nil {
			slog.Error("ResizeWindow recover error:", "err_msg", err)
		}
	}()
	w, err := strconv.Atoi(c.Query("w"))
	if err != nil || (w < 40 || w > 8192) {
		c.JSON(200, gin.H{
			"code": 1,
			"msg":  fmt.Sprintf("connect error window width !!!")})
		return
	}
	h, err := strconv.Atoi(c.Query("h"))
	if err != nil || (h < 2 || h > 4096) {
		c.JSON(200, gin.H{
			"code": 1,
			"msg":  fmt.Sprintf("connect error window width !!!")})
		return
	}

	sessionId := c.Query("session_id")
	cli, ok := OnlineClients.Load(sessionId)
	if !ok || cli == nil {
		c.JSON(200, gin.H{"code": 1, "msg": "the client is disconnected"})
		return
	}

	conn, ok := cli.(*SshConn)
	if !ok || conn == nil {
		DeleteOnlineClient(sessionId)
		c.JSON(200, gin.H{"code": 1, "msg": "to type SshConn error"})
		return
	}

	err = conn.sshSession.WindowChange(h, w)
	if err != nil {
		DeleteOnlineClient(sessionId)
		slog.Error("sshSession.WindowChange error:", "err_msg", err.Error())
	}
	str := fmt.Sprintf("W:%d;H:%d\n", w, h)
	c.JSON(200, gin.H{"code": 0, "data": str, "msg": "ok"})
	return
}

func ResizeWindow(c *gin.Context) {
	var sshObj = SshConn{}
	sshObj.ResizeWindow(c)
}

func NewSshConn(c *gin.Context) {
	// 设置 websocket upgrader
	upgrader := websocket.Upgrader{
		ReadBufferSize:  4096,
		WriteBufferSize: 4096,
		CheckOrigin: func(r *http.Request) bool {
			return true
		},
	}

	// 升级 HTTP 连接为 WebSocket 连接
	ws, err := upgrader.Upgrade(c.Writer, c.Request, nil)
	if err != nil {
		slog.Error("Failed to upgrade connection:", "err_msg", err)
		return
	}
	defer ws.Close()

	// 设置 ping handler
	ws.SetPingHandler(func(appData string) error {
		return ws.WriteControl(websocket.PongMessage, []byte{}, time.Now().Add(time.Second*10))
	})

	// 启动 ping 保活
	go func() {
		ticker := time.NewTicker(30 * time.Second)
		defer ticker.Stop()
		for {
			select {
			case <-ticker.C:
				if err := ws.WriteControl(websocket.PingMessage, []byte{}, time.Now().Add(time.Second*10)); err != nil {
					slog.Error("ping error:", "err_msg", err)
					return
				}
			}
		}
	}()

	sessionId := c.Query("session_id")
	defer DeleteOnlineClient(sessionId)

	w, err := strconv.Atoi(c.Query("w"))
	if err != nil || (w < 40 || w > 8192) {
		ws.WriteMessage(websocket.BinaryMessage, []byte("connect error window width !!!"))
		DeleteOnlineClient(sessionId)
		return
	}

	h, err := strconv.Atoi(c.Query("h"))
	if err != nil || (h < 2 || h > 4096) {
		ws.WriteMessage(websocket.BinaryMessage, []byte("connect error window height !!!"))
		DeleteOnlineClient(sessionId)
		return
	}

	cli, ok := OnlineClients.Load(sessionId)
	if !ok || cli == nil {
		ws.WriteMessage(websocket.BinaryMessage, []byte("session_id not exists !!!"))
		DeleteOnlineClient(sessionId)
		return
	}

	conn, ok := cli.(*SshConn)
	if !ok || conn == nil {
		ws.WriteMessage(websocket.BinaryMessage, []byte("to ssh.Session error !!!"))
		DeleteOnlineClient(sessionId)
		return
	}

	// 创建一个适配器来实现 io.Reader 和 io.Writer 接口
	wsReadWriter := &WebSocketReadWriter{ws: ws}

	err = conn.RunTerminal(conn.Shell, wsReadWriter, wsReadWriter, wsReadWriter, w, h, ws)
	if err != nil {
		ws.WriteMessage(websocket.BinaryMessage, []byte("connect error:"+err.Error()))
		DeleteOnlineClient(sessionId)
		return
	}
}

// WebSocketReadWriter 实现 io.Reader 和 io.Writer 接口
type WebSocketReadWriter struct {
	ws *websocket.Conn
}

func (w *WebSocketReadWriter) Read(p []byte) (n int, err error) {
	_, message, err := w.ws.ReadMessage()
	if err != nil {
		return 0, err
	}
	copy(p, message)
	return len(message), nil
}

func (w *WebSocketReadWriter) Write(p []byte) (n int, err error) {
	err = w.ws.WriteMessage(websocket.BinaryMessage, p)
	if err != nil {
		return 0, err
	}
	return len(p), nil
}

func CreateSessionId(c *gin.Context) {
	var conn SshConn
	if err := c.ShouldBind(&conn); err != nil {
		c.JSON(200, gin.H{"code": 1, "msg": err.Error()})
		return
	}

	// 如果客户提供,使用客户的,并从会话列表删除,防止重复存在
	sessionId := c.Query("session_id")
	//DeleteOnlineClient(sessionId)
	if sessionId == "" {
		sessionId = utils.RandString(15)
	}

	conn.SessionId = sessionId
	conn.LastActiveTime = time.Now()
	conn.StartTime = time.Now()

	err := conn.connect(c.RemoteIP())
	if err != nil {
		c.JSON(200, gin.H{"code": 1, "msg": "CreateSessionId error:" + err.Error()})
		return
	}

	OnlineClients.Store(sessionId, &conn)
	c.JSON(200, gin.H{"code": 0, "data": sessionId, "msg": "ok"})
}

func Disconnect(c *gin.Context) {
	defer func() {
		if err := recover(); err != nil {
			c.JSON(200, gin.H{
				"code": 1,
				"msg":  "delete connect error",
			})
		}
	}()

	sessionId := c.Query("session_id")
	if sessionId == "" {
		c.JSON(200, gin.H{
			"code": 1,
			"msg":  "session not exists",
		})
		return
	}
	DeleteOnlineClient(sessionId)
	c.JSON(200, gin.H{
		"code": 0,
		"msg":  "delete connect success",
	})
}

func ExecCommand(c *gin.Context) {
	type Param struct {
		SessionId string `form:"session_id" binding:"required,min=10" json:"session_id"`
		Cmd       string `form:"cmd" binding:"required,min=1" json:"cmd"`
	}
	var param Param
	if err := c.ShouldBind(&param); err != nil {
		c.JSON(200, gin.H{"code": 2, "msg": err.Error()})
		return
	}

	cli, ok := OnlineClients.Load(param.SessionId)
	if !ok || cli == nil {
		c.JSON(200, gin.H{"code": 3, "msg": "session not exists"})
		return
	}

	conn, ok := cli.(*SshConn)
	if !ok || conn == nil {
		c.JSON(200, gin.H{"code": 4, "msg": "conn not exists"})
		return
	}

	//创建ssh-session
	session, err := conn.sshClient.NewSession()
	if err != nil {
		c.JSON(200, gin.H{"code": 5, "msg": "create session error"})
		return
	}
	defer func(session *ssh.Session) {
		_ = session.Close()
	}(session)

	//执行命令
	out, err := session.CombinedOutput(param.Cmd)
	if err != nil {
		c.JSON(200, gin.H{"code": 6, "msg": "exec cmd error", "data": string(out)})
		return
	}

	c.JSON(200, gin.H{
		"code": 0,
		"msg":  "ok",
		"data": string(out),
	})
}


================================================
FILE: gossh/app/service/ssh_sftp.go
================================================
package service

import (
	"errors"
	"fmt"
	"gossh/gin"
	"io"
	"log/slog"
	"net/http"
	"net/url"
	"path"
	"strconv"
	"strings"
)

func getSshConn(sessionId string) (*SshConn, error) {
	cli, ok := OnlineClients.Load(sessionId)
	if !ok {
		slog.Error("加载ssh连接错误")
		return nil, errors.New("加载ssh连接错误")
	}
	conn, ok := cli.(*SshConn)
	if conn != nil && !ok {
		slog.Error("断言ssh连接错误")
		return nil, errors.New("断言ssh连接错误")
	}
	return conn, nil
}

// SftpList GET sftp 获取指定目录下文件信息
func SftpList(c *gin.Context) {
	defer func() {
		if err := recover(); err != nil {
			c.JSON(200, gin.H{"code": 4, "msg": "读取目录错误"})
			return
		}
	}()
	dirPath := c.PostForm("path")

	conn, err := getSshConn(c.PostForm("session_id"))
	if err != nil {
		slog.Error(err.Error())
		c.JSON(200, gin.H{"code": 2, "msg": err.Error()})
		return
	}

	files, err := conn.sftpClient.ReadDir(dirPath)
	if err != nil {
		slog.Error("sftp客户端ReadDir错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 3, "msg": "sftp客户端读取目录错误"})
		return
	}

	fileCount := 0
	dirCount := 0
	var fileList []any
	for _, file := range files {
		fileInfo := map[string]any{}
		fileInfo["path"] = path.Join(dirPath, file.Name())
		fileInfo["name"] = file.Name()
		fileInfo["mode"] = file.Mode().String()
		fileInfo["size"] = file.Size()
		fileInfo["mod_time"] = file.ModTime().Format("2006-01-02 15:04:05")
		if file.IsDir() {
			fileInfo["type"] = "d"
			dirCount += 1
		} else {
			fileInfo["type"] = "f"
			fileCount += 1
		}
		fileList = append(fileList, fileInfo)
	}

	// 内部方法,处理路径信息
	pathHandler := func(dirPath string) (paths []map[string]string) {
		tmp := strings.Split(dirPath, "/")

		var dirs []string
		if strings.HasPrefix(dirPath, "/") {
			dirs = append(dirs, "/")
		}

		for _, item := range tmp {
			name := strings.TrimSpace(item)
			if len(name) > 0 {
				dirs = append(dirs, name)
			}
		}

		for i, item := range dirs {
			fullPath := path.Join(dirs[:i+1]...)
			pathInfo := map[string]string{}
			pathInfo["name"] = item
			pathInfo["dir"] = fullPath
			paths = append(paths, pathInfo)
		}
		return paths
	}

	data := map[string]any{
		"files":       fileList,
		"file_count":  fileCount,
		"dir_count":   dirCount,
		"paths":       pathHandler(dirPath),
		"current_dir": dirPath,
	}

	c.JSON(200, gin.H{"code": 0, "data": data, "msg": "ok"})
}

// SftpDownLoad POST sftp 下载文件
func SftpDownLoad(c *gin.Context) {
	defer func() {
		if err := recover(); err != nil {
			c.JSON(200, gin.H{"code": 1, "msg": "下载错误"})
			return
		}
	}()
	fullPath, err := url.QueryUnescape(c.Query("path"))
	if err != nil {
		slog.Error("获取文件路径参数错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 2, "msg": "获取文件路径参数错误"})
		return
	}
	conn, err := getSshConn(c.Query("session_id"))
	if err != nil {
		slog.Error(err.Error())
		c.JSON(200, gin.H{"code": 3, "msg": err.Error()})
		return
	}

	file, err := conn.sftpClient.Open(fullPath)
	defer func() {
		_ = file.Close()
	}()
	if err != nil {
		slog.Error("sftpClient.Openc错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 4, "msg": "sftp打开文件错误"})
		return
	}

	stat, err := file.Stat()
	if err != nil {
		slog.Error("file.Stat()错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 4, "msg": "读取文件信息错误"})
		return
	}

	c.Writer.WriteHeader(http.StatusOK)
	c.Header("Content-Disposition", "attachment; filename="+stat.Name())
	c.Header("Content-Type", "application/octet-stream")
	//c.Header("Content-Type", "application/x-download")
	c.Header("Content-Length", fmt.Sprintf("%d", stat.Size()))
	_, err = file.WriteTo(c.Writer)
	if err != nil {
		slog.Error("file.WriteTo错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 5, "msg": "下载文件错误"})
		return
	}
	c.Writer.Flush()
}

// SftpUpload PUT sftp 上传文件
func SftpUpload(c *gin.Context) {
	defer func() {
		if err := recover(); err != nil {
			c.JSON(200, gin.H{"code": 4, "msg": "上传错误"})
			return
		}
	}()

	dstPath := c.PostForm("path")
	//获取上传的文件组
	form, err := c.MultipartForm()
	if err != nil {
		slog.Error("获取form数据错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 1, "msg": "获取form数据错误"})
		return
	}
	files := form.File["files"]
	// files := c.Request.MultipartForm.File["file"]

	conn, err := getSshConn(c.PostForm("session_id"))
	if err != nil {
		slog.Error(err.Error())
		c.JSON(200, gin.H{"code": 2, "msg": err.Error()})
		return
	}

	var ret []string
	for _, file := range files {
		srcFile, err := file.Open()
		if err != nil {
			continue
		}
		fileName := file.Filename
		dstFile, err := conn.sftpClient.Create(path.Join(dstPath, fileName))
		if err != nil {
			continue
		}
		_, err = io.Copy(dstFile, srcFile)
		if err != nil {
			continue
		}
		_ = srcFile.Close()
		_ = dstFile.Close()
		ret = append(ret, fileName)
	}
	msg := strconv.Itoa(len(ret)) + " 个文件上传成功"
	c.JSON(200, gin.H{"code": 0, "msg": msg, "data": ret})
}

// SftpDelete DELETE sftp 删除文件或目录
func SftpDelete(c *gin.Context) {
	defer func() {
		if err := recover(); err != nil {
			c.JSON(200, gin.H{"code": 4, "msg": "删除错误"})
			return
		}
	}()

	type Body struct {
		SessionId string `form:"session_id" binding:"required,min=1,max=128" json:"session_id"`
		Path      string `form:"path" binding:"required,min=1,max=1024" json:"path"`
	}

	var body Body
	if err := c.ShouldBind(&body); err != nil {
		slog.Error("绑定数据错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 1, "msg": "输入数据不合法"})
		return
	}
	conn, err := getSshConn(body.SessionId)
	if err != nil {
		slog.Error(err.Error())
		c.JSON(200, gin.H{"code": 1, "msg": err.Error()})
		return
	}

	err = conn.sftpClient.RemoveAll(body.Path)
	if err != nil {
		slog.Error("sftpClient.Remove错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 2, "msg": "删除文件错误"})
		return
	}
	c.JSON(200, gin.H{"code": 0, "msg": "删除成功"})
}

// SftpCreateDir sftp 创建目录
func SftpCreateDir(c *gin.Context) {
	defer func() {
		if err := recover(); err != nil {
			c.JSON(200, gin.H{"code": 4, "msg": "创建目录错误"})
			return
		}
	}()

	type Body struct {
		SessionId string `form:"session_id" binding:"required,min=1,max=128" json:"session_id"`
		Path      string `form:"path" binding:"required,min=1,max=1024" json:"path"`
	}

	var body Body
	if err := c.ShouldBind(&body); err != nil {
		slog.Error("绑定数据错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 1, "msg": "输入数据不合法"})
		return
	}
	conn, err := getSshConn(body.SessionId)
	if err != nil {
		slog.Error(err.Error())
		c.JSON(200, gin.H{"code": 1, "msg": err.Error()})
		return
	}

	err = conn.sftpClient.MkdirAll(body.Path)
	if err != nil {
		slog.Error("sftpClient.MkdirAll错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 2, "msg": "创建目录错误"})
		return
	}
	c.JSON(200, gin.H{"code": 0, "msg": "创建目录成功"})
}


================================================
FILE: gossh/app/service/ssh_status.go
================================================
package service

import (
	"gossh/app/config"
	"gossh/gin"
	"gossh/gin/sse"
	"net/http"
	"sort"
	"time"
)

type SshConnById []SshConn

func (a SshConnById) Len() int           { return len(a) }
func (a SshConnById) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a SshConnById) Less(i, j int) bool { return a[i].SessionId < a[j].SessionId }

func GetOnlineClient(c *gin.Context) {
	c.Header("Access-Control-Allow-Origin", "*")
	c.Header("Connection", "keep-alive")
	c.Header("Cache-Control", "no-cache")
	c.Header("Content-Type", "text/event-stream")

	for {
		c.Writer.(http.Flusher).Flush()
		time.Sleep(config.DefaultConfig.StatusRefresh)
		select {
		case <-c.Request.Context().Done():
			return
		default:
			var data SshConnById
			OnlineClients.Range(func(key, value any) bool {
				conn, ok := value.(*SshConn)
				if ok && conn != nil {
					data = append(data, *conn)
				}
				return ok
			})

			sort.Sort(data)
			c.Render(200, sse.Event{
				Id:    "200",
				Event: "message",
				Retry: 10000,
				Data: map[string]any{
					"code": 0,
					"data": data,
					"msg":  "ok",
				},
			})
		}
	}
}

func RefreshConnTime(c *gin.Context) {
	ids := c.PostFormArray("ids")
	for _, key := range ids {
		cli, ok := OnlineClients.Load(key)
		if !ok {
			continue
		}
		conn, ok := cli.(*SshConn)
		if conn != nil && ok {
			conn.LastActiveTime = time.Now()
		}
	}
	c.JSON(200, gin.H{
		"code": 0,
		"data": ids,
		"msg":  "ok",
	})
}


================================================
FILE: gossh/app/service/sshd_cert.go
================================================
package service

import (
	"gossh/app/model"
	"gossh/gin"
	"log/slog"
	"strconv"
)

func SshdCertCreate(c *gin.Context) {
	var sshdCert model.SshdCert
	if err := c.ShouldBind(&sshdCert); err != nil {
		slog.Error("SshdCertCreate 绑定数据错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 1, "msg": "输入数据不合法"})
		return
	}

	err := sshdCert.Create(&sshdCert)
	if err != nil {
		slog.Error("创建SSHD证书错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 3, "msg": "创建SSHD证书错误"})
		return
	}
	SshdCertFindAll(c)
}

func CheckSshdCertNameExists(c *gin.Context) {
	type Name struct {
		Name string `form:"name" binding:"required,min=1,max=128" json:"name"`
	}
	var name Name
	if err := c.ShouldBind(&name); err != nil {
		slog.Error("绑定数据错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 1, "msg": "输入数据不合法"})
		return
	}

	var sshdCert model.SshdCert
	tmp, err := sshdCert.FindByName(name.Name)
	if err != nil {
		slog.Error("FindByName错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 3, "msg": "获取SSHD证书信息错误"})
		return
	}

	if tmp.ID != 0 {
		c.JSON(200, gin.H{"code": 4, "msg": "名称已经存存在"})
		return
	}
	c.JSON(200, gin.H{"code": 0, "msg": "ok"})
	return
}

func SshdCertFindByID(c *gin.Context) {
	id, err := strconv.Atoi(c.Param("id"))
	if err != nil {
		slog.Error("获取ID错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 1, "msg": "获取ID错误"})
		return
	}

	var sshdCert model.SshdCert
	data, err := sshdCert.FindByID(uint(id))
	if err != nil {
		slog.Error("FindByID错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 3, "msg": "获取SSHD证书信息错误"})
		return
	}
	c.JSON(200, gin.H{"code": 0, "msg": "ok", "data": data})
}

func SshdCertFindAll(c *gin.Context) {
	limit, err := strconv.Atoi(c.DefaultQuery("limit", "10000"))
	if err != nil {
		slog.Error("获取limit错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 1, "msg": "获取limit错误"})
		return
	}

	offset, err := strconv.Atoi(c.DefaultQuery("offset", "0"))
	if err != nil {
		slog.Error("获取offset错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 2, "msg": "获取offset错误"})
		return
	}

	var sshdCert model.SshdCert
	data, err := sshdCert.FindAll(limit, offset)
	if err != nil {
		slog.Error("sshdCert.FindAll错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 4, "msg": "获取SSHD证书信息错误"})
		return
	}
	c.JSON(200, gin.H{"code": 0, "msg": "ok", "data": data})
}

func SshdCertUpdateById(c *gin.Context) {
	var sshdCert model.SshdCert
	if err := c.ShouldBind(&sshdCert); err != nil {
		slog.Error("获取ID错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 1, "msg": "获取ID错误"})
		return
	}

	err := sshdCert.UpdateById(sshdCert.ID, &sshdCert)
	if err != nil {
		slog.Error("UpdateById错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 5, "msg": "更新SSHD证书错误"})
		return
	}
	SshdCertFindAll(c)
}

func SshdCertDeleteById(c *gin.Context) {
	id, err := strconv.Atoi(c.Param("id"))
	if err != nil {
		slog.Error("获取ID错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 1, "msg": "获取ID错误"})
		return
	}

	var sshdCert model.SshdCert
	err = sshdCert.DeleteByID(uint(id))
	if err != nil {
		slog.Error("sshdCert.DeleteByID错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 5, "msg": "删除SSHD证书错误"})
		return
	}
	SshdCertFindAll(c)
}

func GetSshdCertAuthorizedKeys(c *gin.Context) {
	var sshdCert model.SshdCert
	text, err := sshdCert.GetAuthorizedKeys()
	if err != nil {
		slog.Error("GetAuthorizedKeys failed", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 5, "msg": "获取SSHD证书错误", "err_msg": err})
		return
	}
	c.JSON(200, gin.H{"code": 5, "msg": "ok", "data": text})
}


================================================
FILE: gossh/app/service/sshd_server.go
================================================
package service

import (
	"bytes"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha256"
	"crypto/sha512"
	"crypto/x509"
	"encoding/base64"
	"encoding/binary"
	"encoding/pem"
	"errors"
	"fmt"
	"gossh/app/model"
	"gossh/crypto/ssh"
	"gossh/pty"
	"gossh/sftp"
	"io"
	"log"
	"log/slog"
	"net"
	"os"
	"os/exec"
	"os/user"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"time"
)

type Server struct {
	cli    *model.SshdConf
	config *ssh.ServerConfig
}

func NewServer(c *model.SshdConf) (*Server, error) {
	s := &Server{cli: c}
	sc, err := s.computeSSHConfig()
	if err != nil {
		return nil, err
	}
	s.config = sc
	return s, nil
}

func (s *Server) Start() error {
	listen, err := net.Listen("tcp", fmt.Sprintf("%s:%d", s.cli.Host, s.cli.Port))
	if err != nil {
		return fmt.Errorf("failed to listen on" + fmt.Sprintf("%s:%d", s.cli.Host, s.cli.Port))
	}
	slog.Info("Listening on", "host", s.cli.Host, "port", s.cli.Port)
	for {
		tcpConn, err := listen.Accept()
		if err != nil {
			slog.Error("Failed to accept incoming connection", "err", err)
			continue
		}
		go s.handleConn(tcpConn)
	}
}

func (s *Server) handleConn(tcpConn net.Conn) {
	defer func() {
		if err := recover(); err != nil {
			slog.Error("recovered from panic in handleConn", "err", err)
		}
	}()

	sshConn, chans, reqs, err := ssh.NewServerConn(tcpConn, s.config)
	if err != nil {
		if err != io.EOF {
			slog.Info("Failed to handshake", "err", err)
		}
		return
	}
	slog.Info("New SSH connection from", "address", sshConn.RemoteAddr(), "client_version", sshConn.ClientVersion())
	go ssh.DiscardRequests(reqs)
	go s.handleChannels(chans)
}

func (s *Server) handleChannels(chans <-chan ssh.NewChannel) {
	// Service the incoming Channel channel in go routine
	for newChannel := range chans {
		go s.handleChannel(newChannel)
	}
}

func (s *Server) handleChannel(newChannel ssh.NewChannel) {
	if t := newChannel.ChannelType(); t != "session" {
		_ = newChannel.Reject(ssh.UnknownChannelType, fmt.Sprintf("unknown channel type: %s", t))
		return
	}

	slog.Info("Channel request", "type", newChannel.ChannelType())
	if d := newChannel.ExtraData(); len(d) > 0 {
		slog.Info("Channel data", "data", d)
	}

	connection, requests, err := newChannel.Accept()
	if err != nil {
		slog.Error("Could not accept channel failed", "err", err)
		return
	}
	log.Println("Channel accepted")
	go s.handleRequests(connection, requests)
}

func (s *Server) handleRequests(connection ssh.Channel, requests <-chan *ssh.Request) {
	defer func() {
		if err := recover(); err != nil {
			slog.Error("handleRequests recovered from panic", "err", err)
		}
	}()

	// start keep alive loop
	if ka := s.cli.KeepAlive; ka > 0 {
		ticking := make(chan bool, 1)
		interval := time.Duration(ka) * time.Second
		go s.keepAlive(connection, interval, ticking)
		defer close(ticking)
	}
	// prepare to handle client requests
	env := os.Environ()
	resizes := make(chan []byte, 10)
	defer close(resizes)

	for req := range requests {
		switch req.Type {
		case "subsystem":
			if string(req.Payload[4:]) == "sftp" {
				req.Reply(true, nil)
				server, err := sftp.NewServer(connection, sftp.WithDebug(os.Stderr))
				if err != nil {
					slog.Error("create SFTP server error", "err", err)
					connection.Close()
					return
				}
				err = server.Serve()
				if err == io.EOF {
					server.Close()
					connection.Close()
					return
				} else if err != nil {
					slog.Error("SFTP server error", "err", err)
					connection.Close()
					return
				} else {
					connection.Close()
					return
				}
			}
		case "pty-req":
			termLen := req.Payload[3]
			resizes <- req.Payload[termLen+4:]
			req.Reply(true, nil)
		case "window-change":
			resizes <- req.Payload
		case "env":
			e := struct{ Name, Value string }{}
			_ = ssh.Unmarshal(req.Payload, &e)
			kv := e.Name + "=" + e.Value
			slog.Info("env", "data", kv)
			if s.cli.LoadEnv == "Y" {
				env = appendEnv(env, kv)
			}
		case "shell":
			if len(req.Payload) > 0 {
				slog.Info("shell command ignored", "payload", req.Payload)
			}
			slog.Info("sshd attachShell")
			err := s.attachShell(connection, env, resizes)
			if err != nil {
				slog.Error("exec shell", "err", err)
			}
			req.Reply(err == nil, []byte{})
		case "exec":
			if req.WantReply {
				req.Reply(true, nil)
			}
			command := string(req.Payload[4:])
			slog.Info("exec command string", "cmd", command)
			ret := ExecuteForChannel(command, connection)
			slog.Info("exec return", "code", ret)
			connection.Close()
			return
		default:
			slog.Info("unknown request", "type", req.Type, "want_reply", req.WantReply, "payload", req.Payload)
		}
	}
}

func (s *Server) keepAlive(connection ssh.Channel, interval time.Duration, ticking <-chan bool) {
	defer func() {
		if err := recover(); err != nil {
			slog.Error("keepAlive recovered from panic", "err", err)
		}
	}()
	ticker := time.NewTicker(interval)
	defer ticker.Stop()
	for {
		select {
		case <-ticker.C:
			_, err := connection.SendRequest("ping", false, nil)
			if err != nil {
				slog.Error("failed to send keep alive ping", "err", err)
			}
			slog.Info("sent keep alive ping")
		case <-ticking:
			return
		}
	}
}

func (s *Server) attachShell(connection ssh.Channel, env []string, resizes <-chan []byte) error {
	defer func() {
		if err := recover(); err != nil {
			fmt.Printf("recovered from panic in handleRequests: %s", err)
		}
	}()

	shell := exec.Command(s.cli.Shell)
	dir, err := os.UserHomeDir()
	if err == nil {
		shell.Dir = dir
	}

	shell.Env = env
	slog.Info("Session env", "data", env)

	closeFunc := func() {
		err := connection.Close()
		if err != nil {
			slog.Error("close connect failed", "err_msg", err)
			return
		}
		slog.Info("Session closed")
	}

	shellPty, err := pty.Start(shell)
	if err != nil {
		closeFunc()
		return fmt.Errorf("could not start pty (%s)\n", err)
	}
	//dequeue resizes
	go func() {
		for payload := range resizes {
			w, h := parseDims(payload)
			SetWindowSize(shellPty, w, h)
		}
	}()
	//pipe session to shell and visa-versa
	var once sync.Once
	go func() {
		_, _ = io.Copy(connection, shellPty)
		once.Do(closeFunc)
	}()
	go func() {
		_, _ = io.Copy(shellPty, connection)
		once.Do(closeFunc)
	}()
	slog.Info("shell attached")
	go func() {
		if shell.Process != nil {
			if ps, err := shell.Process.Wait(); err != nil && ps != nil {
				slog.Error("Failed to exit shell", "err", err)
			}
			// shellPty.Close()
		}
		slog.Info("Shell terminated and Session closed")
	}()
	return nil
}

func (s *Server) loadCertAuthFile() (map[string]string, error) {
	var tmp model.SshdCert
	authorizedKeys, err := tmp.GetAuthorizedKeys()
	if err != nil {
		slog.Error("GetAuthorizedKeys failed", "err_msg", err.Error())
		return nil, err
	}

	keys, err := parseKeys([]byte(authorizedKeys))
	if err != nil {
		slog.Error("parseKeys failed", "err_msg", err.Error())
		return nil, err
	}
	return keys, nil
}

func (s *Server) computeSSHConfig() (*ssh.ServerConfig, error) {
	sc := &ssh.ServerConfig{}
	if s.cli.Shell == "" {
		if runtime.GOOS == "windows" {
			s.cli.Shell = "powershell"
		} else {
			s.cli.Shell = "sh"
		}
	}
	p, err := exec.LookPath(s.cli.Shell)
	if err != nil {
		return nil, fmt.Errorf("find shell failed: %s\n", s.cli.Shell)
	}
	s.cli.Shell = p
	slog.Info("Session shell", "shell", s.cli.Shell)

	//user provided key (can generate with 'ssh-keygen -t rsa')
	pri, err := ssh.ParsePrivateKey([]byte(s.cli.KeyFile))
	if err != nil {
		return nil, fmt.Errorf("failed to parse private key\n")
	}
	sc.AddHostKey(pri)
	slog.Info("RSA key", "fingerprint", fingerprint(pri.PublicKey()))

	// 注册账号密码认证逻辑(回调函数)
	sc.PasswordCallback = func(conn ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
		var sshdUsers model.SshdUser
		u, err := sshdUsers.FindByNameAndPwd(conn.User(), string(pass))
		if err != nil {
			slog.Error("Authentication failed", "username", conn.User(), "err_msg", err)
			return nil, err
		}

		if conn.User() == u.Name && string(pass) == u.Pwd {
			slog.Info("Authentication failed with password", "username", conn.User())
			return nil, nil
		}
		slog.Info("Authentication failed", "username", conn.User(), "password", u.Pwd)
		return nil, fmt.Errorf("auth denied\n")
	}

	// 注册证书认证逻辑(回调函数)
	sc.PublicKeyCallback = func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
		ks, err := s.loadCertAuthFile()
		if err != nil {
			return nil, err
		}
		slog.Info("Authentication enabled public keys", "size", len(ks))
		return nil, s.matchKeys(key, ks)
	}

	// 注册BannerCallback(回调函数)
	sc.BannerCallback = func(conn ssh.ConnMetadata) string {
		// 写入自定义的横幅信息到客户端
		return fmt.Sprintf("Welcome to the Go_SSH_Server\n=>user:(%s)\n=>remote addr:(%s)\n=>local  addr:(%s)\n=>client  ver:(%s)\n=>server  ver:(%s)\n\n",
			conn.User(), conn.RemoteAddr().String(), conn.LocalAddr(),
			conn.ClientVersion(), conn.ServerVersion())
	}
	sc.ServerVersion = "SSH-2.0-OpenSSH"
	cf, err := s.cli.FindByID(1)
	if err == nil {
		sc.ServerVersion = cf.ServerVersion
	}
	return sc, nil
}

func (s *Server) matchKeys(key ssh.PublicKey, keys map[string]string) error {
	if cmt, exists := keys[string(key.Marshal())]; exists {
		slog.Info("User authenticated with public key", "username", cmt, "public_key", fingerprint(key))
		return nil
	}
	slog.Error("User authentication failed with public key", "err", fingerprint(key))
	return fmt.Errorf("denied\n")
}

func appendEnv(env []string, kv string) []string {
	p := strings.SplitN(kv, "=", 2)
	k := p[0] + "="
	for i, e := range env {
		if strings.HasPrefix(e, k) {
			env[i] = kv
			return env
		}
	}
	return append(env, kv)
}

// parseDims extracts terminal dimensions (width x height) from the provided buffer.
func parseDims(b []byte) (uint32, uint32) {
	w := binary.BigEndian.Uint32(b)
	h := binary.BigEndian.Uint32(b[4:])
	return w, h
}

// SetWindowSize sets the size of the given pty.
func SetWindowSize(t pty.Pty, w, h uint32) {
	ws := &pty.Winsize{Rows: uint16(h), Cols: uint16(w)}
	_ = pty.Setsize(t, ws)
}

func generateKey(seed string) ([]byte, error) {
	var r io.Reader
	if seed == "" {
		r = rand.Reader
	} else {
		r = newDetermRand([]byte(seed))
	}
	privateKey, err := rsa.GenerateKey(r, 2048)
	if err != nil {
		return nil, err
	}
	err = privateKey.Validate()
	if err != nil {
		return nil, err
	}
	b := x509.MarshalPKCS1PrivateKey(privateKey)
	return pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: b}), nil
}

func parseKeys(b []byte) (map[string]string, error) {
	lines := bytes.Split(b, []byte("\n"))
	//parse each line
	keys := map[string]string{}
	for _, l := range lines {
		if key, cmt, _, _, err := ssh.ParseAuthorizedKey(l); err == nil {
			keys[string(key.Marshal())] = cmt
		}
	}
	//ensure we got something
	if len(keys) == 0 {
		return nil, fmt.Errorf("no keys found\n")
	}
	return keys, nil
}

func fingerprint(k ssh.PublicKey) string {
	bytesData := sha256.Sum256(k.Marshal())
	b64 := base64.StdEncoding.EncodeToString(bytesData[:])
	if strings.HasSuffix(b64, "=") {
		b64 = strings.TrimSuffix(b64, "=") + "."
	}
	return "SHA256:" + b64
}

func newDetermRand(seed []byte) io.Reader {
	const randSize = 2048
	var out []byte
	//strengthen seed
	var next = seed
	for i := 0; i < randSize; i++ {
		next, out = hash(next)
	}
	return &determRand{
		next: next,
		out:  out,
	}
}

type determRand struct {
	next, out []byte
}

func (d *determRand) Read(b []byte) (int, error) {
	l := len(b)
	//HACK: combat https://golang.org/src/crypto/rsa/rsa.go#L257
	if l == 1 {
		return 1, nil
	}
	n := 0
	for n < l {
		next, out := hash(d.next)
		n += copy(b[n:], out)
		d.next = next
	}
	return n, nil
}

func hash(input []byte) (next []byte, output []byte) {
	nextout := sha512.Sum512(input)
	return nextout[:sha512.Size/2], nextout[sha512.Size/2:]
}

// ExecuteForChannel Execute a process for the channel.
func ExecuteForChannel(shellCmd string, ch ssh.Channel) uint32 {
	var err error

	// Windows 下特殊处理命令
	var proc *exec.Cmd
	if runtime.GOOS == "windows" {
		// 使用 Command 创建命令,并正确处理参数
		proc = exec.Command("powershell", "-NoProfile", "-NonInteractive", "-Command",
			"[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; $OutputEncoding = [System.Text.Encoding]::UTF8; chcp 65001 | Out-Null; "+shellCmd)
	} else {
		proc = exec.Command("sh", "-c", shellCmd)
	}

	proc.Env = append(os.Environ(), "LANG=zh_CN.UTF-8", "LC_ALL=zh_CN.UTF-8")

	exe, err := os.Executable()
	if err != nil {
		slog.Error("get os.Executable error", "err", err)
	}
	slog.Info("os.Executable() exe:", "path", exe)

	dir := filepath.Dir(exe)
	slog.Info("exec dir info:", "path", dir)

	proc.Dir = dir
	if userInfo, err := user.Current(); err == nil {
		proc.Dir = userInfo.HomeDir
	}

	stdin, err := proc.StdinPipe()
	if err != nil {
		slog.Error("create pipe failed", "err", err)
		return 1
	}

	go func() {
		defer stdin.Close()
		_, _ = io.Copy(stdin, ch)
	}()
	proc.Stdout = ch
	proc.Stderr = ch.Stderr()

	// 执行命令
	err = proc.Start()
	if err != nil {
		slog.Error("start command failed", "err", err)
		_, _ = ch.Write([]byte(fmt.Sprintf("start command failed: %v\n", err)))
		return 1
	}

	// 等待命令完成
	err = proc.Wait()
	if err != nil {
		var exitErr *exec.ExitError
		if errors.As(err, &exitErr) {
			slog.Error("wait command failed", "exit code", exitErr.ExitCode())
			return uint32(exitErr.ExitCode())
		}
		slog.Error("exec command failed", "err", err)
		_, _ = ch.Write([]byte(fmt.Sprintf("exec command failed: %v\n", err)))
		return 1
	}
	slog.Info("exec command success")
	return 0
}

func startSshServer() {
	status := <-isStartSshd
	if status {
		slog.Info("start sshd server")
	}

	var sshdConf model.SshdConf
	conf, err := sshdConf.FindByID(1)
	if err != nil {
		slog.Error("find sshd server config failed", "err_msg", err)
		return
	}
	slog.Info("find sshd server config", "conf", conf)
	s, err := NewServer(&conf)
	if err != nil {
		slog.Error("NewServer failed", "err_msg", err)
		return
	}
	slog.Info("start sshd server")
	err = s.Start()
	if err != nil {
		slog.Error("sshd server start failed", "err_msg", err)
		return
	}
}

var isStartSshd = make(chan bool)

func InitSshServer() {
	go startSshServer()
	slog.Info("exec sshd init func")
}


================================================
FILE: gossh/app/service/sshd_user.go
================================================
package service

import (
	"gossh/app/model"
	"gossh/gin"
	"log/slog"
	"strconv"
)

func SshdUserCreate(c *gin.Context) {
	var sshdUser model.SshdUser
	if err := c.ShouldBind(&sshdUser); err != nil {
		slog.Error("UserCreate 绑定数据错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 1, "msg": "输入数据不合法"})
		return
	}

	err := sshdUser.Create(&sshdUser)
	if err != nil {
		slog.Error("创建用户错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 3, "msg": "创建用户错误"})
		return
	}
	SshdUserFindAll(c)
}

func CheckSshdUserNameExists(c *gin.Context) {
	type Name struct {
		Name string `form:"name" binding:"required,min=1,max=128" json:"name"`
	}
	var name Name
	if err := c.ShouldBind(&name); err != nil {
		slog.Error("绑定数据错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 1, "msg": "输入数据不合法"})
		return
	}

	var sshdUser model.SshdUser
	tmp, err := sshdUser.FindByName(name.Name)
	if err != nil {
		slog.Error("FindByName错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 3, "msg": "获取用户信息错误"})
		return
	}

	if tmp.ID != 0 {
		c.JSON(200, gin.H{"code": 4, "msg": "用户名已经存存在"})
		return
	}
	c.JSON(200, gin.H{"code": 0, "msg": "ok"})
	return
}

func SshdUserFindByID(c *gin.Context) {
	id, err := strconv.Atoi(c.Param("id"))
	if err != nil {
		slog.Error("获取ID错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 1, "msg": "获取ID错误"})
		return
	}

	var sshdUser model.SshdUser
	data, err := sshdUser.FindByID(uint(id))
	if err != nil {
		slog.Error("FindByID错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 3, "msg": "获取用户信息错误"})
		return
	}
	c.JSON(200, gin.H{"code": 0, "msg": "ok", "data": data})
}

func SshdUserFindAll(c *gin.Context) {
	limit, err := strconv.Atoi(c.DefaultQuery("limit", "10000"))
	if err != nil {
		slog.Error("获取limit错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 1, "msg": "获取limit错误"})
		return
	}

	offset, err := strconv.Atoi(c.DefaultQuery("offset", "0"))
	if err != nil {
		slog.Error("获取offset错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 2, "msg": "获取offset错误"})
		return
	}

	var sshdUser model.SshdUser
	data, err := sshdUser.FindAll(limit, offset)
	if err != nil {
		slog.Error("user.FindAl错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 4, "msg": "获取用户信息错误"})
		return
	}
	c.JSON(200, gin.H{"code": 0, "msg": "ok", "data": data})
}

func SshdUserUpdateById(c *gin.Context) {
	var sshdUser model.SshdUser
	if err := c.ShouldBind(&sshdUser); err != nil {
		slog.Error("获取ID错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 1, "msg": "获取ID错误"})
		return
	}

	err := sshdUser.UpdateById(sshdUser.ID, &sshdUser)
	if err != nil {
		slog.Error("UpdateById错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 5, "msg": "更新用户错误"})
		return
	}
	SshdUserFindAll(c)
}

func SshdUserDeleteById(c *gin.Context) {
	id, err := strconv.Atoi(c.Param("id"))
	if err != nil {
		slog.Error("获取ID错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 1, "msg": "获取ID错误"})
		return
	}

	var sshdUser model.SshdUser
	err = sshdUser.DeleteByID(uint(id))
	if err != nil {
		slog.Error("user.DeleteByID错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 5, "msg": "删除用户错误"})
		return
	}
	SshdUserFindAll(c)
}


================================================
FILE: gossh/app/service/sys_init.go
================================================
package service

import (
	"gossh/app/config"
	"gossh/app/model"
	"gossh/gin"
	"log/slog"
	"os/exec"
	"runtime"
)

func GetRunConf(c *gin.Context) {
	c.JSON(200, gin.H{"code": 0, "msg": "ok", "data": config.DefaultConfig})
}

func SetRunConf(c *gin.Context) {
	if config.DefaultConfig.IsInit {
		c.JSON(200, gin.H{"code": 1, "msg": "已经初始化"})
		return
	}
	var appConfig config.AppConfig
	if err := c.ShouldBind(&appConfig); err != nil {
		c.JSON(200, gin.H{"code": 1, "msg": err.Error()})
		return
	}
	err := config.RewriteConfig(appConfig)
	if err != nil {
		c.JSON(200, gin.H{"code": 1, "msg": err.Error()})
		return
	}
	c.JSON(200, gin.H{"code": 0, "msg": "ok", "data": config.DefaultConfig})
}

func GetIsInit(c *gin.Context) {
	c.JSON(200, gin.H{
		"code": 0, "msg": "ok", "data": map[string]any{
			"is_init": config.DefaultConfig.IsInit,
		},
	})
}

type InitConfig struct {
	DbConnConf
	JwtSecret     string `json:"jwt_secret"  binding:"required,min=1,max=128"`
	SessionSecret string `json:"session_secret"  binding:"required,min=1,max=128"`
	Username      string `json:"username"  binding:"required,min=1,max=63"`
	Password      string `json:"password" binding:"required,min=1,max=63"`
	SshdHost      string `json:"sshd_host"  binding:"required,min=1,max=127"`
	SshdPort      uint16 `json:"sshd_port" binding:"required,gte=1,lte=65535"`
	SshdUser      string `json:"sshd_user"  binding:"required,min=1,max=63"`
	SshdPwd       string `json:"sshd_pwd" binding:"required,min=1,max=63"`
}

func SysInit(c *gin.Context) {
	var initConf InitConfig
	if err := c.ShouldBind(&initConf); err != nil {
		c.JSON(200, gin.H{"code": 1, "msg": err.Error()})
		return
	}

	// 1.检查系统是否已经初始化
	if config.DefaultConfig.IsInit {
		c.JSON(200, gin.H{"code": 1, "msg": "系统已经初始化"})
		return
	}

	// 2.数据库连接检查
	dbConf := DbConnConf{
		DbDsn:  initConf.DbDsn,
		DbType: initConf.DbType,
	}
	err := DbConnTestCheck(dbConf)
	if err != nil {
		c.JSON(200, gin.H{"code": 1, "msg": err.Error()})
		return
	}

	// 3.数据库表迁移
	err = model.DbMigrate(initConf.DbType, initConf.DbDsn)
	if err != nil {
		c.JSON(200, gin.H{"code": 1, "msg": err.Error(), "data": "执行数据库迁移错误"})
		return
	}

	// root 用户过期时间
	dateTime, _ := model.NewDateTime("2099-12-31 00:00:00")

	// 4.创建初始化用户
	var user = model.WebUser{
		ID:       0,
		Name:     initConf.Username,
		Pwd:      initConf.Password,
		DescInfo: "管理员",
		IsAdmin:  "Y",
		IsEnable: "Y",
		IsRoot:   "Y",
		ExpiryAt: dateTime,
	}

	err = user.Create(&user)
	if err != nil {
		c.JSON(200, gin.H{"code": 3, "msg": err.Error(), "data": "初始化创建账号错误"})
		return
	}

	// 5.设置默认网络策略
	var policyConf = model.PolicyConf{
		NetPolicy: "N",
	}
	err = policyConf.Create(&policyConf)
	if err != nil {
		c.JSON(200, gin.H{"code": 3, "msg": err.Error(), "data": "初始化网络策略错误"})
		return
	}

	privateKey, err := generateKey("webssh")
	if err != nil {
		slog.Error("failed to generate private key")
		c.JSON(200, gin.H{"code": 3, "msg": err.Error(), "data": "初始化生成SSHD私钥错误"})
		return
	}

	var shell = "sh"
	if runtime.GOOS == "windows" {
		shell = "powershell"
	} else {
		sh, err := exec.LookPath("bash")
		if err == nil {
			slog.Info("init find shell is bash\n")
			shell = sh
		}
	}

	// 6.初始化sshd服务端配置
	var sshdConf = model.SshdConf{
		ID:            1,
		Name:          "init",
		Host:          initConf.SshdHost,
		Port:          initConf.SshdPort,
		Shell:         shell,
		KeyFile:       string(privateKey),
		KeySeed:       "webssh",
		KeepAlive:     60,
		LoadEnv:       "Y",
		AuthType:      "all",
		ServerVersion: "SSH-2.0-OpenSSH",
	}
	err = sshdConf.Create(&sshdConf)
	if err != nil {
		c.JSON(200, gin.H{"code": 3, "msg": err.Error(), "data": "初始化SSHD服务端配置错误"})
		return
	}

	// 7.初始化sshd服务端账号
	var sshdUser = model.SshdUser{
		ID:       1,
		Name:     initConf.SshdUser,
		Pwd:      initConf.SshdPwd,
		DescInfo: "服务器初始化账号",
		IsEnable: "Y",
		WorkDir:  "",
		ExpiryAt: dateTime,
	}
	err = sshdUser.Create(&sshdUser)
	if err != nil {
		c.JSON(200, gin.H{"code": 3, "msg": err.Error(), "data": "初始化SSHD服务端账号错误"})
		return
	}

	// 8.覆盖默认配置
	var defConf = config.DefaultConfig
	defConf.IsInit = true
	defConf.DbType = initConf.DbType
	defConf.DbDsn = initConf.DbDsn
	defConf.JwtSecret = initConf.JwtSecret
	defConf.SessionSecret = initConf.SessionSecret
	err = config.RewriteConfig(defConf)
	if err != nil {
		c.JSON(200, gin.H{"code": 2, "msg": err.Error(), "data": "写入配置错误"})
		return
	}

	// 9.创建默认连接
	var sshConf = model.SshConf{
		Uid:         1,
		Name:        "self_sshd",
		Address:     "127.0.0.1",
		User:        initConf.SshdUser,
		Pwd:         initConf.SshdPwd,
		AuthType:    "pwd",
		NetType:     "tcp4",
		CertData:    "",
		CertPwd:     "",
		Port:        initConf.SshdPort,
		FontSize:    16,
		Background:  "#000000",
		Foreground:  "#FFFFFF",
		CursorColor: "#FFFFFF",
		FontFamily:  "Courier",
		CursorStyle: "block",
		Shell:       "sh",
		PtyType:     "xterm-256color",
		InitCmd:     "",
		InitBanner:  "# https://github.com/o8oo8o/WebSSH",
	}

	err = sshConf.Create(&sshConf)
	if err != nil {
		c.JSON(200, gin.H{"code": 3, "msg": err.Error(), "data": "初始化创建默认连接错误"})
		return
	}

	isStartSshd <- true
	c.JSON(200, gin.H{"code": 0, "msg": "系统初始化完成"})
}


================================================
FILE: gossh/app/service/web_user.go
================================================
package service

import (
	"gossh/app/config"
	"gossh/app/middleware"
	"gossh/app/model"
	"gossh/app/utils"
	"gossh/gin"
	"log/slog"
	"net/http"
	"strconv"
	"time"
)

func UserCreate(c *gin.Context) {
	var user model.WebUser
	if err := c.ShouldBind(&user); err != nil {
		slog.Error("UserCreate 绑定数据错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 1, "msg": "输入数据不合法"})
		return
	}
	var err error
	user.IsRoot = "N"
	err = user.Create(&user)
	if err != nil {
		slog.Error("创建用户错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 3, "msg": "创建用户错误"})
		return
	}
	UserFindAll(c)
}

func ModifyPasswd(c *gin.Context) {
	type password struct {
		Pwd string `form:"pwd" binding:"required,min=1,max=64" json:"pwd"`
	}

	var pwd password
	if err := c.ShouldBind(&pwd); err != nil {
		slog.Error("绑定数据错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 1, "msg": "输入数据不合法"})
		return
	}

	uid := c.GetUint("uid")
	var tmp model.WebUser
	user, err := tmp.FindByID(uid)
	if err != nil {
		slog.Error("FindByID错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 2, "msg": "获取用户信息错误"})
		return
	}

	user.Pwd = pwd.Pwd
	err = user.UpdatePassword(uid, &user)
	if err != nil {
		slog.Error("UpdatePassword错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 3, "msg": "更新用户密码错误"})
		return
	}

	c.JSON(200, gin.H{"code": 0, "msg": "更新密码成功"})
}

func CheckUserNameExists(c *gin.Context) {
	type Name struct {
		Name string `form:"name" binding:"required,min=1,max=128" json:"name"`
	}
	var name Name
	if err := c.ShouldBind(&name); err != nil {
		slog.Error("绑定数据错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 1, "msg": "输入数据不合法"})
		return
	}
	var user model.WebUser

	tmp, err := user.FindByName(name.Name)
	if err != nil {
		slog.Error("FindByName错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 3, "msg": "获取用户信息错误"})
		return
	}

	if tmp.ID != 0 {
		c.JSON(200, gin.H{"code": 4, "msg": "用户名已经存存在"})
		return
	}
	c.JSON(200, gin.H{"code": 0, "msg": "ok"})
	return
}

func UserFindByID(c *gin.Context) {
	id, err := strconv.Atoi(c.Param("id"))
	if err != nil {
		slog.Error("获取ID错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 1, "msg": "获取ID错误"})
		return
	}
	var user model.WebUser
	data, err := user.FindByID(uint(id))
	if err != nil {
		slog.Error("FindByID错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 3, "msg": "获取用户信息错误"})
		return
	}
	c.JSON(200, gin.H{"code": 0, "msg": "ok", "data": data})
}

func UserFindAll(c *gin.Context) {
	limit, err := strconv.Atoi(c.DefaultQuery("limit", "10000"))
	if err != nil {
		slog.Error("获取limit错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 1, "msg": "获取limit错误"})
		return
	}

	offset, err := strconv.Atoi(c.DefaultQuery("offset", "0"))
	if err != nil {
		slog.Error("获取offset错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 2, "msg": "获取offset错误"})
		return
	}

	var user model.WebUser
	data, err := user.FindAll(limit, offset)
	if err != nil {
		slog.Error("user.FindAl错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 4, "msg": "获取用户信息错误"})
		return
	}
	c.JSON(200, gin.H{"code": 0, "msg": "ok", "data": data})
}

func UserUpdateById(c *gin.Context) {
	var user model.WebUser
	if err := c.ShouldBind(&user); err != nil {
		slog.Error("获取ID错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 1, "msg": "获取ID错误"})
		return
	}

	tmpUser, err := user.FindByID(user.ID)
	if err != nil {
		slog.Error("FindByID错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 3, "msg": "获取用户信息错误"})
		return
	}

	// 防止越权操作
	if tmpUser.IsRoot == "N" {
		user.IsRoot = "N"
	}

	if tmpUser.IsRoot == "Y" {
		c.JSON(200, gin.H{"code": 4, "msg": "内置Root用户不能更新"})
		return
	}

	err = user.UpdateById(user.ID, &user)
	if err != nil {
		slog.Error("UpdateById错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 5, "msg": "更新用户错误"})
		return
	}
	UserFindAll(c)
}

func UserDeleteById(c *gin.Context) {
	id, err := strconv.Atoi(c.Param("id"))
	if err != nil {
		slog.Error("获取ID错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 1, "msg": "获取ID错误"})
		return
	}
	var user model.WebUser
	tmpUser, err := user.FindByID(uint(id))
	if err != nil {
		slog.Error("user.FindByID错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 3, "msg": "获取用户信息错误"})
		return
	}

	// 防止越权操作
	if tmpUser.IsRoot == "Y" {
		c.JSON(200, gin.H{"code": 4, "msg": "内置Root用户不能删除"})
		return
	}

	err = user.DeleteByID(uint(id))
	if err != nil {
		slog.Error("user.DeleteByID错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 5, "msg": "删除用户错误"})
		return
	}
	UserFindAll(c)
}

func UserLogin(c *gin.Context) {
	if !config.DefaultConfig.IsInit {
		slog.Warn("system no init")
		c.JSON(401, gin.H{"code": 401, "msg": "请对系统进行初始化"})
		return
	}
	type Param struct {
		Name string `form:"name" binding:"required,min=1,max=64" json:"name"`
		Pwd  string `form:"pwd" binding:"required,min=1,max=64" json:"pwd"`
	}

	var loginAudit model.LoginAudit
	var param Param

	audit := model.LoginAudit{
		ClientIp:  c.ClientIP(),
		UserAgent: utils.TruncateString(c.Request.UserAgent(), 500),
		ErrMsg:    "请求参数错误",
		IsSuccess: "N",
		OccurAt:   model.DateTime(time.Now()),
	}
	if err := c.ShouldBind(&param); err != nil {
		audit.Name = utils.TruncateString(param.Name, 60)
		audit.Pwd = utils.TruncateString(param.Pwd, 60)
		_ = loginAudit.Create(&audit)
		slog.Error("绑定数据错误", "err_msg", err.Error())
		c.JSON(200, gin.H{"code": 1, "msg": "输入数据不合法"})
		return
	}
	audit.Name = utils.TruncateString(param.Name, 60)
	audit.Pwd = utils.TruncateString(param.Pwd, 60)

	var user model.WebUser
	u, err := user.FindByNameAndPwd(param.Name, param.Pwd)
	if err != nil {
		audit.ErrMsg = "账号密码错误"
		_ = loginAudit.Create(&audit)
		slog.Error("账号密码错误", "err_msg", err.Error())
		c.JSON(401, gin.H{"code": 2, "msg": "账号密码错误"})
		return
	}

	if u.IsEnable == "N" {
		audit.ErrMsg = "账号已禁用"
		_ = loginAudit.Create(&audit)
		c.JSON(401, gin.H{"code": 3, "msg": "账号已禁用"})
		return
	}

	if u.ExpiryAt.ToTime().Unix() < time.Now().Unix() {
		audit.ErrMsg = "账号已过期"
		_ = loginAudit.Create(&audit)
		c.JSON(401, gin.H{"code": 4, "msg": "账号已过期"})
		return
	}

	tokenString, err := middleware.GenerateToken(u.ID)
	if err != nil {
		audit.ErrMsg = "生成Token错误"
		_ = loginAudit.Create(&audit)
		c.JSON(401, gin.H{"code": 5, "msg": err.Error()})
		return
	}

	audit.Name = param.Name
	audit.Pwd = "*"
	audit.ErrMsg = "*"
	audit.IsSuccess = "Y"
	_ = loginAudit.Create(&audit)
	c.JSON(http.StatusOK, gin.H{
		"code":           0,
		"token":          tokenString,
		"msg":            "登录成功",
		"is_root":        u.IsRoot,
		"is_admin":       u.IsAdmin,
		"user_name":      u.Name,
		"user_desc":      u.DescInfo,
		"user_expiry_at": u.ExpiryAt.String(),
	})
}


================================================
FILE: gossh/app/utils/crypto.go
================================================
package utils

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"encoding/base64"
	"errors"
	"fmt"
	"io"
	"log/slog"
	"strings"
)

func AesEncrypt(orig string, key string) (string, error) {
	orig = strings.TrimSpace(orig)
	defer func() {
		if err := recover(); err != nil {
			slog.Error("AES加密错误", "err_msg", err)
		}
	}()
	if len(orig) == 0 {
		return "", nil
	}
	if len(key) != 32 {
		return "", errors.New("加密需要的key长度错误")
	}
	// 转成字节数组
	origData := []byte(orig)
	k := []byte(key)
	// 分组秘钥
	block, err := aes.NewCipher(k)
	if err != nil {
		return "", err
	}
	// 获取秘钥块的长度
	blockSize := block.BlockSize()
	//补码
	PKCS7Padding := func(ciphertext []byte, blockSize int) []byte {
		padding := blockSize - len(ciphertext)%blockSize
		padText := bytes.Repeat([]byte{byte(padding)}, padding)
		return append(ciphertext, padText...)
	}
	origData = PKCS7Padding(origData, blockSize)
	// 加密模式
	blockMode := cipher.NewCBCEncrypter(block, k[:blockSize])
	// 创建数组
	crypt := make([]byte, len(origData))
	// 加密
	blockMode.CryptBlocks(crypt, origData)
	return base64.StdEncoding.EncodeToString(crypt), nil
}

func AesDecrypt(crypt string, key string) (string, error) {
	crypt = strings.TrimSpace(crypt)
	defer func() {
		if err := recover(); err != nil {
			slog.Error("AES解密错误", "err_msg", err)
		}
	}()
	if len(crypt) == 0 {
		return "", nil
	}
	if len(crypt) < 1 || len(key) != 32 {
		return "", errors.New("解密需要的key长度错误")
	}
	// 转成字节数组
	cryptByte, _ := base64.StdEncoding.DecodeString(crypt)
	k := []byte(key)
	// 分组秘钥
	block, err := aes.NewCipher(k)
	if err != nil {
		return "", err
	}
	// 获取秘钥块的长度
	blockSize := block.BlockSize()
	// 加密模式
	blockMode := cipher.NewCBCDecrypter(block, k[:blockSize])
	// 创建数组
	orig := make([]byte, len(cryptByte))
	// 解密
	blockMode.CryptBlocks(orig, cryptByte)
	// 去补全码
	PKCS7UnPadding := func(origData []byte) []byte {
		length := len(origData)
		unPadding := int(origData[length-1])
		return origData[:(length - unPadding)]
	}
	orig = PKCS7UnPadding(orig)
	return string(orig), nil
}

func EncryptString(plaintext, key string) (string, error) {
	plaintext = strings.TrimSpace(plaintext)
	defer func() {
		if err := recover(); err != nil {
			slog.Error("AES加密错误", "err_msg", err)
		}
	}()
	if len(plaintext) == 0 {
		return "", nil
	}
	if len(key) != 32 {
		return "", errors.New("加密需要的key长度错误")
	}

	// 创建 cipher
	block, err := aes.NewCipher([]byte(key))
	if err != nil {
		return "", err
	}

	// 创建 GCM 模式
	gcm, err := cipher.NewGCM(block)
	if err != nil {
		return "", err
	}

	// 创建 nonce
	nonce := make([]byte, gcm.NonceSize())
	if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
		return "", err
	}

	// 加密
	ciphertext := gcm.Seal(nonce, nonce, []byte(plaintext), nil)

	// 返回 base64 编码的结果
	return base64.StdEncoding.EncodeToString(ciphertext), nil
}

func DecryptString(encrypted, key string) (string, error) {
	encrypted = strings.TrimSpace(encrypted)
	defer func() {
		if err := recover(); err != nil {
			slog.Error("AES解密错误", "err_msg", err)
		}
	}()
	if len(encrypted) == 0 {
		return "", nil
	}
	if len(encrypted) < 1 || len(key) != 32 {
		return "", errors.New("解密需要的key长度错误")
	}
	// 解码 base64
	ciphertext, err := base64.StdEncoding.DecodeString(encrypted)
	if err != nil {
		return "", err
	}

	// 创建 cipher
	block, err := aes.NewCipher([]byte(key))
	if err != nil {
		return "", err
	}

	// 创建 GCM 模式
	gcm, err := cipher.NewGCM(block)
	if err != nil {
		return "", err
	}

	// 提取 nonce
	if len(ciphertext) < gcm.NonceSize() {
		return "", fmt.Errorf("ciphertext too short")
	}
	nonce, ciphertext := ciphertext[:gcm.NonceSize()], ciphertext[gcm.NonceSize():]

	// 解密
	plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
	if err != nil {
		return "", err
	}

	return string(plaintext), nil
}


================================================
FILE: gossh/app/utils/utils.go
================================================
package utils

import (
	"math/rand"
	"time"
	"unicode/utf8"
)

// RandString 生成指定长度随机字符串
func RandString(length int) string {
	str := "0123456789abcdefghijklmnopqrstuvwxyz"
	data := []byte(str)
	var result []byte
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	for i := 0; i < length; i++ {
		result = append(result, data[r.Intn(len(data))])
	}
	return string(result)
}

func TruncateString(s string, length int) string {
	if utf8.RuneCountInString(s) <= length {
		return s
	}

	runes := []rune(s)
	if length < 1 {
		return ""
	}
	return string(runes[:length])
}


================================================
FILE: gossh/crypto/blowfish/block.go
================================================
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package blowfish

// getNextWord returns the next big-endian uint32 value from the byte slice
// at the given position in a circular manner, updating the position.
func getNextWord(b []byte, pos *int) uint32 {
	var w uint32
	j := *pos
	for i := 0; i < 4; i++ {
		w = w<<8 | uint32(b[j])
		j++
		if j >= len(b) {
			j = 0
		}
	}
	*pos = j
	return w
}

// ExpandKey performs a key expansion on the given *Cipher. Specifically, it
// performs the Blowfish algorithm's key schedule which sets up the *Cipher's
// pi and substitution tables for calls to Encrypt. This is used, primarily,
// by the bcrypt package to reuse the Blowfish key schedule during its
// set up. It's unlikely that you need to use this directly.
func ExpandKey(key []byte, c *Cipher) {
	j := 0
	for i := 0; i < 18; i++ {
		// Using inlined getNextWord for performance.
		var d uint32
		for k := 0; k < 4; k++ {
			d = d<<8 | uint32(key[j])
			j++
			if j >= len(key) {
				j = 0
			}
		}
		c.p[i] ^= d
	}

	var l, r uint32
	for i := 0; i < 18; i += 2 {
		l, r = encryptBlock(l, r, c)
		c.p[i], c.p[i+1] = l, r
	}

	for i := 0; i < 256; i += 2 {
		l, r = encryptBlock(l, r, c)
		c.s0[i], c.s0[i+1] = l, r
	}
	for i := 0; i < 256; i += 2 {
		l, r = encryptBlock(l, r, c)
		c.s1[i], c.s1[i+1] = l, r
	}
	for i := 0; i < 256; i += 2 {
		l, r = encryptBlock(l, r, c)
		c.s2[i], c.s2[i+1] = l, r
	}
	for i := 0; i < 256; i += 2 {
		l, r = encryptBlock(l, r, c)
		c.s3[i], c.s3[i+1] = l, r
	}
}

// This is similar to ExpandKey, but folds the salt during the key
// schedule. While ExpandKey is essentially expandKeyWithSalt with an all-zero
// salt passed in, reusing ExpandKey turns out to be a place of inefficiency
// and specializing it here is useful.
func expandKeyWithSalt(key []byte, salt []byte, c *Cipher) {
	j := 0
	for i := 0; i < 18; i++ {
		c.p[i] ^= getNextWord(key, &j)
	}

	j = 0
	var l, r uint32
	for i := 0; i < 18; i += 2 {
		l ^= getNextWord(salt, &j)
		r ^= getNextWord(salt, &j)
		l, r = encryptBlock(l, r, c)
		c.p[i], c.p[i+1] = l, r
	}

	for i := 0; i < 256; i += 2 {
		l ^= getNextWord(salt, &j)
		r ^= getNextWord(salt, &j)
		l, r = encryptBlock(l, r, c)
		c.s0[i], c.s0[i+1] = l, r
	}

	for i := 0; i < 256; i += 2 {
		l ^= getNextWord(salt, &j)
		r ^= getNextWord(salt, &j)
		l, r = encryptBlock(l, r, c)
		c.s1[i], c.s1[i+1] = l, r
	}

	for i := 0; i < 256; i += 2 {
		l ^= getNextWord(salt, &j)
		r ^= getNextWord(salt, &j)
		l, r = encryptBlock(l, r, c)
		c.s2[i], c.s2[i+1] = l, r
	}

	for i := 0; i < 256; i += 2 {
		l ^= getNextWord(salt, &j)
		r ^= getNextWord(salt, &j)
		l, r = encryptBlock(l, r, c)
		c.s3[i], c.s3[i+1] = l, r
	}
}

func encryptBlock(l, r uint32, c *Cipher) (uint32, uint32) {
	xl, xr := l, r
	xl ^= c.p[0]
	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[1]
	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[2]
	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[3]
	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[4]
	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[5]
	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[6]
	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[7]
	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[8]
	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[9]
	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[10]
	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[11]
	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[12]
	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[13]
	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[14]
	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[15]
	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[16]
	xr ^= c.p[17]
	return xr, xl
}

func decryptBlock(l, r uint32, c *Cipher) (uint32, uint32) {
	xl, xr := l, r
	xl ^= c.p[17]
	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[16]
	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[15]
	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[14]
	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[13]
	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[12]
	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[11]
	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[10]
	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[9]
	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[8]
	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[7]
	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[6]
	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[5]
	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[4]
	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[3]
	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[2]
	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[1]
	xr ^= c.p[0]
	return xr, xl
}


================================================
FILE: gossh/crypto/blowfish/cipher.go
================================================
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package blowfish implements Bruce Schneier's Blowfish encryption algorithm.
//
// Blowfish is a legacy cipher and its short block size makes it vulnerable to
// birthday bound attacks (see https://sweet32.info). It should only be used
// where compatibility with legacy systems, not security, is the goal.
//
// Deprecated: any new system should use AES (from crypto/aes, if necessary in
// an AEAD mode like crypto/cipher.NewGCM) or XChaCha20-Poly1305 (from
// golang.org/x/crypto/chacha20poly1305).
package blowfish // import "golang.org/x/crypto/blowfish"

// The code is a port of Bruce Schneier's C implementation.
// See https://www.schneier.com/blowfish.html.

import "strconv"

// The Blowfish block size in bytes.
const BlockSize = 8

// A Cipher is an instance of Blowfish encryption using a particular key.
type Cipher struct {
	p              [18]uint32
	s0, s1, s2, s3 [256]uint32
}

type KeySizeError int

func (k KeySizeError) Error() string {
	return "crypto/blowfish: invalid key size " + strconv.Itoa(int(k))
}

// NewCipher creates and returns a Cipher.
// The key argument should be the Blowfish key, from 1 to 56 bytes.
func NewCipher(key []byte) (*Cipher, error) {
	var result Cipher
	if k := len(key); k < 1 || k > 56 {
		return nil, KeySizeError(k)
	}
	initCipher(&result)
	ExpandKey(key, &result)
	return &result, nil
}

// NewSaltedCipher creates a returns a Cipher that folds a salt into its key
// schedule. For most purposes, NewCipher, instead of NewSaltedCipher, is
// sufficient and desirable. For bcrypt compatibility, the key can be over 56
// bytes.
func NewSaltedCipher(key, salt []byte) (*Cipher, error) {
	if len(salt) == 0 {
		return NewCipher(key)
	}
	var result Cipher
	if k := len(key); k < 1 {
		return nil, KeySizeError(k)
	}
	initCipher(&result)
	expandKeyWithSalt(key, salt, &result)
	return &result, nil
}

// BlockSize returns the Blowfish block size, 8 bytes.
// It is necessary to satisfy the Block interface in the
// package "crypto/cipher".
func (c *Cipher) BlockSize() int { return BlockSize }

// Encrypt encrypts the 8-byte buffer src using the key k
// and stores the result in dst.
// Note that for amounts of data larger than a block,
// it is not safe to just call Encrypt on successive blocks;
// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go).
func (c *Cipher) Encrypt(dst, src []byte) {
	l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
	r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
	l, r = encryptBlock(l, r, c)
	dst[0], dst[1], dst[2], dst[3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l)
	dst[4], dst[5], dst[6], dst[7] = byte(r>>24), byte(r>>16), byte(r>>8), byte(r)
}

// Decrypt decrypts the 8-byte buffer src using the key k
// and stores the result in dst.
func (c *Cipher) Decrypt(dst, src []byte) {
	l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
	r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
	l, r = decryptBlock(l, r, c)
	dst[0], dst[1], dst[2], dst[3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l)
	dst[4], dst[5], dst[6], dst[7] = byte(r>>24), byte(r>>16), byte(r>>8), byte(r)
}

func initCipher(c *Cipher) {
	copy(c.p[0:], p[0:])
	copy(c.s0[0:], s0[0:])
	copy(c.s1[0:], s1[0:])
	copy(c.s2[0:], s2[0:])
	copy(c.s3[0:], s3[0:])
}


================================================
FILE: gossh/crypto/blowfish/const.go
================================================
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// The startup permutation array and substitution boxes.
// They are the hexadecimal digits of PI; see:
// https://www.schneier.com/code/constants.txt.

package blowfish

var s0 = [256]uint32{
	0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96,
	0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
	0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658,
	0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
	0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e,
	0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
	0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6,
	0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
	0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c,
	0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
	0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1,
	0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
	0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a,
	0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
	0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176,
	0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
	0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706,
	0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
	0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b,
	0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
	0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c,
	0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
	0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a,
	0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
	0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760,
	0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
	0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8,
	0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
	0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33,
	0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
	0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0,
	0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
	0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777,
	0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
	0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705,
	0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
	0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e,
	0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
	0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9,
	0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
	0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f,
	0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
	0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a,
}

var s1 = [256]uint32{
	0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d,
	0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
	0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65,
	0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
	0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9,
	0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
	0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d,
	0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
	0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc,
	0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
	0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908,
	0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
	0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124,
	0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
	0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908,
	0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
	0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b,
	0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
	0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa,
	0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
	0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d,
	0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
	0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5,
	0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
	0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96,
	0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
	0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca,
	0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
	0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77,
	0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
	0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054,
	0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
	0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea,
	0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
	0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646,
	0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
	0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea,
	0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
	0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e,
	0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
	0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd,
	0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
	0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7,
}

var s2 = [256]uint32{
	0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7,
	0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
	0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af,
	0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
	0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4,
	0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
	0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec,
	0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
	0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332,
	0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
	0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58,
	0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
	0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22,
	0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
	0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60,
	0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
	0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99,
	0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
	0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74,
	0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
	0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3,
	0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
	0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979,
	0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
	0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa,
	0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
	0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086,
	0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
	0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24,
	0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
	0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84,
	0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
	0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09,
	0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
	0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe,
	0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
	0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0,
	0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
	0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188,
	0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
	0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8,
	0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
	0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0,
}

var s3 = [256]uint32{
	0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742,
	0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
	0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79,
	0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
	0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a,
	0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
	0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1,
	0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
	0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797,
	0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
	0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6,
	0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
	0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba,
	0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
	0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5,
	0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
	0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce,
	0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
	0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd,
	0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
	0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb,
	0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
	0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc,
	0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
	0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc,
	0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
	0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a,
	0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
	0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a,
	0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
	0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b,
	0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
	0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e,
	0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
	0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623,
	0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
	0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a,
	0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
	0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3,
	0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
	0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c,
	0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
	0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6,
}

var p = [18]uint32{
	0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
	0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
	0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b,
}


================================================
FILE: gossh/crypto/chacha20/chacha_arm64.go
================================================
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:build gc && !purego

package chacha20

const bufSize = 256

//go:noescape
func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32)

func (c *Cipher) xorKeyStreamBlocks(dst, src []byte) {
	xorKeyStreamVX(dst, src, &c.key, &c.nonce, &c.counter)
}


================================================
FILE: gossh/crypto/chacha20/chacha_arm64.s
================================================
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:build gc && !purego

#include "textflag.h"

#define NUM_ROUNDS 10

// func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32)
TEXT ·xorKeyStreamVX(SB), NOSPLIT, $0
	MOVD	dst+0(FP), R1
	MOVD	src+24(FP), R2
	MOVD	src_len+32(FP), R3
	MOVD	key+48(FP), R4
	MOVD	nonce+56(FP), R6
	MOVD	counter+64(FP), R7

	MOVD	$·constants(SB), R10
	MOVD	$·incRotMatrix(SB), R11

	MOVW	(R7), R20

	AND	$~255, R3, R13
	ADD	R2, R13, R12 // R12 for block end
	AND	$255, R3, R13
loop:
	MOVD	$NUM_ROUNDS, R21
	VLD1	(R11), [V30.S4, V31.S4]

	// load contants
	// VLD4R (R10), [V0.S4, V1.S4, V2.S4, V3.S4]
	WORD	$0x4D60E940

	// load keys
	// VLD4R 16(R4), [V4.S4, V5.S4, V6.S4, V7.S4]
	WORD	$0x4DFFE884
	// VLD4R 16(R4), [V8.S4, V9.S4, V10.S4, V11.S4]
	WORD	$0x4DFFE888
	SUB	$32, R4

	// load counter + nonce
	// VLD1R (R7), [V12.S4]
	WORD	$0x4D40C8EC

	// VLD3R (R6), [V13.S4, V14.S4, V15.S4]
	WORD	$0x4D40E8CD

	// update counter
	VADD	V30.S4, V12.S4, V12.S4

chacha:
	// V0..V3 += V4..V7
	// V12..V15 <<<= ((V12..V15 XOR V0..V3), 16)
	VADD	V0.S4, V4.S4, V0.S4
	VADD	V1.S4, V5.S4, V1.S4
	VADD	V2.S4, V6.S4, V2.S4
	VADD	V3.S4, V7.S4, V3.S4
	VEOR	V12.B16, V0.B16, V12.B16
	VEOR	V13.B16, V1.B16, V13.B16
	VEOR	V14.B16, V2.B16, V14.B16
	VEOR	V15.B16, V3.B16, V15.B16
	VREV32	V12.H8, V12.H8
	VREV32	V13.H8, V13.H8
	VREV32	V14.H8, V14.H8
	VREV32	V15.H8, V15.H8
	// V8..V11 += V12..V15
	// V4..V7 <<<= ((V4..V7 XOR V8..V11), 12)
	VADD	V8.S4, V12.S4, V8.S4
	VADD	V9.S4, V13.S4, V9.S4
	VADD	V10.S4, V14.S4, V10.S4
	VADD	V11.S4, V15.S4, V11.S4
	VEOR	V8.B16, V4.B16, V16.B16
	VEOR	V9.B16, V5.B16, V17.B16
	VEOR	V10.B16, V6.B16, V18.B16
	VEOR	V11.B16, V7.B16, V19.B16
	VSHL	$12, V16.S4, V4.S4
	VSHL	$12, V17.S4, V5.S4
	VSHL	$12, V18.S4, V6.S4
	VSHL	$12, V19.S4, V7.S4
	VSRI	$20, V16.S4, V4.S4
	VSRI	$20, V17.S4, V5.S4
	VSRI	$20, V18.S4, V6.S4
	VSRI	$20, V19.S4, V7.S4

	// V0..V3 += V4..V7
	// V12..V15 <<<= ((V12..V15 XOR V0..V3), 8)
	VADD	V0.S4, V4.S4, V0.S4
	VADD	V1.S4, V5.S4, V1.S4
	VADD	V2.S4, V6.S4, V2.S4
	VADD	V3.S4, V7.S4, V3.S4
	VEOR	V12.B16, V0.B16, V12.B16
	VEOR	V13.B16, V1.B16, V13.B16
	VEOR	V14.B16, V2.B16, V14.B16
	VEOR	V15.B16, V3.B16, V15.B16
	VTBL	V31.B16, [V12.B16], V12.B16
	VTBL	V31.B16, [V13.B16], V13.B16
	VTBL	V31.B16, [V14.B16], V14.B16
	VTBL	V31.B16, [V15.B16], V15.B16

	// V8..V11 += V12..V15
	// V4..V7 <<<= ((V4..V7 XOR V8..V11), 7)
	VADD	V12.S4, V8.S4, V8.S4
	VADD	V13.S4, V9.S4, V9.S4
	VADD	V14.S4, V10.S4, V10.S4
	VADD	V15.S4, V11.S4, V11.S4
	VEOR	V8.B16, V4.B16, V16.B16
	VEOR	V9.B16, V5.B16, V17.B16
	VEOR	V10.B16, V6.B16, V18.B16
	VEOR	V11.B16, V7.B16, V19.B16
	VSHL	$7, V16.S4, V4.S4
	VSHL	$7, V17.S4, V5.S4
	VSHL	$7, V18.S4, V6.S4
	VSHL	$7, V19.S4, V7.S4
	VSRI	$25, V16.S4, V4.S4
	VSRI	$25, V17.S4, V5.S4
	VSRI	$25, V18.S4, V6.S4
	VSRI	$25, V19.S4, V7.S4

	// V0..V3 += V5..V7, V4
	// V15,V12-V14 <<<= ((V15,V12-V14 XOR V0..V3), 16)
	VADD	V0.S4, V5.S4, V0.S4
	VADD	V1.S4, V6.S4, V1.S4
	VADD	V2.S4, V7.S4, V2.S4
	VADD	V3.S4, V4.S4, V3.S4
	VEOR	V15.B16, V0.B16, V15.B16
	VEOR	V12.B16, V1.B16, V12.B16
	VEOR	V13.B16, V2.B16, V13.B16
	VEOR	V14.B16, V3.B16, V14.B16
	VREV32	V12.H8, V12.H8
	VREV32	V13.H8, V13.H8
	VREV32	V14.H8, V14.H8
	VREV32	V15.H8, V15.H8

	// V10 += V15; V5 <<<= ((V10 XOR V5), 12)
	// ...
	VADD	V15.S4, V10.S4, V10.S4
	VADD	V12.S4, V11.S4, V11.S4
	VADD	V13.S4, V8.S4, V8.S4
	VADD	V14.S4, V9.S4, V9.S4
	VEOR	V10.B16, V5.B16, V16.B16
	VEOR	V11.B16, V6.B16, V17.B16
	VEOR	V8.B16, V7.B16, V18.B16
	VEOR	V9.B16, V4.B16, V19.B16
	VSHL	$12, V16.S4, V5.S4
	VSHL	$12, V17.S4, V6.S4
	VSHL	$12, V18.S4, V7.S4
	VSHL	$12, V19.S4, V4.S4
	VSRI	$20, V16.S4, V5.S4
	VSRI	$20, V17.S4, V6.S4
	VSRI	$20, V18.S4, V7.S4
	VSRI	$20, V19.S4, V4.S4

	// V0 += V5; V15 <<<= ((V0 XOR V15), 8)
	// ...
	VADD	V5.S4, V0.S4, V0.S4
	VADD	V6.S4, V1.S4, V1.S4
	VADD	V7.S4, V2.S4, V2.S4
	VADD	V4.S4, V3.S4, V3.S4
	VEOR	V0.B16, V15.B16, V15.B16
	VEOR	V1.B16, V12.B16, V12.B16
	VEOR	V2.B16, V13.B16, V13.B16
	VEOR	V3.B16, V14.B16, V14.B16
	VTBL	V31.B16, [V12.B16], V12.B16
	VTBL	V31.B16, [V13.B16], V13.B16
	VTBL	V31.B16, [V14.B16], V14.B16
	VTBL	V31.B16, [V15.B16], V15.B16

	// V10 += V15; V5 <<<= ((V10 XOR V5), 7)
	// ...
	VADD	V15.S4, V10.S4, V10.S4
	VADD	V12.S4, V11.S4, V11.S4
	VADD	V13.S4, V8.S4, V8.S4
	VADD	V14.S4, V9.S4, V9.S4
	VEOR	V10.B16, V5.B16, V16.B16
	VEOR	V11.B16, V6.B16, V17.B16
	VEOR	V8.B16, V7.B16, V18.B16
	VEOR	V9.B16, V4.B16, V19.B16
	VSHL	$7, V16.S4, V5.S4
	VSHL	$7, V17.S4, V6.S4
	VSHL	$7, V18.S4, V7.S4
	VSHL	$7, V19.S4, V4.S4
	VSRI	$25, V16.S4, V5.S4
	VSRI	$25, V17.S4, V6.S4
	VSRI	$25, V18.S4, V7.S4
	VSRI	$25, V19.S4, V4.S4

	SUB	$1, R21
	CBNZ	R21, chacha

	// VLD4R (R10), [V16.S4, V17.S4, V18.S4, V19.S4]
	WORD	$0x4D60E950

	// VLD4R 16(R4), [V20.S4, V21.S4, V22.S4, V23.S4]
	WORD	$0x4DFFE894
	VADD	V30.S4, V12.S4, V12.S4
	VADD	V16.S4, V0.S4, V0.S4
	VADD	V17.S4, V1.S4, V1.S4
	VADD	V18.S4, V2.S4, V2.S4
	VADD	V19.S4, V3.S4, V3.S4
	// VLD4R 16(R4), [V24.S4, V25.S4, V26.S4, V27.S4]
	WORD	$0x4DFFE898
	// restore R4
	SUB	$32, R4

	// load counter + nonce
	// VLD1R (R7), [V28.S4]
	WORD	$0x4D40C8FC
	// VLD3R (R6), [V29.S4, V30.S4, V31.S4]
	WORD	$0x4D40E8DD

	VADD	V20.S4, V4.S4, V4.S4
	VADD	V21.S4, V5.S4, V5.S4
	VADD	V22.S4, V6.S4, V6.S4
	VADD	V23.S4, V7.S4, V7.S4
	VADD	V24.S4, V8.S4, V8.S4
	VADD	V25.S4, V9.S4, V9.S4
	VADD	V26.S4, V10.S4, V10.S4
	VADD	V27.S4, V11.S4, V11.S4
	VADD	V28.S4, V12.S4, V12.S4
	VADD	V29.S4, V13.S4, V13.S4
	VADD	V30.S4, V14.S4, V14.S4
	VADD	V31.S4, V15.S4, V15.S4

	VZIP1	V1.S4, V0.S4, V16.S4
	VZIP2	V1.S4, V0.S4, V17.S4
	VZIP1	V3.S4, V2.S4, V18.S4
	VZIP2	V3.S4, V2.S4, V19.S4
	VZIP1	V5.S4, V4.S4, V20.S4
	VZIP2	V5.S4, V4.S4, V21.S4
	VZIP1	V7.S4, V6.S4, V22.S4
	VZIP2	V7.S4, V6.S4, V23.S4
	VZIP1	V9.S4, V8.S4, V24.S4
	VZIP2	V9.S4, V8.S4, V25.S4
	VZIP1	V11.S4, V10.S4, V26.S4
	VZIP2	V11.S4, V10.S4, V27.S4
	VZIP1	V13.S4, V12.S4, V28.S4
	VZIP2	V13.S4, V12.S4, V29.S4
	VZIP1	V15.S4, V14.S4, V30.S4
	VZIP2	V15.S4, V14.S4, V31.S4
	VZIP1	V18.D2, V16.D2, V0.D2
	VZIP2	V18.D2, V16.D2, V4.D2
	VZIP1	V19.D2, V17.D2, V8.D2
	VZIP2	V19.D2, V17.D2, V12.D2
	VLD1.P	64(R2), [V16.B16, V17.B16, V18.B16, V19.B16]

	VZIP1	V22.D2, V20.D2, V1.D2
	VZIP2	V22.D2, V20.D2, V5.D2
	VZIP1	V23.D2, V21.D2, V9.D2
	VZIP2	V23.D2, V21.D2, V13.D2
	VLD1.P	64(R2), [V20.B16, V21.B16, V22.B16, V23.B16]
	VZIP1	V26.D2, V24.D2, V2.D2
	VZIP2	V26.D2, V24.D2, V6.D2
	VZIP1	V27.D2, V25.D2, V10.D2
	VZIP2	V27.D2, V25.D2, V14.D2
	VLD1.P	64(R2), [V24.B16, V25.B16, V26.B16, V27.B16]
	VZIP1	V30.D2, V28.D2, V3.D2
	VZIP2	V30.D2, V28.D2, V7.D2
	VZIP1	V31.D2, V29.D2, V11.D2
	VZIP2	V31.D2, V29.D2, V15.D2
	VLD1.P	64(R2), [V28.B16, V29.B16, V30.B16, V31.B16]
	VEOR	V0.B16, V16.B16, V16.B16
	VEOR	V1.B16, V17.B16, V17.B16
	VEOR	V2.B16, V18.B16, V18.B16
	VEOR	V3.B16, V19.B16, V19.B16
	VST1.P	[V16.B16, V17.B16, V18.B16, V19.B16], 64(R1)
	VEOR	V4.B16, V20.B16, V20.B16
	VEOR	V5.B16, V21.B16, V21.B16
	VEOR	V6.B16, V22.B16, V22.B16
	VEOR	V7.B16, V23.B16, V23.B16
	VST1.P	[V20.B16, V21.B16, V22.B16, V23.B16], 64(R1)
	VEOR	V8.B16, V24.B16, V24.B16
	VEOR	V9.B16, V25.B16, V25.B16
	VEOR	V10.B16, V26.B16, V26.B16
	VEOR	V11.B16, V27.B16, V27.B16
	VST1.P	[V24.B16, V25.B16, V26.B16, V27.B16], 64(R1)
	VEOR	V12.B16, V28.B16, V28.B16
	VEOR	V13.B16, V29.B16, V29.B16
	VEOR	V14.B16, V30.B16, V30.B16
	VEOR	V15.B16, V31.B16, V31.B16
	VST1.P	[V28.B16, V29.B16, V30.B16, V31.B16], 64(R1)

	ADD	$4, R20
	MOVW	R20, (R7) // update counter

	CMP	R2, R12
	BGT	loop

	RET


DATA	·constants+0x00(SB)/4, $0x61707865
DATA	·constants+0x04(SB)/4, $0x3320646e
DATA	·constants+0x08(SB)/4, $0x79622d32
DATA	·constants+0x0c(SB)/4, $0x6b206574
GLOBL	·constants(SB), NOPTR|RODATA, $32

DATA	·incRotMatrix+0x00(SB)/4, $0x00000000
DATA	·incRotMatrix+0x04(SB)/4, $0x00000001
DATA	·incRotMatrix+0x08(SB)/4, $0x00000002
DATA	·incRotMatrix+0x0c(SB)/4, $0x00000003
DATA	·incRotMatrix+0x10(SB)/4, $0x02010003
DATA	·incRotMatrix+0x14(SB)/4, $0x06050407
DATA	·incRotMatrix+0x18(SB)/4, $0x0A09080B
DATA	·incRotMatrix+0x1c(SB)/4, $0x0E0D0C0F
GLOBL	·incRotMatrix(SB), NOPTR|RODATA, $32


================================================
FILE: gossh/crypto/chacha20/chacha_generic.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package chacha20 implements the ChaCha20 and XChaCha20 encryption algorithms
// as specified in RFC 8439 and draft-irtf-cfrg-xchacha-01.
package chacha20

import (
	"crypto/cipher"
	"encoding/binary"
	"errors"
	"math/bits"

	"gossh/crypto/internal/alias"
)

const (
	// KeySize is the size of the key used by this cipher, in bytes.
	KeySize = 32

	// NonceSize is the size of the nonce used with the standard variant of this
	// cipher, in bytes.
	//
	// Note that this is too short to be safely generated at random if the same
	// key is reused more than 2³² times.
	NonceSize = 12

	// NonceSizeX is the size of the nonce used with the XChaCha20 variant of
	// this cipher, in bytes.
	NonceSizeX = 24
)

// Cipher is a stateful instance of ChaCha20 or XChaCha20 using a particular key
// and nonce. A *Cipher implements the cipher.Stream interface.
type Cipher struct {
	// The ChaCha20 state is 16 words: 4 constant, 8 of key, 1 of counter
	// (incremented after each block), and 3 of nonce.
	key     [8]uint32
	counter uint32
	nonce   [3]uint32

	// The last len bytes of buf are leftover key stream bytes from the previous
	// XORKeyStream invocation. The size of buf depends on how many blocks are
	// computed at a time by xorKeyStreamBlocks.
	buf [bufSize]byte
	len int

	// overflow is set when the counter overflowed, no more blocks can be
	// generated, and the next XORKeyStream call should panic.
	overflow bool

	// The counter-independent results of the first round are cached after they
	// are computed the first time.
	precompDone      bool
	p1, p5, p9, p13  uint32
	p2, p6, p10, p14 uint32
	p3, p7, p11, p15 uint32
}

var _ cipher.Stream = (*Cipher)(nil)

// NewUnauthenticatedCipher creates a new ChaCha20 stream cipher with the given
// 32 bytes key and a 12 or 24 bytes nonce. If a nonce of 24 bytes is provided,
// the XChaCha20 construction will be used. It returns an error if key or nonce
// have any other length.
//
// Note that ChaCha20, like all stream ciphers, is not authenticated and allows
// attackers to silently tamper with the plaintext. For this reason, it is more
// appropriate as a building block than as a standalone encryption mechanism.
// Instead, consider using package golang.org/x/crypto/chacha20poly1305.
func NewUnauthenticatedCipher(key, nonce []byte) (*Cipher, error) {
	// This function is split into a wrapper so that the Cipher allocation will
	// be inlined, and depending on how the caller uses the return value, won't
	// escape to the heap.
	c := &Cipher{}
	return newUnauthenticatedCipher(c, key, nonce)
}

func newUnauthenticatedCipher(c *Cipher, key, nonce []byte) (*Cipher, error) {
	if len(key) != KeySize {
		return nil, errors.New("chacha20: wrong key size")
	}
	if len(nonce) == NonceSizeX {
		// XChaCha20 uses the ChaCha20 core to mix 16 bytes of the nonce into a
		// derived key, allowing it to operate on a nonce of 24 bytes. See
		// draft-irtf-cfrg-xchacha-01, Section 2.3.
		key, _ = HChaCha20(key, nonce[0:16])
		cNonce := make([]byte, NonceSize)
		copy(cNonce[4:12], nonce[16:24])
		nonce = cNonce
	} else if len(nonce) != NonceSize {
		return nil, errors.New("chacha20: wrong nonce size")
	}

	key, nonce = key[:KeySize], nonce[:NonceSize] // bounds check elimination hint
	c.key = [8]uint32{
		binary.LittleEndian.Uint32(key[0:4]),
		binary.LittleEndian.Uint32(key[4:8]),
		binary.LittleEndian.Uint32(key[8:12]),
		binary.LittleEndian.Uint32(key[12:16]),
		binary.LittleEndian.Uint32(key[16:20]),
		binary.LittleEndian.Uint32(key[20:24]),
		binary.LittleEndian.Uint32(key[24:28]),
		binary.LittleEndian.Uint32(key[28:32]),
	}
	c.nonce = [3]uint32{
		binary.LittleEndian.Uint32(nonce[0:4]),
		binary.LittleEndian.Uint32(nonce[4:8]),
		binary.LittleEndian.Uint32(nonce[8:12]),
	}
	return c, nil
}

// The constant first 4 words of the ChaCha20 state.
const (
	j0 uint32 = 0x61707865 // expa
	j1 uint32 = 0x3320646e // nd 3
	j2 uint32 = 0x79622d32 // 2-by
	j3 uint32 = 0x6b206574 // te k
)

const blockSize = 64

// quarterRound is the core of ChaCha20. It shuffles the bits of 4 state words.
// It's executed 4 times for each of the 20 ChaCha20 rounds, operating on all 16
// words each round, in columnar or diagonal groups of 4 at a time.
func quarterRound(a, b, c, d uint32) (uint32, uint32, uint32, uint32) {
	a += b
	d ^= a
	d = bits.RotateLeft32(d, 16)
	c += d
	b ^= c
	b = bits.RotateLeft32(b, 12)
	a += b
	d ^= a
	d = bits.RotateLeft32(d, 8)
	c += d
	b ^= c
	b = bits.RotateLeft32(b, 7)
	return a, b, c, d
}

// SetCounter sets the Cipher counter. The next invocation of XORKeyStream will
// behave as if (64 * counter) bytes had been encrypted so far.
//
// To prevent accidental counter reuse, SetCounter panics if counter is less
// than the current value.
//
// Note that the execution time of XORKeyStream is not independent of the
// counter value.
func (s *Cipher) SetCounter(counter uint32) {
	// Internally, s may buffer multiple blocks, which complicates this
	// implementation slightly. When checking whether the counter has rolled
	// back, we must use both s.counter and s.len to determine how many blocks
	// we have already output.
	outputCounter := s.counter - uint32(s.len)/blockSize
	if s.overflow || counter < outputCounter {
		panic("chacha20: SetCounter attempted to rollback counter")
	}

	// In the general case, we set the new counter value and reset s.len to 0,
	// causing the next call to XORKeyStream to refill the buffer. However, if
	// we're advancing within the existing buffer, we can save work by simply
	// setting s.len.
	if counter < s.counter {
		s.len = int(s.counter-counter) * blockSize
	} else {
		s.counter = counter
		s.len = 0
	}
}

// XORKeyStream XORs each byte in the given slice with a byte from the
// cipher's key stream. Dst and src must overlap entirely or not at all.
//
// If len(dst) < len(src), XORKeyStream will panic. It is acceptable
// to pass a dst bigger than src, and in that case, XORKeyStream will
// only update dst[:len(src)] and will not touch the rest of dst.
//
// Multiple calls to XORKeyStream behave as if the concatenation of
// the src buffers was passed in a single run. That is, Cipher
// maintains state and does not reset at each XORKeyStream call.
func (s *Cipher) XORKeyStream(dst, src []byte) {
	if len(src) == 0 {
		return
	}
	if len(dst) < len(src) {
		panic("chacha20: output smaller than input")
	}
	dst = dst[:len(src)]
	if alias.InexactOverlap(dst, src) {
		panic("chacha20: invalid buffer overlap")
	}

	// First, drain any remaining key stream from a previous XORKeyStream.
	if s.len != 0 {
		keyStream := s.buf[bufSize-s.len:]
		if len(src) < len(keyStream) {
			keyStream = keyStream[:len(src)]
		}
		_ = src[len(keyStream)-1] // bounds check elimination hint
		for i, b := range keyStream {
			dst[i] = src[i] ^ b
		}
		s.len -= len(keyStream)
		dst, src = dst[len(keyStream):], src[len(keyStream):]
	}
	if len(src) == 0 {
		return
	}

	// If we'd need to let the counter overflow and keep generating output,
	// panic immediately. If instead we'd only reach the last block, remember
	// not to generate any more output after the buffer is drained.
	numBlocks := (uint64(len(src)) + blockSize - 1) / blockSize
	if s.overflow || uint64(s.counter)+numBlocks > 1<<32 {
		panic("chacha20: counter overflow")
	} else if uint64(s.counter)+numBlocks == 1<<32 {
		s.overflow = true
	}

	// xorKeyStreamBlocks implementations expect input lengths that are a
	// multiple of bufSize. Platform-specific ones process multiple blocks at a
	// time, so have bufSizes that are a multiple of blockSize.

	full := len(src) - len(src)%bufSize
	if full > 0 {
		s.xorKeyStreamBlocks(dst[:full], src[:full])
	}
	dst, src = dst[full:], src[full:]

	// If using a multi-block xorKeyStreamBlocks would overflow, use the generic
	// one that does one block at a time.
	const blocksPerBuf = bufSize / blockSize
	if uint64(s.counter)+blocksPerBuf > 1<<32 {
		s.buf = [bufSize]byte{}
		numBlocks := (len(src) + blockSize - 1) / blockSize
		buf := s.buf[bufSize-numBlocks*blockSize:]
		copy(buf, src)
		s.xorKeyStreamBlocksGeneric(buf, buf)
		s.len = len(buf) - copy(dst, buf)
		return
	}

	// If we have a partial (multi-)block, pad it for xorKeyStreamBlocks, and
	// keep the leftover keystream for the next XORKeyStream invocation.
	if len(src) > 0 {
		s.buf = [bufSize]byte{}
		copy(s.buf[:], src)
		s.xorKeyStreamBlocks(s.buf[:], s.buf[:])
		s.len = bufSize - copy(dst, s.buf[:])
	}
}

func (s *Cipher) xorKeyStreamBlocksGeneric(dst, src []byte) {
	if len(dst) != len(src) || len(dst)%blockSize != 0 {
		panic("chacha20: internal error: wrong dst and/or src length")
	}

	// To generate each block of key stream, the initial cipher state
	// (represented below) is passed through 20 rounds of shuffling,
	// alternatively applying quarterRounds by columns (like 1, 5, 9, 13)
	// or by diagonals (like 1, 6, 11, 12).
	//
	//      0:cccccccc   1:cccccccc   2:cccccccc   3:cccccccc
	//      4:kkkkkkkk   5:kkkkkkkk   6:kkkkkkkk   7:kkkkkkkk
	//      8:kkkkkkkk   9:kkkkkkkk  10:kkkkkkkk  11:kkkkkkkk
	//     12:bbbbbbbb  13:nnnnnnnn  14:nnnnnnnn  15:nnnnnnnn
	//
	//            c=constant k=key b=blockcount n=nonce
	var (
		c0, c1, c2, c3   = j0, j1, j2, j3
		c4, c5, c6, c7   = s.key[0], s.key[1], s.key[2], s.key[3]
		c8, c9, c10, c11 = s.key[4], s.key[5], s.key[6], s.key[7]
		_, c13, c14, c15 = s.counter, s.nonce[0], s.nonce[1], s.nonce[2]
	)

	// Three quarters of the first round don't depend on the counter, so we can
	// calculate them here, and reuse them for multiple blocks in the loop, and
	// for future XORKeyStream invocations.
	if !s.precompDone {
		s.p1, s.p5, s.p9, s.p13 = quarterRound(c1, c5, c9, c13)
		s.p2, s.p6, s.p10, s.p14 = quarterRound(c2, c6, c10, c14)
		s.p3, s.p7, s.p11, s.p15 = quarterRound(c3, c7, c11, c15)
		s.precompDone = true
	}

	// A condition of len(src) > 0 would be sufficient, but this also
	// acts as a bounds check elimination hint.
	for len(src) >= 64 && len(dst) >= 64 {
		// The remainder of the first column round.
		fcr0, fcr4, fcr8, fcr12 := quarterRound(c0, c4, c8, s.counter)

		// The second diagonal round.
		x0, x5, x10, x15 := quarterRound(fcr0, s.p5, s.p10, s.p15)
		x1, x6, x11, x12 := quarterRound(s.p1, s.p6, s.p11, fcr12)
		x2, x7, x8, x13 := quarterRound(s.p2, s.p7, fcr8, s.p13)
		x3, x4, x9, x14 := quarterRound(s.p3, fcr4, s.p9, s.p14)

		// The remaining 18 rounds.
		for i := 0; i < 9; i++ {
			// Column round.
			x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12)
			x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13)
			x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14)
			x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15)

			// Diagonal round.
			x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15)
			x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12)
			x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13)
			x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14)
		}

		// Add back the initial state to generate the key stream, then
		// XOR the key stream with the source and write out the result.
		addXor(dst[0:4], src[0:4], x0, c0)
		addXor(dst[4:8], src[4:8], x1, c1)
		addXor(dst[8:12], src[8:12], x2, c2)
		addXor(dst[12:16], src[12:16], x3, c3)
		addXor(dst[16:20], src[16:20], x4, c4)
		addXor(dst[20:24], src[20:24], x5, c5)
		addXor(dst[24:28], src[24:28], x6, c6)
		addXor(dst[28:32], src[28:32], x7, c7)
		addXor(dst[32:36], src[32:36], x8, c8)
		addXor(dst[36:40], src[36:40], x9, c9)
		addXor(dst[40:44], src[40:44], x10, c10)
		addXor(dst[44:48], src[44:48], x11, c11)
		addXor(dst[48:52], src[48:52], x12, s.counter)
		addXor(dst[52:56], src[52:56], x13, c13)
		addXor(dst[56:60], src[56:60], x14, c14)
		addXor(dst[60:64], src[60:64], x15, c15)

		s.counter += 1

		src, dst = src[blockSize:], dst[blockSize:]
	}
}

// HChaCha20 uses the ChaCha20 core to generate a derived key from a 32 bytes
// key and a 16 bytes nonce. It returns an error if key or nonce have any other
// length. It is used as part of the XChaCha20 construction.
func HChaCha20(key, nonce []byte) ([]byte, error) {
	// This function is split into a wrapper so that the slice allocation will
	// be inlined, and depending on how the caller uses the return value, won't
	// escape to the heap.
	out := make([]byte, 32)
	return hChaCha20(out, key, nonce)
}

func hChaCha20(out, key, nonce []byte) ([]byte, error) {
	if len(key) != KeySize {
		return nil, errors.New("chacha20: wrong HChaCha20 key size")
	}
	if len(nonce) != 16 {
		return nil, errors.New("chacha20: wrong HChaCha20 nonce size")
	}

	x0, x1, x2, x3 := j0, j1, j2, j3
	x4 := binary.LittleEndian.Uint32(key[0:4])
	x5 := binary.LittleEndian.Uint32(key[4:8])
	x6 := binary.LittleEndian.Uint32(key[8:12])
	x7 := binary.LittleEndian.Uint32(key[12:16])
	x8 := binary.LittleEndian.Uint32(key[16:20])
	x9 := binary.LittleEndian.Uint32(key[20:24])
	x10 := binary.LittleEndian.Uint32(key[24:28])
	x11 := binary.LittleEndian.Uint32(key[28:32])
	x12 := binary.LittleEndian.Uint32(nonce[0:4])
	x13 := binary.LittleEndian.Uint32(nonce[4:8])
	x14 := binary.LittleEndian.Uint32(nonce[8:12])
	x15 := binary.LittleEndian.Uint32(nonce[12:16])

	for i := 0; i < 10; i++ {
		// Diagonal round.
		x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12)
		x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13)
		x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14)
		x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15)

		// Column round.
		x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15)
		x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12)
		x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13)
		x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14)
	}

	_ = out[31] // bounds check elimination hint
	binary.LittleEndian.PutUint32(out[0:4], x0)
	binary.LittleEndian.PutUint32(out[4:8], x1)
	binary.LittleEndian.PutUint32(out[8:12], x2)
	binary.LittleEndian.PutUint32(out[12:16], x3)
	binary.LittleEndian.PutUint32(out[16:20], x12)
	binary.LittleEndian.PutUint32(out[20:24], x13)
	binary.LittleEndian.PutUint32(out[24:28], x14)
	binary.LittleEndian.PutUint32(out[28:32], x15)
	return out, nil
}


================================================
FILE: gossh/crypto/chacha20/chacha_noasm.go
================================================
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:build (!arm64 && !s390x && !ppc64le) || !gc || purego

package chacha20

const bufSize = blockSize

func (s *Cipher) xorKeyStreamBlocks(dst, src []byte) {
	s.xorKeyStreamBlocksGeneric(dst, src)
}


================================================
FILE: gossh/crypto/chacha20/chacha_ppc64le.go
================================================
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:build gc && !purego

package chacha20

const bufSize = 256

//go:noescape
func chaCha20_ctr32_vsx(out, inp *byte, len int, key *[8]uint32, counter *uint32)

func (c *Cipher) xorKeyStreamBlocks(dst, src []byte) {
	chaCha20_ctr32_vsx(&dst[0], &src[0], len(src), &c.key, &c.counter)
}


================================================
FILE: gossh/crypto/chacha20/chacha_ppc64le.s
================================================
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Based on CRYPTOGAMS code with the following comment:
// # ====================================================================
// # Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
// # project. The module is, however, dual licensed under OpenSSL and
// # CRYPTOGAMS licenses depending on where you obtain it. For further
// # details see http://www.openssl.org/~appro/cryptogams/.
// # ====================================================================

// Code for the perl script that generates the ppc64 assembler
// can be found in the cryptogams repository at the link below. It is based on
// the original from openssl.

// https://github.com/dot-asm/cryptogams/commit/a60f5b50ed908e91

// The differences in this and the original implementation are
// due to the calling conventions and initialization of constants.

//go:build gc && !purego

#include "textflag.h"

#define OUT  R3
#define INP  R4
#define LEN  R5
#define KEY  R6
#define CNT  R7
#define TMP  R15

#define CONSTBASE  R16
#define BLOCKS R17

DATA consts<>+0x00(SB)/8, $0x3320646e61707865
DATA consts<>+0x08(SB)/8, $0x6b20657479622d32
DATA consts<>+0x10(SB)/8, $0x0000000000000001
DATA consts<>+0x18(SB)/8, $0x0000000000000000
DATA consts<>+0x20(SB)/8, $0x0000000000000004
DATA consts<>+0x28(SB)/8, $0x0000000000000000
DATA consts<>+0x30(SB)/8, $0x0a0b08090e0f0c0d
DATA consts<>+0x38(SB)/8, $0x0203000106070405
DATA consts<>+0x40(SB)/8, $0x090a0b080d0e0f0c
DATA consts<>+0x48(SB)/8, $0x0102030005060704
DATA consts<>+0x50(SB)/8, $0x6170786561707865
DATA consts<>+0x58(SB)/8, $0x6170786561707865
DATA consts<>+0x60(SB)/8, $0x3320646e3320646e
DATA consts<>+0x68(SB)/8, $0x3320646e3320646e
DATA consts<>+0x70(SB)/8, $0x79622d3279622d32
DATA consts<>+0x78(SB)/8, $0x79622d3279622d32
DATA consts<>+0x80(SB)/8, $0x6b2065746b206574
DATA consts<>+0x88(SB)/8, $0x6b2065746b206574
DATA consts<>+0x90(SB)/8, $0x0000000100000000
DATA consts<>+0x98(SB)/8, $0x0000000300000002
GLOBL consts<>(SB), RODATA, $0xa0

//func chaCha20_ctr32_vsx(out, inp *byte, len int, key *[8]uint32, counter *uint32)
TEXT ·chaCha20_ctr32_vsx(SB),NOSPLIT,$64-40
	MOVD out+0(FP), OUT
	MOVD inp+8(FP), INP
	MOVD len+16(FP), LEN
	MOVD key+24(FP), KEY
	MOVD counter+32(FP), CNT

	// Addressing for constants
	MOVD $consts<>+0x00(SB), CONSTBASE
	MOVD $16, R8
	MOVD $32, R9
	MOVD $48, R10
	MOVD $64, R11
	SRD $6, LEN, BLOCKS
	// V16
	LXVW4X (CONSTBASE)(R0), VS48
	ADD $80,CONSTBASE

	// Load key into V17,V18
	LXVW4X (KEY)(R0), VS49
	LXVW4X (KEY)(R8), VS50

	// Load CNT, NONCE into V19
	LXVW4X (CNT)(R0), VS51

	// Clear V27
	VXOR V27, V27, V27

	// V28
	LXVW4X (CONSTBASE)(R11), VS60

	// splat slot from V19 -> V26
	VSPLTW $0, V19, V26

	VSLDOI $4, V19, V27, V19
	VSLDOI $12, V27, V19, V19

	VADDUWM V26, V28, V26

	MOVD $10, R14
	MOVD R14, CTR

loop_outer_vsx:
	// V0, V1, V2, V3
	LXVW4X (R0)(CONSTBASE), VS32
	LXVW4X (R8)(CONSTBASE), VS33
	LXVW4X (R9)(CONSTBASE), VS34
	LXVW4X (R10)(CONSTBASE), VS35

	// splat values from V17, V18 into V4-V11
	VSPLTW $0, V17, V4
	VSPLTW $1, V17, V5
	VSPLTW $2, V17, V6
	VSPLTW $3, V17, V7
	VSPLTW $0, V18, V8
	VSPLTW $1, V18, V9
	VSPLTW $2, V18, V10
	VSPLTW $3, V18, V11

	// VOR
	VOR V26, V26, V12

	// splat values from V19 -> V13, V14, V15
	VSPLTW $1, V19, V13
	VSPLTW $2, V19, V14
	VSPLTW $3, V19, V15

	// splat   const values
	VSPLTISW $-16, V27
	VSPLTISW $12, V28
	VSPLTISW $8, V29
	VSPLTISW $7, V30

loop_vsx:
	VADDUWM V0, V4, V0
	VADDUWM V1, V5, V1
	VADDUWM V2, V6, V2
	VADDUWM V3, V7, V3

	VXOR V12, V0, V12
	VXOR V13, V1, V13
	VXOR V14, V2, V14
	VXOR V15, V3, V15

	VRLW V12, V27, V12
	VRLW V13, V27, V13
	VRLW V14, V27, V14
	VRLW V15, V27, V15

	VADDUWM V8, V12, V8
	VADDUWM V9, V13, V9
	VADDUWM V10, V14, V10
	VADDUWM V11, V15, V11

	VXOR V4, V8, V4
	VXOR V5, V9, V5
	VXOR V6, V10, V6
	VXOR V7, V11, V7

	VRLW V4, V28, V4
	VRLW V5, V28, V5
	VRLW V6, V28, V6
	VRLW V7, V28, V7

	VADDUWM V0, V4, V0
	VADDUWM V1, V5, V1
	VADDUWM V2, V6, V2
	VADDUWM V3, V7, V3

	VXOR V12, V0, V12
	VXOR V13, V1, V13
	VXOR V14, V2, V14
	VXOR V15, V3, V15

	VRLW V12, V29, V12
	VRLW V13, V29, V13
	VRLW V14, V29, V14
	VRLW V15, V29, V15

	VADDUWM V8, V12, V8
	VADDUWM V9, V13, V9
	VADDUWM V10, V14, V10
	VADDUWM V11, V15, V11

	VXOR V4, V8, V4
	VXOR V5, V9, V5
	VXOR V6, V10, V6
	VXOR V7, V11, V7

	VRLW V4, V30, V4
	VRLW V5, V30, V5
	VRLW V6, V30, V6
	VRLW V7, V30, V7

	VADDUWM V0, V5, V0
	VADDUWM V1, V6, V1
	VADDUWM V2, V7, V2
	VADDUWM V3, V4, V3

	VXOR V15, V0, V15
	VXOR V12, V1, V12
	VXOR V13, V2, V13
	VXOR V14, V3, V14

	VRLW V15, V27, V15
	VRLW V12, V27, V12
	VRLW V13, V27, V13
	VRLW V14, V27, V14

	VADDUWM V10, V15, V10
	VADDUWM V11, V12, V11
	VADDUWM V8, V13, V8
	VADDUWM V9, V14, V9

	VXOR V5, V10, V5
	VXOR V6, V11, V6
	VXOR V7, V8, V7
	VXOR V4, V9, V4

	VRLW V5, V28, V5
	VRLW V6, V28, V6
	VRLW V7, V28, V7
	VRLW V4, V28, V4

	VADDUWM V0, V5, V0
	VADDUWM V1, V6, V1
	VADDUWM V2, V7, V2
	VADDUWM V3, V4, V3

	VXOR V15, V0, V15
	VXOR V12, V1, V12
	VXOR V13, V2, V13
	VXOR V14, V3, V14

	VRLW V15, V29, V15
	VRLW V12, V29, V12
	VRLW V13, V29, V13
	VRLW V14, V29, V14

	VADDUWM V10, V15, V10
	VADDUWM V11, V12, V11
	VADDUWM V8, V13, V8
	VADDUWM V9, V14, V9

	VXOR V5, V10, V5
	VXOR V6, V11, V6
	VXOR V7, V8, V7
	VXOR V4, V9, V4

	VRLW V5, V30, V5
	VRLW V6, V30, V6
	VRLW V7, V30, V7
	VRLW V4, V30, V4
	BC   16, LT, loop_vsx

	VADDUWM V12, V26, V12

	WORD $0x13600F8C		// VMRGEW V0, V1, V27
	WORD $0x13821F8C		// VMRGEW V2, V3, V28

	WORD $0x10000E8C		// VMRGOW V0, V1, V0
	WORD $0x10421E8C		// VMRGOW V2, V3, V2

	WORD $0x13A42F8C		// VMRGEW V4, V5, V29
	WORD $0x13C63F8C		// VMRGEW V6, V7, V30

	XXPERMDI VS32, VS34, $0, VS33
	XXPERMDI VS32, VS34, $3, VS35
	XXPERMDI VS59, VS60, $0, VS32
	XXPERMDI VS59, VS60, $3, VS34

	WORD $0x10842E8C		// VMRGOW V4, V5, V4
	WORD $0x10C63E8C		// VMRGOW V6, V7, V6

	WORD $0x13684F8C		// VMRGEW V8, V9, V27
	WORD $0x138A5F8C		// VMRGEW V10, V11, V28

	XXPERMDI VS36, VS38, $0, VS37
	XXPERMDI VS36, VS38, $3, VS39
	XXPERMDI VS61, VS62, $0, VS36
	XXPERMDI VS61, VS62, $3, VS38

	WORD $0x11084E8C		// VMRGOW V8, V9, V8
	WORD $0x114A5E8C		// VMRGOW V10, V11, V10

	WORD $0x13AC6F8C		// VMRGEW V12, V13, V29
	WORD $0x13CE7F8C		// VMRGEW V14, V15, V30

	XXPERMDI VS40, VS42, $0, VS41
	XXPERMDI VS40, VS42, $3, VS43
	XXPERMDI VS59, VS60, $0, VS40
	XXPERMDI VS59, VS60, $3, VS42

	WORD $0x118C6E8C		// VMRGOW V12, V13, V12
	WORD $0x11CE7E8C		// VMRGOW V14, V15, V14

	VSPLTISW $4, V27
	VADDUWM V26, V27, V26

	XXPERMDI VS44, VS46, $0, VS45
	XXPERMDI VS44, VS46, $3, VS47
	XXPERMDI VS61, VS62, $0, VS44
	XXPERMDI VS61, VS62, $3, VS46

	VADDUWM V0, V16, V0
	VADDUWM V4, V17, V4
	VADDUWM V8, V18, V8
	VADDUWM V12, V19, V12

	CMPU LEN, $64
	BLT tail_vsx

	// Bottom of loop
	LXVW4X (INP)(R0), VS59
	LXVW4X (INP)(R8), VS60
	LXVW4X (INP)(R9), VS61
	LXVW4X (INP)(R10), VS62

	VXOR V27, V0, V27
	VXOR V28, V4, V28
	VXOR V29, V8, V29
	VXOR V30, V12, V30

	STXVW4X VS59, (OUT)(R0)
	STXVW4X VS60, (OUT)(R8)
	ADD     $64, INP
	STXVW4X VS61, (OUT)(R9)
	ADD     $-64, LEN
	STXVW4X VS62, (OUT)(R10)
	ADD     $64, OUT
	BEQ     done_vsx

	VADDUWM V1, V16, V0
	VADDUWM V5, V17, V4
	VADDUWM V9, V18, V8
	VADDUWM V13, V19, V12

	CMPU  LEN, $64
	BLT   tail_vsx

	LXVW4X (INP)(R0), VS59
	LXVW4X (INP)(R8), VS60
	LXVW4X (INP)(R9), VS61
	LXVW4X (INP)(R10), VS62
	VXOR   V27, V0, V27

	VXOR V28, V4, V28
	VXOR V29, V8, V29
	VXOR V30, V12, V30

	STXVW4X VS59, (OUT)(R0)
	STXVW4X VS60, (OUT)(R8)
	ADD     $64, INP
	STXVW4X VS61, (OUT)(R9)
	ADD     $-64, LEN
	STXVW4X VS62, (OUT)(V10)
	ADD     $64, OUT
	BEQ     done_vsx

	VADDUWM V2, V16, V0
	VADDUWM V6, V17, V4
	VADDUWM V10, V18, V8
	VADDUWM V14, V19, V12

	CMPU LEN, $64
	BLT  tail_vsx

	LXVW4X (INP)(R0), VS59
	LXVW4X (INP)(R8), VS60
	LXVW4X (INP)(R9), VS61
	LXVW4X (INP)(R10), VS62

	VXOR V27, V0, V27
	VXOR V28, V4, V28
	VXOR V29, V8, V29
	VXOR V30, V12, V30

	STXVW4X VS59, (OUT)(R0)
	STXVW4X VS60, (OUT)(R8)
	ADD     $64, INP
	STXVW4X VS61, (OUT)(R9)
	ADD     $-64, LEN
	STXVW4X VS62, (OUT)(R10)
	ADD     $64, OUT
	BEQ     done_vsx

	VADDUWM V3, V16, V0
	VADDUWM V7, V17, V4
	VADDUWM V11, V18, V8
	VADDUWM V15, V19, V12

	CMPU  LEN, $64
	BLT   tail_vsx

	LXVW4X (INP)(R0), VS59
	LXVW4X (INP)(R8), VS60
	LXVW4X (INP)(R9), VS61
	LXVW4X (INP)(R10), VS62

	VXOR V27, V0, V27
	VXOR V28, V4, V28
	VXOR V29, V8, V29
	VXOR V30, V12, V30

	STXVW4X VS59, (OUT)(R0)
	STXVW4X VS60, (OUT)(R8)
	ADD     $64, INP
	STXVW4X VS61, (OUT)(R9)
	ADD     $-64, LEN
	STXVW4X VS62, (OUT)(R10)
	ADD     $64, OUT

	MOVD $10, R14
	MOVD R14, CTR
	BNE  loop_outer_vsx

done_vsx:
	// Increment counter by number of 64 byte blocks
	MOVD (CNT), R14
	ADD  BLOCKS, R14
	MOVD R14, (CNT)
	RET

tail_vsx:
	ADD  $32, R1, R11
	MOVD LEN, CTR

	// Save values on stack to copy from
	STXVW4X VS32, (R11)(R0)
	STXVW4X VS36, (R11)(R8)
	STXVW4X VS40, (R11)(R9)
	STXVW4X VS44, (R11)(R10)
	ADD $-1, R11, R12
	ADD $-1, INP
	ADD $-1, OUT

looptail_vsx:
	// Copying the result to OUT
	// in bytes.
	MOVBZU 1(R12), KEY
	MOVBZU 1(INP), TMP
	XOR    KEY, TMP, KEY
	MOVBU  KEY, 1(OUT)
	BC     16, LT, looptail_vsx

	// Clear the stack values
	STXVW4X VS48, (R11)(R0)
	STXVW4X VS48, (R11)(R8)
	STXVW4X VS48, (R11)(R9)
	STXVW4X VS48, (R11)(R10)
	BR      done_vsx


================================================
FILE: gossh/crypto/chacha20/chacha_s390x.go
================================================
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:build gc && !purego

package chacha20

import "gossh/sys/cpu"

var haveAsm = cpu.S390X.HasVX

const bufSize = 256

// xorKeyStreamVX is an assembly implementation of XORKeyStream. It must only
// be called when the vector facility is available. Implementation in asm_s390x.s.
//
//go:noescape
func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32)

func (c *Cipher) xorKeyStreamBlocks(dst, src []byte) {
	if cpu.S390X.HasVX {
		xorKeyStreamVX(dst, src, &c.key, &c.nonce, &c.counter)
	} else {
		c.xorKeyStreamBlocksGeneric(dst, src)
	}
}


================================================
FILE: gossh/crypto/chacha20/chacha_s390x.s
================================================
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:build gc && !purego

#include "go_asm.h"
#include "textflag.h"

// This is an implementation of the ChaCha20 encryption algorithm as
// specified in RFC 7539. It uses vector instructions to compute
// 4 keystream blocks in parallel (256 bytes) which are then XORed
// with the bytes in the input slice.

GLOBL ·constants<>(SB), RODATA|NOPTR, $32
// BSWAP: swap bytes in each 4-byte element
DATA ·constants<>+0x00(SB)/4, $0x03020100
DATA ·constants<>+0x04(SB)/4, $0x07060504
DATA ·constants<>+0x08(SB)/4, $0x0b0a0908
DATA ·constants<>+0x0c(SB)/4, $0x0f0e0d0c
// J0: [j0, j1, j2, j3]
DATA ·constants<>+0x10(SB)/4, $0x61707865
DATA ·constants<>+0x14(SB)/4, $0x3320646e
DATA ·constants<>+0x18(SB)/4, $0x79622d32
DATA ·constants<>+0x1c(SB)/4, $0x6b206574

#define BSWAP V5
#define J0    V6
#define KEY0  V7
#define KEY1  V8
#define NONCE V9
#define CTR   V10
#define M0    V11
#define M1    V12
#define M2    V13
#define M3    V14
#define INC   V15
#define X0    V16
#define X1    V17
#define X2    V18
#define X3    V19
#define X4    V20
#define X5    V21
#define X6    V22
#define X7    V23
#define X8    V24
#define X9    V25
#define X10   V26
#define X11   V27
#define X12   V28
#define X13   V29
#define X14   V30
#define X15   V31

#define NUM_ROUNDS 20

#define ROUND4(a0, a1, a2, a3, b0, b1, b2, b3, c0, c1, c2, c3, d0, d1, d2, d3) \
	VAF    a1, a0, a0  \
	VAF    b1, b0, b0  \
	VAF    c1, c0, c0  \
	VAF    d1, d0, d0  \
	VX     a0, a2, a2  \
	VX     b0, b2, b2  \
	VX     c0, c2, c2  \
	VX     d0, d2, d2  \
	VERLLF $16, a2, a2 \
	VERLLF $16, b2, b2 \
	VERLLF $16, c2, c2 \
	VERLLF $16, d2, d2 \
	VAF    a2, a3, a3  \
	VAF    b2, b3, b3  \
	VAF    c2, c3, c3  \
	VAF    d2, d3, d3  \
	VX     a3, a1, a1  \
	VX     b3, b1, b1  \
	VX     c3, c1, c1  \
	VX     d3, d1, d1  \
	VERLLF $12, a1, a1 \
	VERLLF $12, b1, b1 \
	VERLLF $12, c1, c1 \
	VERLLF $12, d1, d1 \
	VAF    a1, a0, a0  \
	VAF    b1, b0, b0  \
	VAF    c1, c0, c0  \
	VAF    d1, d0, d0  \
	VX     a0, a2, a2  \
	VX     b0, b2, b2  \
	VX     c0, c2, c2  \
	VX     d0, d2, d2  \
	VERLLF $8, a2, a2  \
	VERLLF $8, b2, b2  \
	VERLLF $8, c2, c2  \
	VERLLF $8, d2, d2  \
	VAF    a2, a3, a3  \
	VAF    b2, b3, b3  \
	VAF    c2, c3, c3  \
	VAF    d2, d3, d3  \
	VX     a3, a1, a1  \
	VX     b3, b1, b1  \
	VX     c3, c1, c1  \
	VX     d3, d1, d1  \
	VERLLF $7, a1, a1  \
	VERLLF $7, b1, b1  \
	VERLLF $7, c1, c1  \
	VERLLF $7, d1, d1

#define PERMUTE(mask, v0, v1, v2, v3) \
	VPERM v0, v0, mask, v0 \
	VPERM v1, v1, mask, v1 \
	VPERM v2, v2, mask, v2 \
	VPERM v3, v3, mask, v3

#define ADDV(x, v0, v1, v2, v3) \
	VAF x, v0, v0 \
	VAF x, v1, v1 \
	VAF x, v2, v2 \
	VAF x, v3, v3

#define XORV(off, dst, src, v0, v1, v2, v3) \
	VLM  off(src), M0, M3          \
	PERMUTE(BSWAP, v0, v1, v2, v3) \
	VX   v0, M0, M0                \
	VX   v1, M1, M1                \
	VX   v2, M2, M2                \
	VX   v3, M3, M3                \
	VSTM M0, M3, off(dst)

#define SHUFFLE(a, b, c, d, t, u, v, w) \
	VMRHF a, c, t \ // t = {a[0], c[0], a[1], c[1]}
	VMRHF b, d, u \ // u = {b[0], d[0], b[1], d[1]}
	VMRLF a, c, v \ // v = {a[2], c[2], a[3], c[3]}
	VMRLF b, d, w \ // w = {b[2], d[2], b[3], d[3]}
	VMRHF t, u, a \ // a = {a[0], b[0], c[0], d[0]}
	VMRLF t, u, b \ // b = {a[1], b[1], c[1], d[1]}
	VMRHF v, w, c \ // c = {a[2], b[2], c[2], d[2]}
	VMRLF v, w, d // d = {a[3], b[3], c[3], d[3]}

// func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32)
TEXT ·xorKeyStreamVX(SB), NOSPLIT, $0
	MOVD $·constants<>(SB), R1
	MOVD dst+0(FP), R2         // R2=&dst[0]
	LMG  src+24(FP), R3, R4    // R3=&src[0] R4=len(src)
	MOVD key+48(FP), R5        // R5=key
	MOVD nonce+56(FP), R6      // R6=nonce
	MOVD counter+64(FP), R7    // R7=counter

	// load BSWAP and J0
	VLM (R1), BSWAP, J0

	// setup
	MOVD  $95, R0
	VLM   (R5), KEY0, KEY1
	VLL   R0, (R6), NONCE
	VZERO M0
	VLEIB $7, $32, M0
	VSRLB M0, NONCE, NONCE

	// initialize counter values
	VLREPF (R7), CTR
	VZERO  INC
	VLEIF  $1, $1, INC
	VLEIF  $2, $2, INC
	VLEIF  $3, $3, INC
	VAF    INC, CTR, CTR
	VREPIF $4, INC

chacha:
	VREPF $0, J0, X0
	VREPF $1, J0, X1
	VREPF $2, J0, X2
	VREPF $3, J0, X3
	VREPF $0, KEY0, X4
	VREPF $1, KEY0, X5
	VREPF $2, KEY0, X6
	VREPF $3, KEY0, X7
	VREPF $0, KEY1, X8
	VREPF $1, KEY1, X9
	VREPF $2, KEY1, X10
	VREPF $3, KEY1, X11
	VLR   CTR, X12
	VREPF $1, NONCE, X13
	VREPF $2, NONCE, X14
	VREPF $3, NONCE, X15

	MOVD $(NUM_ROUNDS/2), R1

loop:
	ROUND4(X0, X4, X12,  X8, X1, X5, X13,  X9, X2, X6, X14, X10, X3, X7, X15, X11)
	ROUND4(X0, X5, X15, X10, X1, X6, X12, X11, X2, X7, X13, X8,  X3, X4, X14, X9)

	ADD $-1, R1
	BNE loop

	// decrement length
	ADD $-256, R4

	// rearrange vectors
	SHUFFLE(X0, X1, X2, X3, M0, M1, M2, M3)
	ADDV(J0, X0, X1, X2, X3)
	SHUFFLE(X4, X5, X6, X7, M0, M1, M2, M3)
	ADDV(KEY0, X4, X5, X6, X7)
	SHUFFLE(X8, X9, X10, X11, M0, M1, M2, M3)
	ADDV(KEY1, X8, X9, X10, X11)
	VAF CTR, X12, X12
	SHUFFLE(X12, X13, X14, X15, M0, M1, M2, M3)
	ADDV(NONCE, X12, X13, X14, X15)

	// increment counters
	VAF INC, CTR, CTR

	// xor keystream with plaintext
	XORV(0*64, R2, R3, X0, X4,  X8, X12)
	XORV(1*64, R2, R3, X1, X5,  X9, X13)
	XORV(2*64, R2, R3, X2, X6, X10, X14)
	XORV(3*64, R2, R3, X3, X7, X11, X15)

	// increment pointers
	MOVD $256(R2), R2
	MOVD $256(R3), R3

	CMPBNE  R4, $0, chacha

	VSTEF $0, CTR, (R7)
	RET


================================================
FILE: gossh/crypto/chacha20/xor.go
================================================
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found src the LICENSE file.

package chacha20

import "runtime"

// Platforms that have fast unaligned 32-bit little endian accesses.
const unaligned = runtime.GOARCH == "386" ||
	runtime.GOARCH == "amd64" ||
	runtime.GOARCH == "arm64" ||
	runtime.GOARCH == "ppc64le" ||
	runtime.GOARCH == "s390x"

// addXor reads a little endian uint32 from src, XORs it with (a + b) and
// places the result in little endian byte order in dst.
func addXor(dst, src []byte, a, b uint32) {
	_, _ = src[3], dst[3] // bounds check elimination hint
	if unaligned {
		// The compiler should optimize this code into
		// 32-bit unaligned little endian loads and stores.
		// TODO: delete once the compiler does a reliably
		// good job with the generic code below.
		// See issue #25111 for more details.
		v := uint32(src[0])
		v |= uint32(src[1]) << 8
		v |= uint32(src[2]) << 16
		v |= uint32(src[3]) << 24
		v ^= a + b
		dst[0] = byte(v)
		dst[1] = byte(v >> 8)
		dst[2] = byte(v >> 16)
		dst[3] = byte(v >> 24)
	} else {
		a += b
		dst[0] = src[0] ^ byte(a)
		dst[1] = src[1] ^ byte(a>>8)
		dst[2] = src[2] ^ byte(a>>16)
		dst[3] = src[3] ^ byte(a>>24)
	}
}


================================================
FILE: gossh/crypto/chacha20poly1305/chacha20poly1305.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package chacha20poly1305 implements the ChaCha20-Poly1305 AEAD and its
// extended nonce variant XChaCha20-Poly1305, as specified in RFC 8439 and
// draft-irtf-cfrg-xchacha-01.
package chacha20poly1305 // import "golang.org/x/crypto/chacha20poly1305"

import (
	"crypto/cipher"
	"errors"
)

const (
	// KeySize is the size of the key used by this AEAD, in bytes.
	KeySize = 32

	// NonceSize is the size of the nonce used with the standard variant of this
	// AEAD, in bytes.
	//
	// Note that this is too short to be safely generated at random if the same
	// key is reused more than 2³² times.
	NonceSize = 12

	// NonceSizeX is the size of the nonce used with the XChaCha20-Poly1305
	// variant of this AEAD, in bytes.
	NonceSizeX = 24

	// Overhead is the size of the Poly1305 authentication tag, and the
	// difference between a ciphertext length and its plaintext.
	Overhead = 16
)

type chacha20poly1305 struct {
	key [KeySize]byte
}

// New returns a ChaCha20-Poly1305 AEAD that uses the given 256-bit key.
func New(key []byte) (cipher.AEAD, error) {
	if len(key) != KeySize {
		return nil, errors.New("chacha20poly1305: bad key length")
	}
	ret := new(chacha20poly1305)
	copy(ret.key[:], key)
	return ret, nil
}

func (c *chacha20poly1305) NonceSize() int {
	return NonceSize
}

func (c *chacha20poly1305) Overhead() int {
	return Overhead
}

func (c *chacha20poly1305) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
	if len(nonce) != NonceSize {
		panic("chacha20poly1305: bad nonce length passed to Seal")
	}

	if uint64(len(plaintext)) > (1<<38)-64 {
		panic("chacha20poly1305: plaintext too large")
	}

	return c.seal(dst, nonce, plaintext, additionalData)
}

var errOpen = errors.New("chacha20poly1305: message authentication failed")

func (c *chacha20poly1305) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
	if len(nonce) != NonceSize {
		panic("chacha20poly1305: bad nonce length passed to Open")
	}
	if len(ciphertext) < 16 {
		return nil, errOpen
	}
	if uint64(len(ciphertext)) > (1<<38)-48 {
		panic("chacha20poly1305: ciphertext too large")
	}

	return c.open(dst, nonce, ciphertext, additionalData)
}

// sliceForAppend takes a slice and a requested number of bytes. It returns a
// slice with the contents of the given slice followed by that many bytes and a
// second slice that aliases into it and contains only the extra bytes. If the
// original slice has sufficient capacity then no allocation is performed.
func sliceForAppend(in []byte, n int) (head, tail []byte) {
	if total := len(in) + n; cap(in) >= total {
		head = in[:total]
	} else {
		head = make([]byte, total)
		copy(head, in)
	}
	tail = head[len(in):]
	return
}


================================================
FILE: gossh/crypto/chacha20poly1305/chacha20poly1305_amd64.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:build gc && !purego

package chacha20poly1305

import (
	"encoding/binary"

	"gossh/crypto/internal/alias"
	"gossh/sys/cpu"
)

//go:noescape
func chacha20Poly1305Open(dst []byte, key []uint32, src, ad []byte) bool

//go:noescape
func chacha20Poly1305Seal(dst []byte, key []uint32, src, ad []byte)

var (
	useAVX2 = cpu.X86.HasAVX2 && cpu.X86.HasBMI2
)

// setupState writes a ChaCha20 input matrix to state. See
// https://tools.ietf.org/html/rfc7539#section-2.3.
func setupState(state *[16]uint32, key *[32]byte, nonce []byte) {
	state[0] = 0x61707865
	state[1] = 0x3320646e
	state[2] = 0x79622d32
	state[3] = 0x6b206574

	state[4] = binary.LittleEndian.Uint32(key[0:4])
	state[5] = binary.LittleEndian.Uint32(key[4:8])
	state[6] = binary.LittleEndian.Uint32(key[8:12])
	state[7] = binary.LittleEndian.Uint32(key[12:16])
	state[8] = binary.LittleEndian.Uint32(key[16:20])
	state[9] = binary.LittleEndian.Uint32(key[20:24])
	state[10] = binary.LittleEndian.Uint32(key[24:28])
	state[11] = binary.LittleEndian.Uint32(key[28:32])

	state[12] = 0
	state[13] = binary.LittleEndian.Uint32(nonce[0:4])
	state[14] = binary.LittleEndian.Uint32(nonce[4:8])
	state[15] = binary.LittleEndian.Uint32(nonce[8:12])
}

func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) []byte {
	if !cpu.X86.HasSSSE3 {
		return c.sealGeneric(dst, nonce, plaintext, additionalData)
	}

	var state [16]uint32
	setupState(&state, &c.key, nonce)

	ret, out := sliceForAppend(dst, len(plaintext)+16)
	if alias.InexactOverlap(out, plaintext) {
		panic("chacha20poly1305: invalid buffer overlap")
	}
	chacha20Poly1305Seal(out[:], state[:], plaintext, additionalData)
	return ret
}

func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
	if !cpu.X86.HasSSSE3 {
		return c.openGeneric(dst, nonce, ciphertext, additionalData)
	}

	var state [16]uint32
	setupState(&state, &c.key, nonce)

	ciphertext = ciphertext[:len(ciphertext)-16]
	ret, out := sliceForAppend(dst, len(ciphertext))
	if alias.InexactOverlap(out, ciphertext) {
		panic("chacha20poly1305: invalid buffer overlap")
	}
	if !chacha20Poly1305Open(out, state[:], ciphertext, additionalData) {
		for i := range out {
			out[i] = 0
		}
		return nil, errOpen
	}

	return ret, nil
}


================================================
FILE: gossh/crypto/chacha20poly1305/chacha20poly1305_amd64.s
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file was originally from https://golang.org/cl/24717 by Vlad Krasnov of CloudFlare.

//go:build gc && !purego

#include "textflag.h"
// General register allocation
#define oup DI
#define inp SI
#define inl BX
#define adp CX // free to reuse, after we hash the additional data
#define keyp R8 // free to reuse, when we copy the key to stack
#define itr2 R9 // general iterator
#define itr1 CX // general iterator
#define acc0 R10
#define acc1 R11
#define acc2 R12
#define t0 R13
#define t1 R14
#define t2 R15
#define t3 R8
// Register and stack allocation for the SSE code
#define rStore (0*16)(BP)
#define sStore (1*16)(BP)
#define state1Store (2*16)(BP)
#define state2Store (3*16)(BP)
#define tmpStore (4*16)(BP)
#define ctr0Store (5*16)(BP)
#define ctr1Store (6*16)(BP)
#define ctr2Store (7*16)(BP)
#define ctr3Store (8*16)(BP)
#define A0 X0
#define A1 X1
#define A2 X2
#define B0 X3
#define B1 X4
#define B2 X5
#define C0 X6
#define C1 X7
#define C2 X8
#define D0 X9
#define D1 X10
#define D2 X11
#define T0 X12
#define T1 X13
#define T2 X14
#define T3 X15
#define A3 T0
#define B3 T1
#define C3 T2
#define D3 T3
// Register and stack allocation for the AVX2 code
#define rsStoreAVX2 (0*32)(BP)
#define state1StoreAVX2 (1*32)(BP)
#define state2StoreAVX2 (2*32)(BP)
#define ctr0StoreAVX2 (3*32)(BP)
#define ctr1StoreAVX2 (4*32)(BP)
#define ctr2StoreAVX2 (5*32)(BP)
#define ctr3StoreAVX2 (6*32)(BP)
#define tmpStoreAVX2 (7*32)(BP) // 256 bytes on stack
#define AA0 Y0
#define AA1 Y5
#define AA2 Y6
#define AA3 Y7
#define BB0 Y14
#define BB1 Y9
#define BB2 Y10
#define BB3 Y11
#define CC0 Y12
#define CC1 Y13
#define CC2 Y8
#define CC3 Y15
#define DD0 Y4
#define DD1 Y1
#define DD2 Y2
#define DD3 Y3
#define TT0 DD3
#define TT1 AA3
#define TT2 BB3
#define TT3 CC3
// ChaCha20 constants
DATA ·chacha20Constants<>+0x00(SB)/4, $0x61707865
DATA ·chacha20Constants<>+0x04(SB)/4, $0x3320646e
DATA ·chacha20Constants<>+0x08(SB)/4, $0x79622d32
DATA ·chacha20Constants<>+0x0c(SB)/4, $0x6b206574
DATA ·chacha20Constants<>+0x10(SB)/4, $0x61707865
DATA ·chacha20Constants<>+0x14(SB)/4, $0x3320646e
DATA ·chacha20Constants<>+0x18(SB)/4, $0x79622d32
DATA ·chacha20Constants<>+0x1c(SB)/4, $0x6b206574
// <<< 16 with PSHUFB
DATA ·rol16<>+0x00(SB)/8, $0x0504070601000302
DATA ·rol16<>+0x08(SB)/8, $0x0D0C0F0E09080B0A
DATA ·rol16<>+0x10(SB)/8, $0x0504070601000302
DATA ·rol16<>+0x18(SB)/8, $0x0D0C0F0E09080B0A
// <<< 8 with PSHUFB
DATA ·rol8<>+0x00(SB)/8, $0x0605040702010003
DATA ·rol8<>+0x08(SB)/8, $0x0E0D0C0F0A09080B
DATA ·rol8<>+0x10(SB)/8, $0x0605040702010003
DATA ·rol8<>+0x18(SB)/8, $0x0E0D0C0F0A09080B

DATA ·avx2InitMask<>+0x00(SB)/8, $0x0
DATA ·avx2InitMask<>+0x08(SB)/8, $0x0
DATA ·avx2InitMask<>+0x10(SB)/8, $0x1
DATA ·avx2InitMask<>+0x18(SB)/8, $0x0

DATA ·avx2IncMask<>+0x00(SB)/8, $0x2
DATA ·avx2IncMask<>+0x08(SB)/8, $0x0
DATA ·avx2IncMask<>+0x10(SB)/8, $0x2
DATA ·avx2IncMask<>+0x18(SB)/8, $0x0
// Poly1305 key clamp
DATA ·polyClampMask<>+0x00(SB)/8, $0x0FFFFFFC0FFFFFFF
DATA ·polyClampMask<>+0x08(SB)/8, $0x0FFFFFFC0FFFFFFC
DATA ·polyClampMask<>+0x10(SB)/8, $0xFFFFFFFFFFFFFFFF
DATA ·polyClampMask<>+0x18(SB)/8, $0xFFFFFFFFFFFFFFFF

DATA ·sseIncMask<>+0x00(SB)/8, $0x1
DATA ·sseIncMask<>+0x08(SB)/8, $0x0
// To load/store the last < 16 bytes in a buffer
DATA ·andMask<>+0x00(SB)/8, $0x00000000000000ff
DATA ·andMask<>+0x08(SB)/8, $0x0000000000000000
DATA ·andMask<>+0x10(SB)/8, $0x000000000000ffff
DATA ·andMask<>+0x18(SB)/8, $0x0000000000000000
DATA ·andMask<>+0x20(SB)/8, $0x0000000000ffffff
DATA ·andMask<>+0x28(SB)/8, $0x0000000000000000
DATA ·andMask<>+0x30(SB)/8, $0x00000000ffffffff
DATA ·andMask<>+0x38(SB)/8, $0x0000000000000000
DATA ·andMask<>+0x40(SB)/8, $0x000000ffffffffff
DATA ·andMask<>+0x48(SB)/8, $0x0000000000000000
DATA ·andMask<>+0x50(SB)/8, $0x0000ffffffffffff
DATA ·andMask<>+0x58(SB)/8, $0x0000000000000000
DATA ·andMask<>+0x60(SB)/8, $0x00ffffffffffffff
DATA ·andMask<>+0x68(SB)/8, $0x0000000000000000
DATA ·andMask<>+0x70(SB)/8, $0xffffffffffffffff
DATA ·andMask<>+0x78(SB)/8, $0x0000000000000000
DATA ·andMask<>+0x80(SB)/8, $0xffffffffffffffff
DATA ·andMask<>+0x88(SB)/8, $0x00000000000000ff
DATA ·andMask<>+0x90(SB)/8, $0xffffffffffffffff
DATA ·andMask<>+0x98(SB)/8, $0x000000000000ffff
DATA ·andMask<>+0xa0(SB)/8, $0xffffffffffffffff
DATA ·andMask<>+0xa8(SB)/8, $0x0000000000ffffff
DATA ·andMask<>+0xb0(SB)/8, $0xffffffffffffffff
DATA ·andMask<>+0xb8(SB)/8, $0x00000000ffffffff
DATA ·andMask<>+0xc0(SB)/8, $0xffffffffffffffff
DATA ·andMask<>+0xc8(SB)/8, $0x000000ffffffffff
DATA ·andMask<>+0xd0(SB)/8, $0xffffffffffffffff
DATA ·andMask<>+0xd8(SB)/8, $0x0000ffffffffffff
DATA ·andMask<>+0xe0(SB)/8, $0xffffffffffffffff
DATA ·andMask<>+0xe8(SB)/8, $0x00ffffffffffffff

GLOBL ·chacha20Constants<>(SB), (NOPTR+RODATA), $32
GLOBL ·rol16<>(SB), (NOPTR+RODATA), $32
GLOBL ·rol8<>(SB), (NOPTR+RODATA), $32
GLOBL ·sseIncMask<>(SB), (NOPTR+RODATA), $16
GLOBL ·avx2IncMask<>(SB), (NOPTR+RODATA), $32
GLOBL ·avx2InitMask<>(SB), (NOPTR+RODATA), $32
GLOBL ·polyClampMask<>(SB), (NOPTR+RODATA), $32
GLOBL ·andMask<>(SB), (NOPTR+RODATA), $240
// No PALIGNR in Go ASM yet (but VPALIGNR is present).
#define shiftB0Left BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xdb; BYTE $0x04 // PALIGNR $4, X3, X3
#define shiftB1Left BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xe4; BYTE $0x04 // PALIGNR $4, X4, X4
#define shiftB2Left BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xed; BYTE $0x04 // PALIGNR $4, X5, X5
#define shiftB3Left BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xed; BYTE $0x04 // PALIGNR $4, X13, X13
#define shiftC0Left BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xf6; BYTE $0x08 // PALIGNR $8, X6, X6
#define shiftC1Left BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xff; BYTE $0x08 // PALIGNR $8, X7, X7
#define shiftC2Left BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xc0; BYTE $0x08 // PALIGNR $8, X8, X8
#define shiftC3Left BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xf6; BYTE $0x08 // PALIGNR $8, X14, X14
#define shiftD0Left BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xc9; BYTE $0x0c // PALIGNR $12, X9, X9
#define shiftD1Left BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xd2; BYTE $0x0c // PALIGNR $12, X10, X10
#define shiftD2Left BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xdb; BYTE $0x0c // PALIGNR $12, X11, X11
#define shiftD3Left BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xff; BYTE $0x0c // PALIGNR $12, X15, X15
#define shiftB0Right BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xdb; BYTE $0x0c // PALIGNR $12, X3, X3
#define shiftB1Right BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xe4; BYTE $0x0c // PALIGNR $12, X4, X4
#define shiftB2Right BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xed; BYTE $0x0c // PALIGNR $12, X5, X5
#define shiftB3Right BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xed; BYTE $0x0c // PALIGNR $12, X13, X13
#define shiftC0Right shiftC0Left
#define shiftC1Right shiftC1Left
#define shiftC2Right shiftC2Left
#define shiftC3
Download .txt
gitextract_q8k6q315/

├── .github/
│   └── workflows/
│       └── build-and-release.yml
├── .gitignore
├── Dockerfile
├── LICENSE
├── README.md
├── gossh/
│   ├── Makefile
│   ├── app/
│   │   ├── config/
│   │   │   └── config.go
│   │   ├── middleware/
│   │   │   ├── db_check.go
│   │   │   ├── jwt_auth.go
│   │   │   ├── net_filter.go
│   │   │   ├── perm_check.go
│   │   │   └── sys_init.go
│   │   ├── model/
│   │   │   ├── cmd_note.go
│   │   │   ├── datetime.go
│   │   │   ├── db_init.go
│   │   │   ├── login_audit.go
│   │   │   ├── net_filter.go
│   │   │   ├── policy_conf.go
│   │   │   ├── ssh_conf.go
│   │   │   ├── sshd_cert.go
│   │   │   ├── sshd_conf.go
│   │   │   ├── sshd_user.go
│   │   │   └── web_user.go
│   │   ├── service/
│   │   │   ├── cmd_note.go
│   │   │   ├── db_conn.go
│   │   │   ├── login_audit.go
│   │   │   ├── net_filter.go
│   │   │   ├── policy_conf.go
│   │   │   ├── service_init.go
│   │   │   ├── ssh_conf.go
│   │   │   ├── ssh_conn.go
│   │   │   ├── ssh_sftp.go
│   │   │   ├── ssh_status.go
│   │   │   ├── sshd_cert.go
│   │   │   ├── sshd_server.go
│   │   │   ├── sshd_user.go
│   │   │   ├── sys_init.go
│   │   │   └── web_user.go
│   │   └── utils/
│   │       ├── crypto.go
│   │       └── utils.go
│   ├── crypto/
│   │   ├── blowfish/
│   │   │   ├── block.go
│   │   │   ├── cipher.go
│   │   │   └── const.go
│   │   ├── chacha20/
│   │   │   ├── chacha_arm64.go
│   │   │   ├── chacha_arm64.s
│   │   │   ├── chacha_generic.go
│   │   │   ├── chacha_noasm.go
│   │   │   ├── chacha_ppc64le.go
│   │   │   ├── chacha_ppc64le.s
│   │   │   ├── chacha_s390x.go
│   │   │   ├── chacha_s390x.s
│   │   │   └── xor.go
│   │   ├── chacha20poly1305/
│   │   │   ├── chacha20poly1305.go
│   │   │   ├── chacha20poly1305_amd64.go
│   │   │   ├── chacha20poly1305_amd64.s
│   │   │   ├── chacha20poly1305_generic.go
│   │   │   ├── chacha20poly1305_noasm.go
│   │   │   └── xchacha20poly1305.go
│   │   ├── curve25519/
│   │   │   ├── curve25519.go
│   │   │   ├── curve25519_compat.go
│   │   │   ├── curve25519_go120.go
│   │   │   └── internal/
│   │   │       └── field/
│   │   │           ├── fe.go
│   │   │           ├── fe_amd64.go
│   │   │           ├── fe_amd64.s
│   │   │           ├── fe_amd64_noasm.go
│   │   │           ├── fe_arm64.go
│   │   │           ├── fe_arm64.s
│   │   │           ├── fe_arm64_noasm.go
│   │   │           ├── fe_generic.go
│   │   │           ├── sync.checkpoint
│   │   │           └── sync.sh
│   │   ├── internal/
│   │   │   ├── alias/
│   │   │   │   ├── alias.go
│   │   │   │   └── alias_purego.go
│   │   │   ├── poly1305/
│   │   │   │   ├── mac_noasm.go
│   │   │   │   ├── poly1305.go
│   │   │   │   ├── sum_amd64.go
│   │   │   │   ├── sum_amd64.s
│   │   │   │   ├── sum_generic.go
│   │   │   │   ├── sum_ppc64le.go
│   │   │   │   ├── sum_ppc64le.s
│   │   │   │   ├── sum_s390x.go
│   │   │   │   └── sum_s390x.s
│   │   │   └── testenv/
│   │   │       ├── exec.go
│   │   │       ├── testenv_notunix.go
│   │   │       └── testenv_unix.go
│   │   └── ssh/
│   │       ├── agent/
│   │       │   ├── client.go
│   │       │   ├── forward.go
│   │       │   ├── keyring.go
│   │       │   └── server.go
│   │       ├── buffer.go
│   │       ├── certs.go
│   │       ├── channel.go
│   │       ├── cipher.go
│   │       ├── client.go
│   │       ├── client_auth.go
│   │       ├── common.go
│   │       ├── connection.go
│   │       ├── doc.go
│   │       ├── handshake.go
│   │       ├── internal/
│   │       │   └── bcrypt_pbkdf/
│   │       │       └── bcrypt_pbkdf.go
│   │       ├── kex.go
│   │       ├── keys.go
│   │       ├── knownhosts/
│   │       │   └── knownhosts.go
│   │       ├── mac.go
│   │       ├── messages.go
│   │       ├── mux.go
│   │       ├── server.go
│   │       ├── session.go
│   │       ├── ssh_gss.go
│   │       ├── streamlocal.go
│   │       ├── tcpip.go
│   │       ├── terminal/
│   │       │   └── terminal.go
│   │       └── transport.go
│   ├── gin/
│   │   ├── auth.go
│   │   ├── binding/
│   │   │   ├── binding.go
│   │   │   ├── default_validator.go
│   │   │   ├── form.go
│   │   │   ├── form_mapping.go
│   │   │   ├── header.go
│   │   │   ├── json.go
│   │   │   ├── multipart_form_mapping.go
│   │   │   ├── query.go
│   │   │   ├── uri.go
│   │   │   └── xml.go
│   │   ├── context.go
│   │   ├── debug.go
│   │   ├── errors.go
│   │   ├── fs.go
│   │   ├── gin.go
│   │   ├── ginS/
│   │   │   ├── README.md
│   │   │   └── gins.go
│   │   ├── internal/
│   │   │   ├── bytesconv/
│   │   │   │   └── bytesconv.go
│   │   │   └── json/
│   │   │       └── json.go
│   │   ├── jwt/
│   │   │   ├── README.md
│   │   │   ├── claims.go
│   │   │   ├── cmd/
│   │   │   │   └── jwt/
│   │   │   │       ├── README.md
│   │   │   │       └── main.go
│   │   │   ├── ecdsa.go
│   │   │   ├── ecdsa_utils.go
│   │   │   ├── ed25519.go
│   │   │   ├── ed25519_utils.go
│   │   │   ├── errors.go
│   │   │   ├── errors_go1_20.go
│   │   │   ├── errors_go_other.go
│   │   │   ├── hmac.go
│   │   │   ├── map_claims.go
│   │   │   ├── none.go
│   │   │   ├── parser.go
│   │   │   ├── parser_option.go
│   │   │   ├── registered_claims.go
│   │   │   ├── request/
│   │   │   │   ├── doc.go
│   │   │   │   ├── extractor.go
│   │   │   │   ├── oauth2.go
│   │   │   │   └── request.go
│   │   │   ├── rsa.go
│   │   │   ├── rsa_pss.go
│   │   │   ├── rsa_utils.go
│   │   │   ├── signing_method.go
│   │   │   ├── token.go
│   │   │   ├── token_option.go
│   │   │   ├── types.go
│   │   │   └── validator.go
│   │   ├── logger.go
│   │   ├── mode.go
│   │   ├── path.go
│   │   ├── recovery.go
│   │   ├── render/
│   │   │   ├── data.go
│   │   │   ├── html.go
│   │   │   ├── json.go
│   │   │   ├── reader.go
│   │   │   ├── redirect.go
│   │   │   ├── render.go
│   │   │   ├── text.go
│   │   │   └── xml.go
│   │   ├── response_writer.go
│   │   ├── routergroup.go
│   │   ├── sessions/
│   │   │   ├── context/
│   │   │   │   └── context.go
│   │   │   ├── cookie/
│   │   │   │   └── cookie.go
│   │   │   ├── memstore/
│   │   │   │   ├── cache.go
│   │   │   │   ├── memstore.go
│   │   │   │   └── store.go
│   │   │   ├── securecookie/
│   │   │   │   └── securecookie.go
│   │   │   ├── session_options_go1.10.go
│   │   │   ├── session_options_go1.11.go
│   │   │   ├── sessions/
│   │   │   │   ├── cookie.go
│   │   │   │   ├── cookie_go111.go
│   │   │   │   ├── doc.go
│   │   │   │   ├── lex.go
│   │   │   │   ├── options.go
│   │   │   │   ├── options_go111.go
│   │   │   │   ├── sessions.go
│   │   │   │   └── store.go
│   │   │   └── sessions.go
│   │   ├── sse/
│   │   │   ├── sse-decoder.go
│   │   │   ├── sse-encoder.go
│   │   │   └── writer.go
│   │   ├── tree.go
│   │   ├── utils.go
│   │   ├── validator/
│   │   │   ├── baked_in.go
│   │   │   ├── cache.go
│   │   │   ├── country_codes.go
│   │   │   ├── currency_codes.go
│   │   │   ├── errors.go
│   │   │   ├── field_level.go
│   │   │   ├── options.go
│   │   │   ├── postcode_regexes.go
│   │   │   ├── regexes.go
│   │   │   ├── struct_level.go
│   │   │   ├── util.go
│   │   │   ├── validator.go
│   │   │   └── validator_instance.go
│   │   └── version.go
│   ├── go.mod
│   ├── gorm/
│   │   ├── association.go
│   │   ├── callbacks/
│   │   │   ├── associations.go
│   │   │   ├── callbacks.go
│   │   │   ├── callmethod.go
│   │   │   ├── create.go
│   │   │   ├── delete.go
│   │   │   ├── helper.go
│   │   │   ├── interfaces.go
│   │   │   ├── preload.go
│   │   │   ├── query.go
│   │   │   ├── raw.go
│   │   │   ├── row.go
│   │   │   ├── transaction.go
│   │   │   └── update.go
│   │   ├── callbacks.go
│   │   ├── chainable_api.go
│   │   ├── clause/
│   │   │   ├── clause.go
│   │   │   ├── delete.go
│   │   │   ├── expression.go
│   │   │   ├── from.go
│   │   │   ├── group_by.go
│   │   │   ├── insert.go
│   │   │   ├── joins.go
│   │   │   ├── limit.go
│   │   │   ├── locking.go
│   │   │   ├── on_conflict.go
│   │   │   ├── order_by.go
│   │   │   ├── returning.go
│   │   │   ├── select.go
│   │   │   ├── set.go
│   │   │   ├── update.go
│   │   │   ├── values.go
│   │   │   ├── where.go
│   │   │   └── with.go
│   │   ├── driver/
│   │   │   ├── mysql/
│   │   │   │   ├── error_translator.go
│   │   │   │   ├── migrator.go
│   │   │   │   └── mysql.go
│   │   │   └── pgsql/
│   │   │       ├── error_translator.go
│   │   │       ├── migrator.go
│   │   │       └── postgres.go
│   │   ├── errors.go
│   │   ├── finisher_api.go
│   │   ├── gorm.go
│   │   ├── inflection/
│   │   │   └── inflections.go
│   │   ├── interfaces.go
│   │   ├── logger/
│   │   │   ├── logger.go
│   │   │   └── sql.go
│   │   ├── migrator/
│   │   │   ├── column_type.go
│   │   │   ├── index.go
│   │   │   ├── migrator.go
│   │   │   └── table_type.go
│   │   ├── migrator.go
│   │   ├── model.go
│   │   ├── now/
│   │   │   ├── main.go
│   │   │   ├── now.go
│   │   │   └── time.go
│   │   ├── prepare_stmt.go
│   │   ├── scan.go
│   │   ├── schema/
│   │   │   ├── constraint.go
│   │   │   ├── field.go
│   │   │   ├── index.go
│   │   │   ├── interfaces.go
│   │   │   ├── naming.go
│   │   │   ├── pool.go
│   │   │   ├── relationship.go
│   │   │   ├── schema.go
│   │   │   ├── serializer.go
│   │   │   └── utils.go
│   │   ├── soft_delete.go
│   │   ├── statement.go
│   │   └── utils/
│   │       ├── tests/
│   │       │   ├── dummy_dialecter.go
│   │       │   ├── models.go
│   │       │   └── utils.go
│   │       └── utils.go
│   ├── main.go
│   ├── mysql/
│   │   ├── atomic_bool.go
│   │   ├── atomic_bool_go118.go
│   │   ├── auth.go
│   │   ├── buffer.go
│   │   ├── collations.go
│   │   ├── conncheck.go
│   │   ├── conncheck_dummy.go
│   │   ├── connection.go
│   │   ├── connector.go
│   │   ├── const.go
│   │   ├── driver.go
│   │   ├── dsn.go
│   │   ├── errors.go
│   │   ├── fields.go
│   │   ├── infile.go
│   │   ├── nulltime.go
│   │   ├── packets.go
│   │   ├── result.go
│   │   ├── rows.go
│   │   ├── statement.go
│   │   ├── transaction.go
│   │   └── utils.go
│   ├── pgsql/
│   │   ├── array.go
│   │   ├── buf.go
│   │   ├── conn.go
│   │   ├── conn_go115.go
│   │   ├── conn_go18.go
│   │   ├── connector.go
│   │   ├── copy.go
│   │   ├── encode.go
│   │   ├── error.go
│   │   ├── hstore/
│   │   │   └── hstore.go
│   │   ├── krb.go
│   │   ├── notice.go
│   │   ├── notify.go
│   │   ├── oid/
│   │   │   ├── doc.go
│   │   │   ├── gen.go
│   │   │   └── types.go
│   │   ├── rows.go
│   │   ├── scram/
│   │   │   └── scram.go
│   │   ├── ssl.go
│   │   ├── ssl_permissions.go
│   │   ├── ssl_windows.go
│   │   ├── url.go
│   │   ├── user_other.go
│   │   ├── user_posix.go
│   │   ├── user_windows.go
│   │   └── uuid.go
│   ├── pty/
│   │   ├── asm_solaris_amd64.s
│   │   ├── cmd_windows.go
│   │   ├── doc.go
│   │   ├── ioctl.go
│   │   ├── ioctl_bsd.go
│   │   ├── ioctl_inner.go
│   │   ├── ioctl_legacy.go
│   │   ├── ioctl_solaris.go
│   │   ├── ioctl_unsupported.go
│   │   ├── pty_darwin.go
│   │   ├── pty_dragonfly.go
│   │   ├── pty_freebsd.go
│   │   ├── pty_linux.go
│   │   ├── pty_netbsd.go
│   │   ├── pty_openbsd.go
│   │   ├── pty_solaris.go
│   │   ├── pty_unsupported.go
│   │   ├── pty_windows.go
│   │   ├── run.go
│   │   ├── run_unix.go
│   │   ├── run_windows.go
│   │   ├── types.go
│   │   ├── types_dragonfly.go
│   │   ├── types_freebsd.go
│   │   ├── types_netbsd.go
│   │   ├── types_openbsd.go
│   │   ├── winsize.go
│   │   ├── winsize_unix.go
│   │   ├── winsize_windows.go
│   │   ├── ztypes_386.go
│   │   ├── ztypes_amd64.go
│   │   ├── ztypes_arm.go
│   │   ├── ztypes_arm64.go
│   │   ├── ztypes_dragonfly_amd64.go
│   │   ├── ztypes_freebsd_386.go
│   │   ├── ztypes_freebsd_amd64.go
│   │   ├── ztypes_freebsd_arm.go
│   │   ├── ztypes_freebsd_arm64.go
│   │   ├── ztypes_freebsd_ppc64.go
│   │   ├── ztypes_freebsd_riscv64.go
│   │   ├── ztypes_loong64.go
│   │   ├── ztypes_mipsx.go
│   │   ├── ztypes_netbsd_32bit_int.go
│   │   ├── ztypes_openbsd_32bit_int.go
│   │   ├── ztypes_ppc.go
│   │   ├── ztypes_ppc64.go
│   │   ├── ztypes_ppc64le.go
│   │   ├── ztypes_riscvx.go
│   │   ├── ztypes_s390x.go
│   │   └── ztypes_sparcx.go
│   ├── readme.md
│   ├── sftp/
│   │   ├── allocator.go
│   │   ├── attrs.go
│   │   ├── attrs_stubs.go
│   │   ├── attrs_unix.go
│   │   ├── client.go
│   │   ├── conn.go
│   │   ├── debug.go
│   │   ├── fuzz.go
│   │   ├── internal/
│   │   │   ├── encoding/
│   │   │   │   └── ssh/
│   │   │   │       └── filexfer/
│   │   │   │           ├── attrs.go
│   │   │   │           ├── buffer.go
│   │   │   │           ├── extended_packets.go
│   │   │   │           ├── extensions.go
│   │   │   │           ├── filexfer.go
│   │   │   │           ├── fx.go
│   │   │   │           ├── fxp.go
│   │   │   │           ├── handle_packets.go
│   │   │   │           ├── init_packets.go
│   │   │   │           ├── open_packets.go
│   │   │   │           ├── openssh/
│   │   │   │           │   ├── fsync.go
│   │   │   │           │   ├── hardlink.go
│   │   │   │           │   ├── openssh.go
│   │   │   │           │   ├── posix-rename.go
│   │   │   │           │   └── statvfs.go
│   │   │   │           ├── packets.go
│   │   │   │           ├── path_packets.go
│   │   │   │           ├── permissions.go
│   │   │   │           └── response_packets.go
│   │   │   └── sftpfs/
│   │   │       ├── filesystem.go
│   │   │       └── walk.go
│   │   ├── ls_formatting.go
│   │   ├── ls_plan9.go
│   │   ├── ls_stub.go
│   │   ├── ls_unix.go
│   │   ├── match.go
│   │   ├── packet-manager.go
│   │   ├── packet-typing.go
│   │   ├── packet.go
│   │   ├── pool.go
│   │   ├── release.go
│   │   ├── request-attrs.go
│   │   ├── request-errors.go
│   │   ├── request-example.go
│   │   ├── request-interfaces.go
│   │   ├── request-plan9.go
│   │   ├── request-server.go
│   │   ├── request-unix.go
│   │   ├── request.go
│   │   ├── request_windows.go
│   │   ├── server.go
│   │   ├── server_plan9.go
│   │   ├── server_statvfs_darwin.go
│   │   ├── server_statvfs_impl.go
│   │   ├── server_statvfs_linux.go
│   │   ├── server_statvfs_plan9.go
│   │   ├── server_statvfs_stubs.go
│   │   ├── server_unix.go
│   │   ├── server_windows.go
│   │   ├── sftp.go
│   │   ├── stat_plan9.go
│   │   ├── stat_posix.go
│   │   ├── syscall_fixed.go
│   │   └── syscall_good.go
│   ├── sqlite/
│   │   ├── ddlmod.go
│   │   ├── errors.go
│   │   ├── migrator.go
│   │   └── sqlite.go
│   ├── sys/
│   │   ├── cpu/
│   │   │   ├── asm_aix_ppc64.s
│   │   │   ├── byteorder.go
│   │   │   ├── cpu.go
│   │   │   ├── cpu_aix.go
│   │   │   ├── cpu_arm.go
│   │   │   ├── cpu_arm64.go
│   │   │   ├── cpu_arm64.s
│   │   │   ├── cpu_gc_arm64.go
│   │   │   ├── cpu_gc_s390x.go
│   │   │   ├── cpu_gc_x86.go
│   │   │   ├── 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_mips64x.go
│   │   │   ├── cpu_linux_noinit.go
│   │   │   ├── cpu_linux_ppc64x.go
│   │   │   ├── cpu_linux_s390x.go
│   │   │   ├── cpu_loong64.go
│   │   │   ├── 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_ppc64x.go
│   │   │   ├── cpu_riscv64.go
│   │   │   ├── cpu_s390x.go
│   │   │   ├── cpu_s390x.s
│   │   │   ├── cpu_wasm.go
│   │   │   ├── cpu_x86.go
│   │   │   ├── cpu_x86.s
│   │   │   ├── 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
│   │   ├── execabs/
│   │   │   ├── execabs.go
│   │   │   ├── execabs_go118.go
│   │   │   └── execabs_go119.go
│   │   ├── plan9/
│   │   │   ├── asm.s
│   │   │   ├── asm_plan9_386.s
│   │   │   ├── asm_plan9_amd64.s
│   │   │   ├── asm_plan9_arm.s
│   │   │   ├── const_plan9.go
│   │   │   ├── dir_plan9.go
│   │   │   ├── env_plan9.go
│   │   │   ├── errors_plan9.go
│   │   │   ├── mkall.sh
│   │   │   ├── mkerrors.sh
│   │   │   ├── mksyscall.go
│   │   │   ├── mksysnum_plan9.sh
│   │   │   ├── pwd_go15_plan9.go
│   │   │   ├── pwd_plan9.go
│   │   │   ├── race.go
│   │   │   ├── race0.go
│   │   │   ├── str.go
│   │   │   ├── syscall.go
│   │   │   ├── syscall_plan9.go
│   │   │   ├── zsyscall_plan9_386.go
│   │   │   ├── zsyscall_plan9_amd64.go
│   │   │   ├── zsyscall_plan9_arm.go
│   │   │   └── zsysnum_plan9.go
│   │   ├── unix/
│   │   │   ├── 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
│   │   │   ├── bluetooth_linux.go
│   │   │   ├── 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
│   │   │   ├── epoll_zos.go
│   │   │   ├── fcntl.go
│   │   │   ├── fcntl_darwin.go
│   │   │   ├── fcntl_linux_32bit.go
│   │   │   ├── fdset.go
│   │   │   ├── fstatfs_zos.go
│   │   │   ├── gccgo.go
│   │   │   ├── gccgo_c.c
│   │   │   ├── gccgo_linux_amd64.go
│   │   │   ├── ifreq_linux.go
│   │   │   ├── internal/
│   │   │   │   └── mkmerge/
│   │   │   │       └── mkmerge.go
│   │   │   ├── ioctl_linux.go
│   │   │   ├── ioctl_signed.go
│   │   │   ├── ioctl_unsigned.go
│   │   │   ├── ioctl_zos.go
│   │   │   ├── linux/
│   │   │   │   ├── Dockerfile
│   │   │   │   ├── mkall.go
│   │   │   │   ├── mksysnum.go
│   │   │   │   └── types.go
│   │   │   ├── mkall.sh
│   │   │   ├── mkasm.go
│   │   │   ├── mkerrors.sh
│   │   │   ├── mkpost.go
│   │   │   ├── mksyscall.go
│   │   │   ├── mksyscall_aix_ppc.go
│   │   │   ├── mksyscall_aix_ppc64.go
│   │   │   ├── mksyscall_solaris.go
│   │   │   ├── mksysctl_openbsd.go
│   │   │   ├── mksysnum.go
│   │   │   ├── 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
│   │   │   ├── 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
│   │   │   ├── types_aix.go
│   │   │   ├── types_darwin.go
│   │   │   ├── types_dragonfly.go
│   │   │   ├── types_freebsd.go
│   │   │   ├── types_netbsd.go
│   │   │   ├── types_openbsd.go
│   │   │   ├── types_solaris.go
│   │   │   ├── unveil_openbsd.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
│   │   │   ├── 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
│   │   ├── websocket/
│   │   │   ├── client.go
│   │   │   ├── dial.go
│   │   │   ├── hybi.go
│   │   │   ├── server.go
│   │   │   └── websocket.go
│   │   └── windows/
│   │       ├── aliases.go
│   │       ├── dll_windows.go
│   │       ├── empty.s
│   │       ├── env_windows.go
│   │       ├── eventlog.go
│   │       ├── exec_windows.go
│   │       ├── memory_windows.go
│   │       ├── mkerrors.bash
│   │       ├── mkknownfolderids.bash
│   │       ├── mksyscall.go
│   │       ├── mkwinsyscall/
│   │       │   └── mkwinsyscall.go
│   │       ├── race.go
│   │       ├── race0.go
│   │       ├── registry/
│   │       │   ├── key.go
│   │       │   ├── mksyscall.go
│   │       │   ├── syscall.go
│   │       │   ├── value.go
│   │       │   └── zsyscall_windows.go
│   │       ├── security_windows.go
│   │       ├── service.go
│   │       ├── setupapi_windows.go
│   │       ├── str.go
│   │       ├── svc/
│   │       │   ├── debug/
│   │       │   │   ├── log.go
│   │       │   │   └── service.go
│   │       │   ├── eventlog/
│   │       │   │   ├── install.go
│   │       │   │   └── log.go
│   │       │   ├── mgr/
│   │       │   │   ├── config.go
│   │       │   │   ├── mgr.go
│   │       │   │   ├── recovery.go
│   │       │   │   └── service.go
│   │       │   ├── security.go
│   │       │   └── service.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
│   ├── term/
│   │   ├── term.go
│   │   ├── term_plan9.go
│   │   ├── term_unix.go
│   │   ├── term_unix_bsd.go
│   │   ├── term_unix_other.go
│   │   ├── term_unsupported.go
│   │   ├── term_windows.go
│   │   └── terminal.go
│   ├── toml/
│   │   ├── README.md
│   │   ├── decode.go
│   │   ├── errors.go
│   │   ├── internal/
│   │   │   ├── characters/
│   │   │   │   ├── ascii.go
│   │   │   │   └── utf8.go
│   │   │   ├── cli/
│   │   │   │   └── cli.go
│   │   │   ├── danger/
│   │   │   │   ├── danger.go
│   │   │   │   └── typeid.go
│   │   │   ├── testsuite/
│   │   │   │   ├── add.go
│   │   │   │   ├── json.go
│   │   │   │   ├── parser.go
│   │   │   │   ├── rm.go
│   │   │   │   └── testsuite.go
│   │   │   └── tracker/
│   │   │       ├── key.go
│   │   │       ├── seen.go
│   │   │       └── tracker.go
│   │   ├── localtime.go
│   │   ├── marshaler.go
│   │   ├── strict.go
│   │   ├── types.go
│   │   ├── unmarshaler.go
│   │   └── unstable/
│   │       ├── ast.go
│   │       ├── builder.go
│   │       ├── doc.go
│   │       ├── kind.go
│   │       ├── parser.go
│   │       ├── scanner.go
│   │       └── unmarshaler.go
│   ├── webroot/
│   │   ├── assets/
│   │   │   ├── About-BpAaEtx1.js
│   │   │   ├── About-CLFeE-IU.css
│   │   │   ├── Manage-BTEK3ejV.css
│   │   │   ├── Manage-D_HsZWaT.js
│   │   │   ├── NotFound-Ts0Rt7lc.js
│   │   │   ├── SysInit-Lho0-Z3X.css
│   │   │   ├── SysInit-UcmoR0-x.js
│   │   │   ├── el-card-fwQOLwdi.css
│   │   │   ├── index-D6GWZ696.css
│   │   │   └── index-jH42E5tC.js
│   │   ├── index.html
│   │   └── readme.md
│   └── websocket/
│       ├── client.go
│       ├── compression.go
│       ├── conn.go
│       ├── doc.go
│       ├── join.go
│       ├── json.go
│       ├── mask.go
│       ├── mask_safe.go
│       ├── prepared.go
│       ├── proxy.go
│       ├── server.go
│       └── util.go
├── postman.json
├── sshd.dockerfile
└── webssh/
    ├── .gitignore
    ├── README.md
    ├── auto-imports.d.ts
    ├── components.d.ts
    ├── env.d.ts
    ├── index.html
    ├── package.json
    ├── src/
    │   ├── App.vue
    │   ├── components/
    │   │   ├── Account.vue
    │   │   ├── Connect.vue
    │   │   ├── LoginAudit.vue
    │   │   ├── NetFilter.vue
    │   │   ├── SshdCert.vue
    │   │   └── SshdUser.vue
    │   ├── main.ts
    │   ├── router/
    │   │   └── index.ts
    │   ├── stores/
    │   │   └── store.ts
    │   └── views/
    │       ├── About.vue
    │       ├── Empty.vue
    │       ├── Home.vue
    │       ├── Login.vue
    │       ├── Manage.vue
    │       ├── NotFound.vue
    │       └── SysInit.vue
    ├── tsconfig.app.json
    ├── tsconfig.json
    ├── tsconfig.node.json
    └── vite.config.ts
Download .txt
Showing preview only (9,216K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (107986 symbols across 865 files)

FILE: gossh/app/config/config.go
  type AppConfig (line 13) | type AppConfig struct
    method write (line 31) | func (c *AppConfig) write() error {
  function InitConfig (line 77) | func InitConfig() {
  function RewriteConfig (line 144) | func RewriteConfig(conf AppConfig) error {

FILE: gossh/app/middleware/db_check.go
  function DbCheck (line 9) | func DbCheck() gin.HandlerFunc {

FILE: gossh/app/middleware/jwt_auth.go
  type JwtClaims (line 15) | type JwtClaims struct
  function GenerateToken (line 24) | func GenerateToken(id uint) (string, error) {
  function ParseToken (line 46) | func ParseToken(tokenString string) (*JwtClaims, error) {
  function RenewToken (line 55) | func RenewToken(claims *JwtClaims) (string, error) {
  function withinLimit (line 64) | func withinLimit(s, l int64) bool {
  function JWTAuth (line 68) | func JWTAuth() gin.HandlerFunc {

FILE: gossh/app/middleware/net_filter.go
  function check (line 12) | func check(ip net.IP) bool {
  function NetFilter (line 67) | func NetFilter() gin.HandlerFunc {

FILE: gossh/app/middleware/perm_check.go
  function PremCheck (line 83) | func PremCheck(engine *gin.Engine) gin.HandlerFunc {

FILE: gossh/app/middleware/sys_init.go
  function SysInit (line 8) | func SysInit() gin.HandlerFunc {

FILE: gossh/app/model/cmd_note.go
  type CmdNote (line 3) | type CmdNote struct
    method Create (line 13) | func (c CmdNote) Create(cmd *CmdNote) error {
    method FindByName (line 17) | func (c CmdNote) FindByName(name string) (CmdNote, error) {
    method FindByID (line 23) | func (c CmdNote) FindByID(id uint, uid uint) (CmdNote, error) {
    method FindAll (line 29) | func (c CmdNote) FindAll(offset, limit int, uid uint) ([]CmdNote, erro...
    method UpdateById (line 35) | func (c CmdNote) UpdateById(id, uid uint, cmd *CmdNote) error {
    method DeleteByID (line 39) | func (c CmdNote) DeleteByID(id, uid uint) error {

FILE: gossh/app/model/datetime.go
  constant TimeFormat (line 10) | TimeFormat = "2006-01-02 15:04:05"
  type DateTime (line 13) | type DateTime
    method MarshalJSON (line 24) | func (t DateTime) MarshalJSON() ([]byte, error) {
    method UnmarshalJSON (line 28) | func (t *DateTime) UnmarshalJSON(b []byte) error {
    method Value (line 36) | func (t DateTime) Value() (driver.Value, error) {
    method Scan (line 43) | func (t *DateTime) Scan(v any) error {
    method ToTime (line 52) | func (t *DateTime) ToTime() time.Time {
    method String (line 56) | func (t DateTime) String() string {
  function NewDateTime (line 15) | func NewDateTime(str string) (DateTime, error) {

FILE: gossh/app/model/db_init.go
  function InitDatabase (line 22) | func InitDatabase() {
  function GetSqliteDb (line 33) | func GetSqliteDb(dsn string) (*gorm.DB, error) {
  function DbMigrate (line 63) | func DbMigrate(dbType, dsn string) error {

FILE: gossh/app/model/login_audit.go
  type LoginAudit (line 3) | type LoginAudit struct
    method Create (line 17) | func (c LoginAudit) Create(audit *LoginAudit) error {
    method Search (line 21) | func (c LoginAudit) Search(
    method FindByID (line 48) | func (c LoginAudit) FindByID(id uint) (LoginAudit, error) {
    method DeleteByID (line 54) | func (c LoginAudit) DeleteByID(id uint) error {

FILE: gossh/app/model/net_filter.go
  type NetFilter (line 5) | type NetFilter struct
    method Create (line 17) | func (c NetFilter) Create(filter *NetFilter) error {
    method FindByName (line 21) | func (c NetFilter) FindByName(name string) (NetFilter, error) {
    method FindByID (line 27) | func (c NetFilter) FindByID(id uint) (NetFilter, error) {
    method FindAll (line 33) | func (c NetFilter) FindAll(offset, limit int) ([]NetFilter, error) {
    method FindAllPolicy (line 39) | func (c NetFilter) FindAllPolicy(policy string) ([]NetFilter, error) {
    method UpdateById (line 45) | func (c NetFilter) UpdateById(id uint, filter *NetFilter) error {
    method DeleteByID (line 49) | func (c NetFilter) DeleteByID(id uint) error {

FILE: gossh/app/model/policy_conf.go
  type PolicyConf (line 3) | type PolicyConf struct
    method Create (line 11) | func (c PolicyConf) Create(conf *PolicyConf) error {
    method FindByID (line 15) | func (c PolicyConf) FindByID(id uint) (PolicyConf, error) {
    method FindAll (line 21) | func (c PolicyConf) FindAll(offset, limit int) ([]PolicyConf, error) {
    method UpdateById (line 27) | func (c PolicyConf) UpdateById(id uint, conf *PolicyConf) error {
    method DeleteByID (line 31) | func (c PolicyConf) DeleteByID(id uint) error {

FILE: gossh/app/model/ssh_conf.go
  type SshConf (line 10) | type SshConf struct
    method Create (line 37) | func (c *SshConf) Create(conf *SshConf) error {
    method FindByID (line 41) | func (c *SshConf) FindByID(id uint, uid uint) (SshConf, error) {
    method FindAll (line 47) | func (c *SshConf) FindAll(offset, limit int, uid uint) ([]SshConf, err...
    method UpdateById (line 53) | func (_ *SshConf) UpdateById(id, uid uint, conf *SshConf) error {
    method DeleteByID (line 57) | func (c *SshConf) DeleteByID(id, uid uint) error {
    method BeforeCreate (line 62) | func (c *SshConf) BeforeCreate(_ *gorm.DB) error {
    method BeforeUpdate (line 68) | func (c *SshConf) BeforeUpdate(_ *gorm.DB) error {
    method AfterFind (line 74) | func (c *SshConf) AfterFind(_ *gorm.DB) error {
    method sshConfEncrypt (line 91) | func (c *SshConf) sshConfEncrypt() (*SshConf, error) {

FILE: gossh/app/model/sshd_cert.go
  type SshdCert (line 5) | type SshdCert struct
    method Create (line 17) | func (c *SshdCert) Create(user *SshdCert) error {
    method FindByName (line 21) | func (c *SshdCert) FindByName(name string) (SshdCert, error) {
    method FindByID (line 27) | func (c *SshdCert) FindByID(id uint) (SshdCert, error) {
    method FindAll (line 33) | func (c *SshdCert) FindAll(limit, offset int) ([]SshdCert, error) {
    method GetAuthorizedKeys (line 39) | func (c *SshdCert) GetAuthorizedKeys() (string, error) {
    method UpdateById (line 53) | func (c *SshdCert) UpdateById(id uint, user *SshdCert) error {
    method DeleteByID (line 57) | func (c *SshdCert) DeleteByID(id uint) error {

FILE: gossh/app/model/sshd_conf.go
  type SshdConf (line 9) | type SshdConf struct
    method Create (line 25) | func (c *SshdConf) Create(conf *SshdConf) error {
    method FindByName (line 29) | func (c *SshdConf) FindByName(name string) (SshdConf, error) {
    method FindByID (line 35) | func (c *SshdConf) FindByID(id uint) (SshdConf, error) {
    method UpdateByName (line 41) | func (c *SshdConf) UpdateByName(name string, conf *SshdConf) error {
    method DeleteByName (line 45) | func (c *SshdConf) DeleteByName(name string) error {
    method BeforeCreate (line 50) | func (c *SshdConf) BeforeCreate(_ *gorm.DB) error {
    method BeforeUpdate (line 57) | func (c *SshdConf) BeforeUpdate(_ *gorm.DB) error {
    method AfterFind (line 64) | func (c *SshdConf) AfterFind(_ *gorm.DB) error {

FILE: gossh/app/model/sshd_user.go
  type SshdUser (line 12) | type SshdUser struct
    method Create (line 25) | func (c *SshdUser) Create(user *SshdUser) error {
    method FindByNameAndPwd (line 29) | func (c *SshdUser) FindByNameAndPwd(name, pwd string) (SshdUser, error) {
    method FindByName (line 45) | func (c *SshdUser) FindByName(name string) (SshdUser, error) {
    method FindByID (line 51) | func (c *SshdUser) FindByID(id uint) (SshdUser, error) {
    method FindAll (line 57) | func (c *SshdUser) FindAll(limit, offset int) ([]SshdUser, error) {
    method UpdateById (line 63) | func (c *SshdUser) UpdateById(id uint, user *SshdUser) error {
    method DeleteByID (line 67) | func (c *SshdUser) DeleteByID(id uint) error {
    method BeforeCreate (line 72) | func (c *SshdUser) BeforeCreate(_ *gorm.DB) error {
    method BeforeUpdate (line 79) | func (c *SshdUser) BeforeUpdate(_ *gorm.DB) error {
    method AfterFind (line 86) | func (c *SshdUser) AfterFind(_ *gorm.DB) error {

FILE: gossh/app/model/web_user.go
  type WebUser (line 10) | type WebUser struct
    method Create (line 24) | func (c *WebUser) Create(user *WebUser) error {
    method FindByNameAndPwd (line 28) | func (c *WebUser) FindByNameAndPwd(name, pwd string) (WebUser, error) {
    method FindByName (line 40) | func (c *WebUser) FindByName(name string) (WebUser, error) {
    method FindByID (line 46) | func (c *WebUser) FindByID(id uint) (WebUser, error) {
    method FindAll (line 52) | func (c *WebUser) FindAll(limit, offset int) ([]WebUser, error) {
    method UpdateById (line 58) | func (c *WebUser) UpdateById(id uint, user *WebUser) error {
    method UpdatePassword (line 62) | func (c *WebUser) UpdatePassword(id uint, user *WebUser) error {
    method DeleteByID (line 66) | func (c *WebUser) DeleteByID(id uint) error {
    method BeforeCreate (line 71) | func (c *WebUser) BeforeCreate(_ *gorm.DB) error {
    method BeforeUpdate (line 78) | func (c *WebUser) BeforeUpdate(_ *gorm.DB) error {
    method AfterFind (line 85) | func (c *WebUser) AfterFind(_ *gorm.DB) error {

FILE: gossh/app/service/cmd_note.go
  function CmdNoteCreate (line 9) | func CmdNoteCreate(c *gin.Context) {
  function CmdNoteFindByID (line 24) | func CmdNoteFindByID(c *gin.Context) {
  function CmdNoteFindAll (line 39) | func CmdNoteFindAll(c *gin.Context) {
  function CmdNoteUpdateById (line 60) | func CmdNoteUpdateById(c *gin.Context) {
  function CmdNoteDeleteById (line 74) | func CmdNoteDeleteById(c *gin.Context) {

FILE: gossh/app/service/db_conn.go
  type DbConnConf (line 15) | type DbConnConf struct
  function DbConnCheck (line 20) | func DbConnCheck(c *gin.Context) {
  function DbConnTestCheck (line 39) | func DbConnTestCheck(dbConf DbConnConf) error {

FILE: gossh/app/service/login_audit.go
  function AuditFindByID (line 9) | func AuditFindByID(c *gin.Context) {
  function LoginAuditSearch (line 24) | func LoginAuditSearch(c *gin.Context) {
  function LoginAuditDeleteById (line 51) | func LoginAuditDeleteById(c *gin.Context) {

FILE: gossh/app/service/net_filter.go
  function NetFilterCreate (line 9) | func NetFilterCreate(c *gin.Context) {
  function NetFilterFindByID (line 24) | func NetFilterFindByID(c *gin.Context) {
  function NetFilterFindAll (line 39) | func NetFilterFindAll(c *gin.Context) {
  function NetFilterUpdateById (line 61) | func NetFilterUpdateById(c *gin.Context) {
  function NetFilterDeleteById (line 75) | func NetFilterDeleteById(c *gin.Context) {

FILE: gossh/app/service/policy_conf.go
  function PolicyConfCreate (line 9) | func PolicyConfCreate(c *gin.Context) {
  function PolicyConfFindByID (line 24) | func PolicyConfFindByID(c *gin.Context) {
  function PolicyConfFindAll (line 39) | func PolicyConfFindAll(c *gin.Context) {
  function PolicyConfUpdateById (line 61) | func PolicyConfUpdateById(c *gin.Context) {
  function PolicyConfDeleteById (line 81) | func PolicyConfDeleteById(c *gin.Context) {

FILE: gossh/app/service/service_init.go
  function DeleteOnlineClient (line 14) | func DeleteOnlineClient(sessionId string) {
  function cleanNoActiveSession (line 82) | func cleanNoActiveSession() {
  function initApp (line 103) | func initApp() {
  function InitSessionClean (line 118) | func InitSessionClean() {

FILE: gossh/app/service/ssh_conf.go
  function ConfCreate (line 9) | func ConfCreate(c *gin.Context) {
  function ConfFindByID (line 24) | func ConfFindByID(c *gin.Context) {
  function ConfFindAll (line 39) | func ConfFindAll(c *gin.Context) {
  function ConfUpdateById (line 60) | func ConfUpdateById(c *gin.Context) {
  function ConfDeleteById (line 75) | func ConfDeleteById(c *gin.Context) {

FILE: gossh/app/service/ssh_conn.go
  type SshConn (line 20) | type SshConn struct
    method MarshalJSON (line 49) | func (s *SshConn) MarshalJSON() ([]byte, error) {
    method connect (line 75) | func (s *SshConn) connect(clientIp string) error {
    method RunTerminal (line 151) | func (s *SshConn) RunTerminal(shell string, stdout, stderr io.Writer, ...
    method ResizeWindow (line 189) | func (s *SshConn) ResizeWindow(c *gin.Context) {
  function ResizeWindow (line 234) | func ResizeWindow(c *gin.Context) {
  function NewSshConn (line 239) | func NewSshConn(c *gin.Context) {
  type WebSocketReadWriter (line 320) | type WebSocketReadWriter struct
    method Read (line 324) | func (w *WebSocketReadWriter) Read(p []byte) (n int, err error) {
    method Write (line 333) | func (w *WebSocketReadWriter) Write(p []byte) (n int, err error) {
  function CreateSessionId (line 341) | func CreateSessionId(c *gin.Context) {
  function Disconnect (line 369) | func Disconnect(c *gin.Context) {
  function ExecCommand (line 394) | func ExecCommand(c *gin.Context) {

FILE: gossh/app/service/ssh_sftp.go
  function getSshConn (line 16) | func getSshConn(sessionId string) (*SshConn, error) {
  function SftpList (line 31) | func SftpList(c *gin.Context) {
  function SftpDownLoad (line 112) | func SftpDownLoad(c *gin.Context) {
  function SftpUpload (line 164) | func SftpUpload(c *gin.Context) {
  function SftpDelete (line 214) | func SftpDelete(c *gin.Context) {
  function SftpCreateDir (line 250) | func SftpCreateDir(c *gin.Context) {

FILE: gossh/app/service/ssh_status.go
  type SshConnById (line 12) | type SshConnById
    method Len (line 14) | func (a SshConnById) Len() int           { return len(a) }
    method Swap (line 15) | func (a SshConnById) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
    method Less (line 16) | func (a SshConnById) Less(i, j int) bool { return a[i].SessionId < a[j...
  function GetOnlineClient (line 18) | func GetOnlineClient(c *gin.Context) {
  function RefreshConnTime (line 55) | func RefreshConnTime(c *gin.Context) {

FILE: gossh/app/service/sshd_cert.go
  function SshdCertCreate (line 10) | func SshdCertCreate(c *gin.Context) {
  function CheckSshdCertNameExists (line 27) | func CheckSshdCertNameExists(c *gin.Context) {
  function SshdCertFindByID (line 54) | func SshdCertFindByID(c *gin.Context) {
  function SshdCertFindAll (line 72) | func SshdCertFindAll(c *gin.Context) {
  function SshdCertUpdateById (line 97) | func SshdCertUpdateById(c *gin.Context) {
  function SshdCertDeleteById (line 114) | func SshdCertDeleteById(c *gin.Context) {
  function GetSshdCertAuthorizedKeys (line 132) | func GetSshdCertAuthorizedKeys(c *gin.Context) {

FILE: gossh/app/service/sshd_server.go
  type Server (line 33) | type Server struct
    method Start (line 48) | func (s *Server) Start() error {
    method handleConn (line 64) | func (s *Server) handleConn(tcpConn net.Conn) {
    method handleChannels (line 83) | func (s *Server) handleChannels(chans <-chan ssh.NewChannel) {
    method handleChannel (line 90) | func (s *Server) handleChannel(newChannel ssh.NewChannel) {
    method handleRequests (line 110) | func (s *Server) handleRequests(connection ssh.Channel, requests <-cha...
    method keepAlive (line 194) | func (s *Server) keepAlive(connection ssh.Channel, interval time.Durat...
    method attachShell (line 216) | func (s *Server) attachShell(connection ssh.Channel, env []string, res...
    method loadCertAuthFile (line 276) | func (s *Server) loadCertAuthFile() (map[string]string, error) {
    method computeSSHConfig (line 292) | func (s *Server) computeSSHConfig() (*ssh.ServerConfig, error) {
    method matchKeys (line 358) | func (s *Server) matchKeys(key ssh.PublicKey, keys map[string]string) ...
  function NewServer (line 38) | func NewServer(c *model.SshdConf) (*Server, error) {
  function appendEnv (line 367) | func appendEnv(env []string, kv string) []string {
  function parseDims (line 380) | func parseDims(b []byte) (uint32, uint32) {
  function SetWindowSize (line 387) | func SetWindowSize(t pty.Pty, w, h uint32) {
  function generateKey (line 392) | func generateKey(seed string) ([]byte, error) {
  function parseKeys (line 411) | func parseKeys(b []byte) (map[string]string, error) {
  function fingerprint (line 427) | func fingerprint(k ssh.PublicKey) string {
  function newDetermRand (line 436) | func newDetermRand(seed []byte) io.Reader {
  type determRand (line 450) | type determRand struct
    method Read (line 454) | func (d *determRand) Read(b []byte) (int, error) {
  function hash (line 469) | func hash(input []byte) (next []byte, output []byte) {
  function ExecuteForChannel (line 475) | func ExecuteForChannel(shellCmd string, ch ssh.Channel) uint32 {
  function startSshServer (line 541) | func startSshServer() {
  function InitSshServer (line 569) | func InitSshServer() {

FILE: gossh/app/service/sshd_user.go
  function SshdUserCreate (line 10) | func SshdUserCreate(c *gin.Context) {
  function CheckSshdUserNameExists (line 27) | func CheckSshdUserNameExists(c *gin.Context) {
  function SshdUserFindByID (line 54) | func SshdUserFindByID(c *gin.Context) {
  function SshdUserFindAll (line 72) | func SshdUserFindAll(c *gin.Context) {
  function SshdUserUpdateById (line 97) | func SshdUserUpdateById(c *gin.Context) {
  function SshdUserDeleteById (line 114) | func SshdUserDeleteById(c *gin.Context) {

FILE: gossh/app/service/sys_init.go
  function GetRunConf (line 12) | func GetRunConf(c *gin.Context) {
  function SetRunConf (line 16) | func SetRunConf(c *gin.Context) {
  function GetIsInit (line 34) | func GetIsInit(c *gin.Context) {
  type InitConfig (line 42) | type InitConfig struct
  function SysInit (line 54) | func SysInit(c *gin.Context) {

FILE: gossh/app/service/web_user.go
  function UserCreate (line 15) | func UserCreate(c *gin.Context) {
  function ModifyPasswd (line 33) | func ModifyPasswd(c *gin.Context) {
  function CheckUserNameExists (line 65) | func CheckUserNameExists(c *gin.Context) {
  function UserFindByID (line 92) | func UserFindByID(c *gin.Context) {
  function UserFindAll (line 109) | func UserFindAll(c *gin.Context) {
  function UserUpdateById (line 134) | func UserUpdateById(c *gin.Context) {
  function UserDeleteById (line 168) | func UserDeleteById(c *gin.Context) {
  function UserLogin (line 198) | func UserLogin(c *gin.Context) {

FILE: gossh/app/utils/crypto.go
  function AesEncrypt (line 16) | func AesEncrypt(orig string, key string) (string, error) {
  function AesDecrypt (line 55) | func AesDecrypt(crypt string, key string) (string, error) {
  function EncryptString (line 94) | func EncryptString(plaintext, key string) (string, error) {
  function DecryptString (line 133) | func DecryptString(encrypted, key string) (string, error) {

FILE: gossh/app/utils/utils.go
  function RandString (line 10) | func RandString(length int) string {
  function TruncateString (line 21) | func TruncateString(s string, length int) string {

FILE: gossh/crypto/blowfish/block.go
  function getNextWord (line 9) | func getNextWord(b []byte, pos *int) uint32 {
  function ExpandKey (line 28) | func ExpandKey(key []byte, c *Cipher) {
  function expandKeyWithSalt (line 71) | func expandKeyWithSalt(key []byte, salt []byte, c *Cipher) {
  function encryptBlock (line 115) | func encryptBlock(l, r uint32, c *Cipher) (uint32, uint32) {
  function decryptBlock (line 138) | func decryptBlock(l, r uint32, c *Cipher) (uint32, uint32) {

FILE: gossh/crypto/blowfish/cipher.go
  constant BlockSize (line 22) | BlockSize = 8
  type Cipher (line 25) | type Cipher struct
    method BlockSize (line 68) | func (c *Cipher) BlockSize() int { return BlockSize }
    method Encrypt (line 75) | func (c *Cipher) Encrypt(dst, src []byte) {
    method Decrypt (line 85) | func (c *Cipher) Decrypt(dst, src []byte) {
  type KeySizeError (line 30) | type KeySizeError
    method Error (line 32) | func (k KeySizeError) Error() string {
  function NewCipher (line 38) | func NewCipher(key []byte) (*Cipher, error) {
  function NewSaltedCipher (line 52) | func NewSaltedCipher(key, salt []byte) (*Cipher, error) {
  function initCipher (line 93) | func initCipher(c *Cipher) {

FILE: gossh/crypto/chacha20/chacha_arm64.go
  constant bufSize (line 9) | bufSize = 256
  function xorKeyStreamVX (line 12) | func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, c...
  method xorKeyStreamBlocks (line 14) | func (c *Cipher) xorKeyStreamBlocks(dst, src []byte) {

FILE: gossh/crypto/chacha20/chacha_generic.go
  constant KeySize (line 20) | KeySize = 32
  constant NonceSize (line 27) | NonceSize = 12
  constant NonceSizeX (line 31) | NonceSizeX = 24
  type Cipher (line 36) | type Cipher struct
    method SetCounter (line 152) | func (s *Cipher) SetCounter(counter uint32) {
    method XORKeyStream (line 184) | func (s *Cipher) XORKeyStream(dst, src []byte) {
    method xorKeyStreamBlocksGeneric (line 256) | func (s *Cipher) xorKeyStreamBlocksGeneric(dst, src []byte) {
  function NewUnauthenticatedCipher (line 72) | func NewUnauthenticatedCipher(key, nonce []byte) (*Cipher, error) {
  function newUnauthenticatedCipher (line 80) | func newUnauthenticatedCipher(c *Cipher, key, nonce []byte) (*Cipher, er...
  constant j0 (line 117) | j0 uint32 = 0x61707865
  constant j1 (line 118) | j1 uint32 = 0x3320646e
  constant j2 (line 119) | j2 uint32 = 0x79622d32
  constant j3 (line 120) | j3 uint32 = 0x6b206574
  constant blockSize (line 123) | blockSize = 64
  function quarterRound (line 128) | func quarterRound(a, b, c, d uint32) (uint32, uint32, uint32, uint32) {
  function HChaCha20 (line 344) | func HChaCha20(key, nonce []byte) ([]byte, error) {
  function hChaCha20 (line 352) | func hChaCha20(out, key, nonce []byte) ([]byte, error) {

FILE: gossh/crypto/chacha20/chacha_noasm.go
  constant bufSize (line 9) | bufSize = blockSize
  method xorKeyStreamBlocks (line 11) | func (s *Cipher) xorKeyStreamBlocks(dst, src []byte) {

FILE: gossh/crypto/chacha20/chacha_ppc64le.go
  constant bufSize (line 9) | bufSize = 256
  function chaCha20_ctr32_vsx (line 12) | func chaCha20_ctr32_vsx(out, inp *byte, len int, key *[8]uint32, counter...
  method xorKeyStreamBlocks (line 14) | func (c *Cipher) xorKeyStreamBlocks(dst, src []byte) {

FILE: gossh/crypto/chacha20/chacha_s390x.go
  constant bufSize (line 13) | bufSize = 256
  function xorKeyStreamVX (line 19) | func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, c...
  method xorKeyStreamBlocks (line 21) | func (c *Cipher) xorKeyStreamBlocks(dst, src []byte) {

FILE: gossh/crypto/chacha20/xor.go
  constant unaligned (line 10) | unaligned = runtime.GOARCH == "386" ||
  function addXor (line 18) | func addXor(dst, src []byte, a, b uint32) {

FILE: gossh/crypto/chacha20poly1305/chacha20poly1305.go
  constant KeySize (line 17) | KeySize = 32
  constant NonceSize (line 24) | NonceSize = 12
  constant NonceSizeX (line 28) | NonceSizeX = 24
  constant Overhead (line 32) | Overhead = 16
  type chacha20poly1305 (line 35) | type chacha20poly1305 struct
    method NonceSize (line 49) | func (c *chacha20poly1305) NonceSize() int {
    method Overhead (line 53) | func (c *chacha20poly1305) Overhead() int {
    method Seal (line 57) | func (c *chacha20poly1305) Seal(dst, nonce, plaintext, additionalData ...
    method Open (line 71) | func (c *chacha20poly1305) Open(dst, nonce, ciphertext, additionalData...
  function New (line 40) | func New(key []byte) (cipher.AEAD, error) {
  function sliceForAppend (line 89) | func sliceForAppend(in []byte, n int) (head, tail []byte) {

FILE: gossh/crypto/chacha20poly1305/chacha20poly1305_amd64.go
  function chacha20Poly1305Open (line 17) | func chacha20Poly1305Open(dst []byte, key []uint32, src, ad []byte) bool
  function chacha20Poly1305Seal (line 20) | func chacha20Poly1305Seal(dst []byte, key []uint32, src, ad []byte)
  function setupState (line 28) | func setupState(state *[16]uint32, key *[32]byte, nonce []byte) {
  method seal (line 49) | func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []...
  method open (line 65) | func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData [...

FILE: gossh/crypto/chacha20poly1305/chacha20poly1305_generic.go
  function writeWithPadding (line 15) | func writeWithPadding(p *poly1305.MAC, b []byte) {
  function writeUint64 (line 24) | func writeUint64(p *poly1305.MAC, n int) {
  method sealGeneric (line 30) | func (c *chacha20poly1305) sealGeneric(dst, nonce, plaintext, additional...
  method openGeneric (line 53) | func (c *chacha20poly1305) openGeneric(dst, nonce, ciphertext, additiona...

FILE: gossh/crypto/chacha20poly1305/chacha20poly1305_noasm.go
  method seal (line 9) | func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []...
  method open (line 13) | func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData [...

FILE: gossh/crypto/chacha20poly1305/xchacha20poly1305.go
  type xchacha20poly1305 (line 14) | type xchacha20poly1305 struct
    method NonceSize (line 33) | func (*xchacha20poly1305) NonceSize() int {
    method Overhead (line 37) | func (*xchacha20poly1305) Overhead() int {
    method Seal (line 41) | func (x *xchacha20poly1305) Seal(dst, nonce, plaintext, additionalData...
    method Open (line 66) | func (x *xchacha20poly1305) Open(dst, nonce, ciphertext, additionalDat...
  function NewX (line 24) | func NewX(key []byte) (cipher.AEAD, error) {

FILE: gossh/crypto/curve25519/curve25519.go
  function ScalarMult (line 18) | func ScalarMult(dst, scalar, point *[32]byte) {
  function ScalarBaseMult (line 27) | func ScalarBaseMult(dst, scalar *[32]byte) {
  constant ScalarSize (line 33) | ScalarSize = 32
  constant PointSize (line 35) | PointSize = 32
  function init (line 43) | func init() { Basepoint = basePoint[:] }
  function X25519 (line 54) | func X25519(scalar, point []byte) ([]byte, error) {

FILE: gossh/crypto/curve25519/curve25519_compat.go
  function scalarMult (line 17) | func scalarMult(dst, scalar, point *[32]byte) {
  function scalarBaseMult (line 69) | func scalarBaseMult(dst, scalar *[32]byte) {
  function x25519 (line 74) | func x25519(dst *[32]byte, scalar, point []byte) ([]byte, error) {
  function checkBasepoint (line 96) | func checkBasepoint() {

FILE: gossh/crypto/curve25519/curve25519_go120.go
  function x25519 (line 11) | func x25519(dst *[32]byte, scalar, point []byte) ([]byte, error) {
  function scalarMult (line 29) | func scalarMult(dst, scalar, point *[32]byte) {
  function scalarBaseMult (line 39) | func scalarBaseMult(dst, scalar *[32]byte) {

FILE: gossh/crypto/curve25519/internal/field/fe.go
  type Element (line 22) | type Element struct
    method Zero (line 39) | func (v *Element) Zero() *Element {
    method One (line 47) | func (v *Element) One() *Element {
    method reduce (line 53) | func (v *Element) reduce() *Element {
    method Add (line 86) | func (v *Element) Add(a, b *Element) *Element {
    method Subtract (line 100) | func (v *Element) Subtract(a, b *Element) *Element {
    method Negate (line 112) | func (v *Element) Negate(a *Element) *Element {
    method Invert (line 119) | func (v *Element) Invert(z *Element) *Element {
    method Set (line 184) | func (v *Element) Set(a *Element) *Element {
    method SetBytes (line 194) | func (v *Element) SetBytes(x []byte) *Element {
    method Bytes (line 220) | func (v *Element) Bytes() []byte {
    method bytes (line 227) | func (v *Element) bytes(out *[32]byte) []byte {
    method Equal (line 248) | func (v *Element) Equal(u *Element) int {
    method Select (line 257) | func (v *Element) Select(a, b *Element, cond int) *Element {
    method Swap (line 268) | func (v *Element) Swap(u *Element, cond int) {
    method IsNegative (line 288) | func (v *Element) IsNegative() int {
    method Absolute (line 293) | func (v *Element) Absolute(u *Element) *Element {
    method Multiply (line 298) | func (v *Element) Multiply(x, y *Element) *Element {
    method Square (line 304) | func (v *Element) Square(x *Element) *Element {
    method Mult32 (line 310) | func (v *Element) Mult32(x *Element, y uint32) *Element {
    method Pow22523 (line 335) | func (v *Element) Pow22523(x *Element) *Element {
    method SqrtRatio (line 394) | func (r *Element) SqrtRatio(u, v *Element) (rr *Element, wasSquare int) {
  constant maskLow51Bits (line 34) | maskLow51Bits uint64 = (1 << 51) - 1
  function mask64Bits (line 254) | func mask64Bits(cond int) uint64 { return ^(uint64(cond) - 1) }
  function mul51 (line 327) | func mul51(a uint64, b uint32) (lo uint64, hi uint64) {

FILE: gossh/crypto/curve25519/internal/field/fe_amd64.go
  function feMul (line 10) | func feMul(out *Element, a *Element, b *Element)
  function feSquare (line 15) | func feSquare(out *Element, a *Element)

FILE: gossh/crypto/curve25519/internal/field/fe_amd64_noasm.go
  function feMul (line 9) | func feMul(v, x, y *Element) { feMulGeneric(v, x, y) }
  function feSquare (line 11) | func feSquare(v, x *Element) { feSquareGeneric(v, x) }

FILE: gossh/crypto/curve25519/internal/field/fe_arm64.go
  function carryPropagate (line 10) | func carryPropagate(v *Element)
  method carryPropagate (line 12) | func (v *Element) carryPropagate() *Element {

FILE: gossh/crypto/curve25519/internal/field/fe_arm64_noasm.go
  method carryPropagate (line 9) | func (v *Element) carryPropagate() *Element {

FILE: gossh/crypto/curve25519/internal/field/fe_generic.go
  type uint128 (line 11) | type uint128 struct
  function mul64 (line 16) | func mul64(a, b uint64) uint128 {
  function addMul64 (line 22) | func addMul64(v uint128, a, b uint64) uint128 {
  function shiftRightBy51 (line 30) | func shiftRightBy51(a uint128) uint64 {
  function feMulGeneric (line 34) | func feMulGeneric(v, a, b *Element) {
  function feSquareGeneric (line 165) | func feSquareGeneric(v, a *Element) {
  method carryPropagateGeneric (line 250) | func (v *Element) carryPropagateGeneric() *Element {

FILE: gossh/crypto/internal/alias/alias.go
  function AnyOverlap (line 14) | func AnyOverlap(x, y []byte) bool {
  function InexactOverlap (line 26) | func InexactOverlap(x, y []byte) bool {

FILE: gossh/crypto/internal/alias/alias_purego.go
  function AnyOverlap (line 17) | func AnyOverlap(x, y []byte) bool {
  function InexactOverlap (line 29) | func InexactOverlap(x, y []byte) bool {

FILE: gossh/crypto/internal/poly1305/mac_noasm.go
  type mac (line 9) | type mac struct

FILE: gossh/crypto/internal/poly1305/poly1305.go
  constant TagSize (line 23) | TagSize = 16
  function Sum (line 28) | func Sum(out *[16]byte, m []byte, key *[32]byte) {
  function Verify (line 35) | func Verify(mac *[16]byte, m []byte, key *[32]byte) bool {
  function New (line 50) | func New(key *[32]byte) *MAC {
  type MAC (line 63) | type MAC struct
    method Size (line 70) | func (h *MAC) Size() int { return TagSize }
    method Write (line 76) | func (h *MAC) Write(p []byte) (n int, err error) {
    method Sum (line 85) | func (h *MAC) Sum(b []byte) []byte {
    method Verify (line 94) | func (h *MAC) Verify(expected []byte) bool {

FILE: gossh/crypto/internal/poly1305/sum_amd64.go
  function update (line 10) | func update(state *macState, msg []byte)
  type mac (line 17) | type mac struct
    method Write (line 19) | func (h *mac) Write(p []byte) (int, error) {
    method Sum (line 41) | func (h *mac) Sum(out *[16]byte) {

FILE: gossh/crypto/internal/poly1305/sum_generic.go
  function sumGeneric (line 31) | func sumGeneric(out *[TagSize]byte, msg []byte, key *[32]byte) {
  function newMACGeneric (line 37) | func newMACGeneric(key *[32]byte) macGeneric {
  type macState (line 45) | type macState struct
  type macGeneric (line 55) | type macGeneric struct
    method Write (line 64) | func (h *macGeneric) Write(p []byte) (int, error) {
    method Sum (line 89) | func (h *macGeneric) Sum(out *[TagSize]byte) {
  constant rMask0 (line 101) | rMask0 = 0x0FFFFFFC0FFFFFFF
  constant rMask1 (line 102) | rMask1 = 0x0FFFFFFC0FFFFFFC
  function initialize (line 106) | func initialize(key *[32]byte, m *macState) {
  type uint128 (line 115) | type uint128 struct
  function mul64 (line 119) | func mul64(a, b uint64) uint128 {
  function add128 (line 124) | func add128(a, b uint128) uint128 {
  function shiftRightBy2 (line 133) | func shiftRightBy2(a uint128) uint128 {
  function updateGeneric (line 146) | func updateGeneric(state *macState, msg []byte) {
  constant maskLow2Bits (line 268) | maskLow2Bits    uint64 = 0x0000000000000003
  constant maskNotLow2Bits (line 269) | maskNotLow2Bits uint64 = ^maskLow2Bits
  function select64 (line 273) | func select64(v, x, y uint64) uint64 { return ^(v-1)&x | (v-1)&y }
  constant p0 (line 277) | p0 = 0xFFFFFFFFFFFFFFFB
  constant p1 (line 278) | p1 = 0xFFFFFFFFFFFFFFFF
  constant p2 (line 279) | p2 = 0x0000000000000003
  function finalize (line 285) | func finalize(out *[TagSize]byte, h *[3]uint64, s *[2]uint64) {

FILE: gossh/crypto/internal/poly1305/sum_ppc64le.go
  function update (line 10) | func update(state *macState, msg []byte)
  type mac (line 17) | type mac struct
    method Write (line 19) | func (h *mac) Write(p []byte) (int, error) {
    method Sum (line 41) | func (h *mac) Sum(out *[16]byte) {

FILE: gossh/crypto/internal/poly1305/sum_s390x.go
  function updateVX (line 18) | func updateVX(state *macState, msg []byte)
  type mac (line 27) | type mac struct
    method Write (line 34) | func (h *mac) Write(p []byte) (int, error) {
    method Sum (line 64) | func (h *mac) Sum(out *[TagSize]byte) {

FILE: gossh/crypto/internal/testenv/exec.go
  function CommandContext (line 25) | func CommandContext(t testing.TB, ctx context.Context, name string, args...
  function Command (line 117) | func Command(t testing.TB, name string, args ...string) *exec.Cmd {

FILE: gossh/crypto/ssh/agent/client.go
  type SignatureFlags (line 35) | type SignatureFlags
  constant SignatureFlagReserved (line 39) | SignatureFlagReserved SignatureFlags = 1 << iota
  constant SignatureFlagRsaSha256 (line 40) | SignatureFlagRsaSha256
  constant SignatureFlagRsaSha512 (line 41) | SignatureFlagRsaSha512
  type Agent (line 45) | type Agent interface
  type ExtendedAgent (line 72) | type ExtendedAgent interface
  type ConstraintExtension (line 93) | type ConstraintExtension struct
  type AddedKey (line 104) | type AddedKey struct
  constant agentRequestV1Identities (line 127) | agentRequestV1Identities   = 1
  constant agentRemoveAllV1Identities (line 128) | agentRemoveAllV1Identities = 9
  constant agentAddIdentity (line 131) | agentAddIdentity         = 17
  constant agentRemoveIdentity (line 132) | agentRemoveIdentity      = 18
  constant agentRemoveAllIdentities (line 133) | agentRemoveAllIdentities = 19
  constant agentAddIDConstrained (line 134) | agentAddIDConstrained    = 25
  constant agentAddSmartcardKey (line 137) | agentAddSmartcardKey            = 20
  constant agentRemoveSmartcardKey (line 138) | agentRemoveSmartcardKey         = 21
  constant agentLock (line 139) | agentLock                       = 22
  constant agentUnlock (line 140) | agentUnlock                     = 23
  constant agentAddSmartcardKeyConstrained (line 141) | agentAddSmartcardKeyConstrained = 26
  constant agentConstrainLifetime (line 144) | agentConstrainLifetime = 1
  constant agentConstrainConfirm (line 145) | agentConstrainConfirm  = 2
  constant agentConstrainExtensionV00 (line 149) | agentConstrainExtensionV00 = 3
  constant agentConstrainExtension (line 151) | agentConstrainExtension = 255
  constant maxAgentResponseBytes (line 156) | maxAgentResponseBytes = 16 << 20
  constant agentFailure (line 163) | agentFailure = 5
  type failureAgentMsg (line 165) | type failureAgentMsg struct
  constant agentSuccess (line 167) | agentSuccess = 6
  type successAgentMsg (line 169) | type successAgentMsg struct
  constant agentRequestIdentities (line 172) | agentRequestIdentities = 11
  type requestIdentitiesAgentMsg (line 174) | type requestIdentitiesAgentMsg struct
  constant agentIdentitiesAnswer (line 177) | agentIdentitiesAnswer = 12
  type identitiesAnswerAgentMsg (line 179) | type identitiesAnswerAgentMsg struct
  constant agentSignRequest (line 185) | agentSignRequest = 13
  type signRequestAgentMsg (line 187) | type signRequestAgentMsg struct
  constant agentSignResponse (line 196) | agentSignResponse = 14
  type signResponseAgentMsg (line 198) | type signResponseAgentMsg struct
  type publicKey (line 202) | type publicKey struct
  type constrainLifetimeAgentMsg (line 208) | type constrainLifetimeAgentMsg struct
  type constrainExtensionAgentMsg (line 212) | type constrainExtensionAgentMsg struct
  constant agentExtension (line 221) | agentExtension = 27
  constant agentExtensionFailure (line 222) | agentExtensionFailure = 28
  type extensionAgentMsg (line 232) | type extensionAgentMsg struct
  type Key (line 241) | type Key struct
    method String (line 253) | func (k *Key) String() string {
    method Type (line 264) | func (k *Key) Type() string {
    method Marshal (line 269) | func (k *Key) Marshal() []byte {
    method Verify (line 274) | func (k *Key) Verify(data []byte, sig *ssh.Signature) error {
  function clientErr (line 247) | func clientErr(err error) error {
  type wireKey (line 282) | type wireKey struct
  function parseKey (line 287) | func parseKey(in []byte) (out *Key, rest []byte, err error) {
  type client (line 311) | type client struct
    method call (line 327) | func (c *client) call(req []byte) (reply any, err error) {
    method callRaw (line 342) | func (c *client) callRaw(req []byte) (reply []byte, err error) {
    method simpleCall (line 369) | func (c *client) simpleCall(req []byte) error {
    method RemoveAll (line 380) | func (c *client) RemoveAll() error {
    method Remove (line 384) | func (c *client) Remove(key ssh.PublicKey) error {
    method Lock (line 391) | func (c *client) Lock(passphrase []byte) error {
    method Unlock (line 398) | func (c *client) Unlock(passphrase []byte) error {
    method List (line 406) | func (c *client) List() ([]*Key, error) {
    method Sign (line 439) | func (c *client) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature,...
    method SignWithFlags (line 443) | func (c *client) SignWithFlags(key ssh.PublicKey, data []byte, flags S...
    method insertKey (line 537) | func (c *client) insertKey(s any, comment string, constraints []byte) ...
    method Add (line 653) | func (c *client) Add(key AddedKey) error {
    method insertCert (line 671) | func (c *client) insertCert(s any, cert *ssh.Certificate, comment stri...
    method Signers (line 754) | func (c *client) Signers() ([]ssh.Signer, error) {
    method Extension (line 832) | func (c *client) Extension(extensionType string, contents []byte) ([]b...
  function NewClient (line 320) | func NewClient(rw io.ReadWriter) ExtendedAgent {
  function unmarshal (line 471) | func unmarshal(packet []byte) (any, error) {
  type rsaKeyMsg (line 496) | type rsaKeyMsg struct
  type dsaKeyMsg (line 508) | type dsaKeyMsg struct
  type ecdsaKeyMsg (line 519) | type ecdsaKeyMsg struct
  type ed25519KeyMsg (line 528) | type ed25519KeyMsg struct
  type rsaCertMsg (line 615) | type rsaCertMsg struct
  type dsaCertMsg (line 626) | type dsaCertMsg struct
  type ecdsaCertMsg (line 634) | type ecdsaCertMsg struct
  type ed25519CertMsg (line 642) | type ed25519CertMsg struct
  type agentKeyringSigner (line 767) | type agentKeyringSigner struct
    method PublicKey (line 772) | func (s *agentKeyringSigner) PublicKey() ssh.PublicKey {
    method Sign (line 776) | func (s *agentKeyringSigner) Sign(rand io.Reader, data []byte) (*ssh.S...
    method SignWithAlgorithm (line 781) | func (s *agentKeyringSigner) SignWithAlgorithm(rand io.Reader, data []...
  function underlyingAlgo (line 821) | func underlyingAlgo(algo string) string {

FILE: gossh/crypto/ssh/agent/forward.go
  function RequestAgentForwarding (line 19) | func RequestAgentForwarding(session *ssh.Session) error {
  function ForwardToAgent (line 31) | func ForwardToAgent(client *ssh.Client, keyring Agent) error {
  constant channelType (line 53) | channelType = "auth-agent@openssh.com"
  function ForwardToRemote (line 57) | func ForwardToRemote(client *ssh.Client, addr string) error {
  function forwardUnixSocket (line 81) | func forwardUnixSocket(channel ssh.Channel, addr string) {

FILE: gossh/crypto/ssh/agent/keyring.go
  type privKey (line 19) | type privKey struct
  type keyring (line 25) | type keyring struct
    method RemoveAll (line 42) | func (r *keyring) RemoveAll() error {
    method removeLocked (line 55) | func (r *keyring) removeLocked(want []byte) error {
    method Remove (line 75) | func (r *keyring) Remove(key ssh.PublicKey) error {
    method Lock (line 86) | func (r *keyring) Lock(passphrase []byte) error {
    method Unlock (line 99) | func (r *keyring) Unlock(passphrase []byte) error {
    method expireKeysLocked (line 117) | func (r *keyring) expireKeysLocked() {
    method List (line 126) | func (r *keyring) List() ([]*Key, error) {
    method Add (line 149) | func (r *keyring) Add(key AddedKey) error {
    method Sign (line 184) | func (r *keyring) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature...
    method SignWithFlags (line 188) | func (r *keyring) SignWithFlags(key ssh.PublicKey, data []byte, flags ...
    method Signers (line 223) | func (r *keyring) Signers() ([]ssh.Signer, error) {
    method Extension (line 239) | func (r *keyring) Extension(extensionType string, contents []byte) ([]...
  function NewKeyring (line 37) | func NewKeyring() Agent {

FILE: gossh/crypto/ssh/agent/server.go
  type server (line 25) | type server struct
    method processRequestBytes (line 29) | func (s *server) processRequestBytes(reqData []byte) []byte {
    method processRequest (line 76) | func (s *server) processRequest(data []byte) (any, error) {
    method insertIdentity (line 493) | func (s *server) insertIdentity(req []byte) error {
  function marshalKey (line 46) | func marshalKey(k *Key) []byte {
  constant agentV1IdentitiesAnswer (line 58) | agentV1IdentitiesAnswer = 2
  type agentV1IdentityMsg (line 60) | type agentV1IdentityMsg struct
  type agentRemoveIdentityMsg (line 64) | type agentRemoveIdentityMsg struct
  type agentLockMsg (line 68) | type agentLockMsg struct
  type agentUnlockMsg (line 72) | type agentUnlockMsg struct
  function parseConstraints (line 202) | func parseConstraints(constraints []byte) (lifetimeSecs uint32, confirmB...
  function setConstraints (line 228) | func setConstraints(key *AddedKey, constraintBytes []byte) error {
  function parseRSAKey (line 240) | func parseRSAKey(req []byte) (*AddedKey, error) {
  function parseEd25519Key (line 265) | func parseEd25519Key(req []byte) (*AddedKey, error) {
  function parseDSAKey (line 279) | func parseDSAKey(req []byte) (*AddedKey, error) {
  function unmarshalECDSA (line 303) | func unmarshalECDSA(curveName string, keyBytes []byte, privScalar *big.I...
  function parseEd25519Cert (line 327) | func parseEd25519Cert(req []byte) (*AddedKey, error) {
  function parseECDSAKey (line 349) | func parseECDSAKey(req []byte) (*AddedKey, error) {
  function parseRSACert (line 367) | func parseRSACert(req []byte) (*AddedKey, error) {
  function parseDSACert (line 414) | func parseDSACert(req []byte) (*AddedKey, error) {
  function parseECDSACert (line 456) | func parseECDSACert(req []byte) (*AddedKey, error) {
  function ServeAgent (line 535) | func ServeAgent(agent Agent, c io.ReadWriter) error {

FILE: gossh/crypto/ssh/buffer.go
  type buffer (line 15) | type buffer struct
    method write (line 44) | func (b *buffer) write(buf []byte) {
    method eof (line 55) | func (b *buffer) eof() {
    method Read (line 64) | func (b *buffer) Read(buf []byte) (n int, err error) {
  type element (line 26) | type element struct
  function newBuffer (line 32) | func newBuffer() *buffer {

FILE: gossh/crypto/ssh/certs.go
  constant CertAlgoRSAv01 (line 23) | CertAlgoRSAv01        = "ssh-rsa-cert-v01@openssh.com"
  constant CertAlgoDSAv01 (line 24) | CertAlgoDSAv01        = "ssh-dss-cert-v01@openssh.com"
  constant CertAlgoECDSA256v01 (line 25) | CertAlgoECDSA256v01   = "ecdsa-sha2-nistp256-cert-v01@openssh.com"
  constant CertAlgoECDSA384v01 (line 26) | CertAlgoECDSA384v01   = "ecdsa-sha2-nistp384-cert-v01@openssh.com"
  constant CertAlgoECDSA521v01 (line 27) | CertAlgoECDSA521v01   = "ecdsa-sha2-nistp521-cert-v01@openssh.com"
  constant CertAlgoSKECDSA256v01 (line 28) | CertAlgoSKECDSA256v01 = "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com"
  constant CertAlgoED25519v01 (line 29) | CertAlgoED25519v01    = "ssh-ed25519-cert-v01@openssh.com"
  constant CertAlgoSKED25519v01 (line 30) | CertAlgoSKED25519v01  = "sk-ssh-ed25519-cert-v01@openssh.com"
  constant CertAlgoRSASHA256v01 (line 35) | CertAlgoRSASHA256v01 = "rsa-sha2-256-cert-v01@openssh.com"
  constant CertAlgoRSASHA512v01 (line 36) | CertAlgoRSASHA512v01 = "rsa-sha2-512-cert-v01@openssh.com"
  constant CertSigAlgoRSAv01 (line 41) | CertSigAlgoRSAv01 = CertAlgoRSAv01
  constant CertSigAlgoRSASHA2256v01 (line 43) | CertSigAlgoRSASHA2256v01 = CertAlgoRSASHA256v01
  constant CertSigAlgoRSASHA2512v01 (line 45) | CertSigAlgoRSASHA2512v01 = CertAlgoRSASHA512v01
  constant UserCert (line 52) | UserCert = 1
  constant HostCert (line 53) | HostCert = 2
  type Signature (line 57) | type Signature struct
  constant CertTimeInfinity (line 65) | CertTimeInfinity = 1<<64 - 1
  type Certificate (line 71) | type Certificate struct
    method SignCert (line 446) | func (c *Certificate) SignCert(rand io.Reader, authority Signer) error {
    method bytesForSigning (line 521) | func (cert *Certificate) bytesForSigning() []byte {
    method Marshal (line 531) | func (c *Certificate) Marshal() []byte {
    method Type (line 563) | func (c *Certificate) Type() string {
    method Verify (line 573) | func (c *Certificate) Verify(data []byte, sig *Signature) error {
  type genericCertData (line 89) | type genericCertData struct
  function marshalStringList (line 103) | func marshalStringList(namelist []string) []byte {
  type optionsTuple (line 112) | type optionsTuple struct
  type optionsTupleValue (line 117) | type optionsTupleValue struct
  function marshalTuples (line 124) | func marshalTuples(tups map[string]string) []byte {
  function parseTuples (line 144) | func parseTuples(in []byte) (map[string]string, error) {
  function parseCert (line 183) | func parseCert(in []byte, privAlgo string) (*Certificate, error) {
  type openSSHCertSigner (line 241) | type openSSHCertSigner struct
    method Sign (line 274) | func (s *openSSHCertSigner) Sign(rand io.Reader, data []byte) (*Signat...
    method PublicKey (line 278) | func (s *openSSHCertSigner) PublicKey() PublicKey {
  type algorithmOpenSSHCertSigner (line 246) | type algorithmOpenSSHCertSigner struct
    method SignWithAlgorithm (line 282) | func (s *algorithmOpenSSHCertSigner) SignWithAlgorithm(rand io.Reader,...
  function NewCertSigner (line 254) | func NewCertSigner(cert *Certificate, signer Signer) (Signer, error) {
  constant sourceAddressCriticalOption (line 286) | sourceAddressCriticalOption = "source-address"
  type CertChecker (line 292) | type CertChecker struct
    method CheckHostKey (line 334) | func (c *CertChecker) CheckHostKey(addr string, remote net.Addr, key P...
    method Authenticate (line 360) | func (c *CertChecker) Authenticate(conn ConnMetadata, pubKey PublicKey...
    method CheckCert (line 385) | func (c *CertChecker) CheckCert(principal string, cert *Certificate) e...
  function underlyingAlgo (line 503) | func underlyingAlgo(algo string) string {
  function certificateAlgo (line 512) | func certificateAlgo(algo string) (certAlgo string, ok bool) {
  function parseSignatureBody (line 577) | func parseSignatureBody(in []byte) (out *Signature, rest []byte, ok bool) {
  function parseSignature (line 600) | func parseSignature(in []byte) (out *Signature, rest []byte, ok bool) {

FILE: gossh/crypto/ssh/channel.go
  constant minPacketLength (line 17) | minPacketLength = 9
  constant channelMaxPacket (line 21) | channelMaxPacket = 1 << 15
  constant channelWindowSize (line 23) | channelWindowSize = 64 * channelMaxPacket
  type NewChannel (line 28) | type NewChannel interface
  type Channel (line 49) | type Channel interface
  type Request (line 84) | type Request struct
    method Reply (line 96) | func (r *Request) Reply(ok bool, payload []byte) error {
  type RejectionReason (line 110) | type RejectionReason
    method String (line 120) | func (r RejectionReason) String() string {
  constant Prohibited (line 113) | Prohibited RejectionReason = iota + 1
  constant ConnectionFailed (line 114) | ConnectionFailed
  constant UnknownChannelType (line 115) | UnknownChannelType
  constant ResourceShortage (line 116) | ResourceShortage
  function min (line 134) | func min(a uint32, b int) uint32 {
  type channelDirection (line 141) | type channelDirection
  constant channelInbound (line 144) | channelInbound channelDirection = iota
  constant channelOutbound (line 145) | channelOutbound
  type channel (line 150) | type channel struct
    method writePacket (line 210) | func (ch *channel) writePacket(packet []byte) error {
    method sendMessage (line 222) | func (ch *channel) sendMessage(msg any) error {
    method WriteExtended (line 234) | func (ch *channel) WriteExtended(data []byte, extendedCode uint32) (n ...
    method handleData (line 288) | func (ch *channel) handleData(packet []byte) error {
    method adjustWindow (line 337) | func (c *channel) adjustWindow(adj uint32) error {
    method ReadExtended (line 358) | func (c *channel) ReadExtended(data []byte, extended uint32) (n int, e...
    method close (line 382) | func (c *channel) close() {
    method responseMessageReceived (line 399) | func (ch *channel) responseMessageReceived() error {
    method handlePacket (line 410) | func (ch *channel) handlePacket(packet []byte) error {
    method Accept (line 503) | func (ch *channel) Accept() (Channel, <-chan *Request, error) {
    method Reject (line 522) | func (ch *channel) Reject(reason RejectionReason, message string) error {
    method Read (line 536) | func (ch *channel) Read(data []byte) (int, error) {
    method Write (line 543) | func (ch *channel) Write(data []byte) (int, error) {
    method CloseWrite (line 550) | func (ch *channel) CloseWrite() error {
    method Close (line 559) | func (ch *channel) Close() error {
    method Extended (line 570) | func (ch *channel) Extended(code uint32) io.ReadWriter {
    method Stderr (line 577) | func (ch *channel) Stderr() io.ReadWriter {
    method SendRequest (line 581) | func (ch *channel) SendRequest(name string, wantReply bool, payload []...
    method ackRequest (line 621) | func (ch *channel) ackRequest(ok bool) error {
    method ChannelType (line 639) | func (ch *channel) ChannelType() string {
    method ExtraData (line 643) | func (ch *channel) ExtraData() []byte {
  method newChannel (line 469) | func (m *mux) newChannel(chanType string, direction channelDirection, ex...
  type extChannel (line 490) | type extChannel struct
    method Write (line 495) | func (e *extChannel) Write(data []byte) (n int, err error) {
    method Read (line 499) | func (e *extChannel) Read(data []byte) (n int, err error) {

FILE: gossh/crypto/ssh/cipher.go
  constant packetSizeMultiple (line 23) | packetSizeMultiple = 16
  constant maxPacket (line 34) | maxPacket = 256 * 1024
  type noneCipher (line 39) | type noneCipher struct
    method XORKeyStream (line 41) | func (c noneCipher) XORKeyStream(dst, src []byte) {
  function newAESCTR (line 45) | func newAESCTR(key, iv []byte) (cipher.Stream, error) {
  function newRC4 (line 53) | func newRC4(key, iv []byte) (cipher.Stream, error) {
  type cipherMode (line 57) | type cipherMode struct
  function streamCipherMode (line 63) | func streamCipherMode(skip int, createFunc func(key, iv []byte) (cipher....
  constant prefixLen (line 134) | prefixLen = 5
  type streamPacketCipher (line 137) | type streamPacketCipher struct
    method readCipherPacket (line 151) | func (s *streamPacketCipher) readCipherPacket(seqNum uint32, r io.Read...
    method writeCipherPacket (line 223) | func (s *streamPacketCipher) writeCipherPacket(seqNum uint32, w io.Wri...
  type gcmCipher (line 302) | type gcmCipher struct
    method writeCipherPacket (line 328) | func (c *gcmCipher) writeCipherPacket(seqNum uint32, w io.Writer, rand...
    method incIV (line 362) | func (c *gcmCipher) incIV() {
    method readCipherPacket (line 371) | func (c *gcmCipher) readCipherPacket(seqNum uint32, r io.Reader) ([]by...
  function newGCMCipher (line 309) | func newGCMCipher(key, iv, unusedMacKey []byte, unusedAlgs directionAlgo...
  constant gcmTagSize (line 326) | gcmTagSize = 16
  type cbcCipher (line 415) | type cbcCipher struct
    method readCipherPacket (line 491) | func (c *cbcCipher) readCipherPacket(seqNum uint32, r io.Reader) ([]by...
    method readCipherPacketLeaky (line 505) | func (c *cbcCipher) readCipherPacketLeaky(seqNum uint32, r io.Reader) ...
    method writeCipherPacket (line 581) | func (c *cbcCipher) writeCipherPacket(seqNum uint32, w io.Writer, rand...
  function newCBCCipher (line 431) | func newCBCCipher(c cipher.Block, key, iv, macKey []byte, algs direction...
  function newAESCBCCipher (line 445) | func newAESCBCCipher(key, iv, macKey []byte, algs directionAlgorithms) (...
  function newTripleDESCBCCipher (line 459) | func newTripleDESCBCCipher(key, iv, macKey []byte, algs directionAlgorit...
  function maxUInt32 (line 473) | func maxUInt32(a, b int) uint32 {
  constant cbcMinPacketSizeMultiple (line 481) | cbcMinPacketSizeMultiple = 8
  constant cbcMinPacketSize (line 482) | cbcMinPacketSize         = 16
  constant cbcMinPaddingSize (line 483) | cbcMinPaddingSize        = 4
  type cbcError (line 487) | type cbcError
    method Error (line 489) | func (e cbcError) Error() string { return string(e) }
  constant chacha20Poly1305ID (line 637) | chacha20Poly1305ID = "chacha20-poly1305@openssh.com"
  type chacha20Poly1305Cipher (line 646) | type chacha20Poly1305Cipher struct
    method readCipherPacket (line 666) | func (c *chacha20Poly1305Cipher) readCipherPacket(seqNum uint32, r io....
    method writeCipherPacket (line 736) | func (c *chacha20Poly1305Cipher) writeCipherPacket(seqNum uint32, w io...
  function newChaCha20Cipher (line 652) | func newChaCha20Cipher(key, unusedIV, unusedMACKey []byte, unusedAlgs di...

FILE: gossh/crypto/ssh/client.go
  type Client (line 19) | type Client struct
    method HandleChannelOpen (line 32) | func (c *Client) HandleChannelOpen(channelType string) <-chan NewChann...
    method NewSession (line 133) | func (c *Client) NewSession() (*Session, error) {
    method handleGlobalRequests (line 141) | func (c *Client) handleGlobalRequests(incoming <-chan *Request) {
    method handleChannelOpens (line 150) | func (c *Client) handleChannelOpens(in <-chan NewChannel) {
  function NewClient (line 53) | func NewClient(c Conn, chans <-chan NewChannel, reqs <-chan *Request) *C...
  function NewClientConn (line 71) | func NewClientConn(c net.Conn, addr string, config *ClientConfig) (Conn,...
  method clientHandshake (line 93) | func (c *connection) clientHandshake(dialAddress string, config *ClientC...
  function verifyHostKeySignature (line 118) | func verifyHostKeySignature(hostKey PublicKey, algo string, result *kexR...
  function Dial (line 176) | func Dial(network, addr string, config *ClientConfig) (*Client, error) {
  type HostKeyCallback (line 193) | type HostKeyCallback
  type BannerCallback (line 197) | type BannerCallback
  type ClientConfig (line 201) | type ClientConfig struct
  function InsecureIgnoreHostKey (line 247) | func InsecureIgnoreHostKey() HostKeyCallback {
  type fixedHostKey (line 253) | type fixedHostKey struct
    method check (line 257) | func (f *fixedHostKey) check(hostname string, remote net.Addr, key Pub...
  function FixedHostKey (line 269) | func FixedHostKey(key PublicKey) HostKeyCallback {
  function BannerDisplayStderr (line 276) | func BannerDisplayStderr() BannerCallback {

FILE: gossh/crypto/ssh/client_auth.go
  type authResult (line 15) | type authResult
  constant authFailure (line 18) | authFailure authResult = iota
  constant authPartialSuccess (line 19) | authPartialSuccess
  constant authSuccess (line 20) | authSuccess
  method clientAuthenticate (line 24) | func (c *connection) clientAuthenticate(config *ClientConfig) error {
  function contains (line 116) | func contains(list []string, e string) bool {
  type AuthMethod (line 126) | type AuthMethod interface
  type noneAuth (line 139) | type noneAuth
    method auth (line 141) | func (n *noneAuth) auth(session []byte, user string, c packetConn, ran...
    method method (line 153) | func (n *noneAuth) method() string {
  type passwordCallback (line 159) | type passwordCallback
    method auth (line 161) | func (cb passwordCallback) auth(session []byte, user string, c packetC...
    method method (line 191) | func (cb passwordCallback) method() string {
  function Password (line 196) | func Password(secret string) AuthMethod {
  function PasswordCallback (line 202) | func PasswordCallback(prompt func() (secret string, err error)) AuthMeth...
  type publickeyAuthMsg (line 206) | type publickeyAuthMsg struct
  type publicKeyCallback (line 222) | type publicKeyCallback
    method method (line 224) | func (cb publicKeyCallback) method() string {
    method auth (line 298) | func (cb publicKeyCallback) auth(session []byte, user string, c packet...
  function pickSignatureAlgorithm (line 228) | func pickSignatureAlgorithm(signer Signer, extensions map[string][]byte)...
  function validateKey (line 393) | func validateKey(key PublicKey, algo string, user string, c packetConn) ...
  function confirmKeyAck (line 410) | func confirmKeyAck(key PublicKey, algo string, c packetConn) (bool, erro...
  function PublicKeys (line 442) | func PublicKeys(signers ...Signer) AuthMethod {
  function PublicKeysCallback (line 448) | func PublicKeysCallback(getSigners func() (signers []Signer, err error))...
  function handleAuthResponse (line 455) | func handleAuthResponse(c packetConn) (authResult, []string, error) {
  function handleBannerResponse (line 491) | func handleBannerResponse(c packetConn, packet []byte) error {
  type KeyboardInteractiveChallenge (line 516) | type KeyboardInteractiveChallenge
    method method (line 524) | func (cb KeyboardInteractiveChallenge) method() string {
    method auth (line 528) | func (cb KeyboardInteractiveChallenge) auth(session []byte, user strin...
  function KeyboardInteractive (line 520) | func KeyboardInteractive(challenge KeyboardInteractiveChallenge) AuthMet...
  type retryableAuthMethod (line 633) | type retryableAuthMethod struct
    method auth (line 638) | func (r *retryableAuthMethod) auth(session []byte, user string, c pack...
    method method (line 648) | func (r *retryableAuthMethod) method() string {
  function RetryableAuthMethod (line 663) | func RetryableAuthMethod(auth AuthMethod, maxTries int) AuthMethod {
  function GSSAPIWithMICAuthMethod (line 671) | func GSSAPIWithMICAuthMethod(gssAPIClient GSSAPIClient, target string) A...
  type gssAPIWithMICCallback (line 678) | type gssAPIWithMICCallback struct
    method auth (line 683) | func (g *gssAPIWithMICCallback) auth(session []byte, user string, c pa...
    method method (line 777) | func (g *gssAPIWithMICCallback) method() string {

FILE: gossh/crypto/ssh/common.go
  constant compressionNone (line 22) | compressionNone = "none"
  constant serviceUserAuth (line 23) | serviceUserAuth = "ssh-userauth"
  constant serviceSSH (line 24) | serviceSSH      = "ssh-connection"
  function algorithmsForKeyFormat (line 112) | func algorithmsForKeyFormat(keyFormat string) []string {
  function isRSA (line 125) | func isRSA(algo string) bool {
  function isRSACert (line 130) | func isRSACert(algo string) bool {
  function unexpectedMessageError (line 152) | func unexpectedMessageError(expected, got uint8) error {
  function parseError (line 157) | func parseError(tag uint8) error {
  function findCommon (line 161) | func findCommon(what string, client []string, server []string) (common s...
  type directionAlgorithms (line 173) | type directionAlgorithms struct
    method rekeyBytes (line 180) | func (a *directionAlgorithms) rekeyBytes() int64 {
  type algorithms (line 200) | type algorithms struct
  function findAgreedAlgorithms (line 207) | func findAgreedAlgorithms(isClient bool, clientKexInit, serverKexInit *k...
  constant minRekeyThreshold (line 264) | minRekeyThreshold uint64 = 256
  type Config (line 268) | type Config struct
    method SetDefaults (line 295) | func (c *Config) SetDefaults() {
  function buildDataSignedForAuth (line 348) | func buildDataSignedForAuth(sessionID []byte, req userAuthRequestMsg, al...
  function appendU16 (line 371) | func appendU16(buf []byte, n uint16) []byte {
  function appendU32 (line 375) | func appendU32(buf []byte, n uint32) []byte {
  function appendU64 (line 379) | func appendU64(buf []byte, n uint64) []byte {
  function appendInt (line 385) | func appendInt(buf []byte, n int) []byte {
  function appendString (line 389) | func appendString(buf []byte, s string) []byte {
  function appendBool (line 395) | func appendBool(buf []byte, b bool) []byte {
  function newCond (line 404) | func newCond() *sync.Cond { return sync.NewCond(new(sync.Mutex)) }
  type window (line 408) | type window struct
    method add (line 417) | func (w *window) add(win uint32) bool {
    method close (line 438) | func (w *window) close() {
    method reserve (line 448) | func (w *window) reserve(win uint32) (uint32, error) {
    method waitWriterBlocked (line 470) | func (w *window) waitWriterBlocked() {

FILE: gossh/crypto/ssh/connection.go
  type OpenChannelError (line 14) | type OpenChannelError struct
    method Error (line 19) | func (e *OpenChannelError) Error() string {
  type ConnMetadata (line 24) | type ConnMetadata interface
  type Conn (line 50) | type Conn interface
  function DiscardRequests (line 79) | func DiscardRequests(in <-chan *Request) {
  type connection (line 88) | type connection struct
    method Close (line 96) | func (c *connection) Close() error {
  type sshConn (line 102) | type sshConn struct
    method User (line 117) | func (c *sshConn) User() string {
    method RemoteAddr (line 121) | func (c *sshConn) RemoteAddr() net.Addr {
    method Close (line 125) | func (c *sshConn) Close() error {
    method LocalAddr (line 129) | func (c *sshConn) LocalAddr() net.Addr {
    method SessionID (line 133) | func (c *sshConn) SessionID() []byte {
    method ClientVersion (line 137) | func (c *sshConn) ClientVersion() []byte {
    method ServerVersion (line 141) | func (c *sshConn) ServerVersion() []byte {
  function dup (line 111) | func dup(src []byte) []byte {

FILE: gossh/crypto/ssh/handshake.go
  constant debugHandshake (line 21) | debugHandshake = false
  constant chanSize (line 26) | chanSize = 16
  type keyingTransport (line 31) | type keyingTransport interface
  type handshakeTransport (line 52) | type handshakeTransport struct
    method getSessionID (line 169) | func (t *handshakeTransport) getSessionID() []byte {
    method waitSession (line 175) | func (t *handshakeTransport) waitSession() error {
    method id (line 187) | func (t *handshakeTransport) id() string {
    method printPacket (line 194) | func (t *handshakeTransport) printPacket(p []byte, write bool) {
    method readPacket (line 208) | func (t *handshakeTransport) readPacket() ([]byte, error) {
    method readLoop (line 216) | func (t *handshakeTransport) readLoop() {
    method pushPacket (line 244) | func (t *handshakeTransport) pushPacket(p []byte) error {
    method getWriteError (line 251) | func (t *handshakeTransport) getWriteError() error {
    method recordWriteError (line 257) | func (t *handshakeTransport) recordWriteError(err error) {
    method requestKeyExchange (line 265) | func (t *handshakeTransport) requestKeyExchange() {
    method resetWriteThresholds (line 273) | func (t *handshakeTransport) resetWriteThresholds() {
    method kexLoop (line 284) | func (t *handshakeTransport) kexLoop() {
    method resetReadThresholds (line 388) | func (t *handshakeTransport) resetReadThresholds() {
    method readOnePacket (line 399) | func (t *handshakeTransport) readOnePacket(first bool) ([]byte, error) {
    method sendKexInit (line 467) | func (t *handshakeTransport) sendKexInit() error {
    method writePacket (line 555) | func (t *handshakeTransport) writePacket(p []byte) error {
    method Close (line 596) | func (t *handshakeTransport) Close() error {
    method enterKeyExchange (line 609) | func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) ...
    method server (line 775) | func (t *handshakeTransport) server(kex kexAlgorithm, magics *handshak...
    method client (line 785) | func (t *handshakeTransport) client(kex kexAlgorithm, magics *handshak...
  type pendingKex (line 119) | type pendingKex struct
  function newHandshakeTransport (line 124) | func newHandshakeTransport(conn keyingTransport, config *Config, clientV...
  function newClientTransport (line 144) | func newClientTransport(conn keyingTransport, clientVersion, serverVersi...
  function newServerTransport (line 160) | func newServerTransport(conn keyingTransport, clientVersion, serverVersi...
  constant packetRekeyThreshold (line 386) | packetRekeyThreshold = (1 << 31)
  constant kexStrictClient (line 462) | kexStrictClient = "kex-strict-c-v00@openssh.com"
  constant kexStrictServer (line 463) | kexStrictServer = "kex-strict-s-v00@openssh.com"
  type algorithmSignerWrapper (line 739) | type algorithmSignerWrapper struct
    method SignWithAlgorithm (line 743) | func (a algorithmSignerWrapper) SignWithAlgorithm(rand io.Reader, data...
  function pickHostKey (line 750) | func pickHostKey(hostKeys []Signer, algo string) AlgorithmSigner {

FILE: gossh/crypto/ssh/internal/bcrypt_pbkdf/bcrypt_pbkdf.go
  constant blockSize (line 17) | blockSize = 32
  function Key (line 21) | func Key(password, salt []byte, rounds, keyLen int) ([]byte, error) {
  function bcryptHash (line 74) | func bcryptHash(out, shapass, shasalt []byte) {

FILE: gossh/crypto/ssh/kex.go
  constant kexAlgoDH1SHA1 (line 22) | kexAlgoDH1SHA1                = "diffie-hellman-group1-sha1"
  constant kexAlgoDH14SHA1 (line 23) | kexAlgoDH14SHA1               = "diffie-hellman-group14-sha1"
  constant kexAlgoDH14SHA256 (line 24) | kexAlgoDH14SHA256             = "diffie-hellman-group14-sha256"
  constant kexAlgoDH16SHA512 (line 25) | kexAlgoDH16SHA512             = "diffie-hellman-group16-sha512"
  constant kexAlgoECDH256 (line 26) | kexAlgoECDH256                = "ecdh-sha2-nistp256"
  constant kexAlgoECDH384 (line 27) | kexAlgoECDH384                = "ecdh-sha2-nistp384"
  constant kexAlgoECDH521 (line 28) | kexAlgoECDH521                = "ecdh-sha2-nistp521"
  constant kexAlgoCurve25519SHA256LibSSH (line 29) | kexAlgoCurve25519SHA256LibSSH = "curve25519-sha256@libssh.org"
  constant kexAlgoCurve25519SHA256 (line 30) | kexAlgoCurve25519SHA256       = "curve25519-sha256"
  constant kexAlgoDHGEXSHA1 (line 35) | kexAlgoDHGEXSHA1   = "diffie-hellman-group-exchange-sha1"
  constant kexAlgoDHGEXSHA256 (line 36) | kexAlgoDHGEXSHA256 = "diffie-hellman-group-exchange-sha256"
  type kexResult (line 40) | type kexResult struct
  type handshakeMagics (line 65) | type handshakeMagics struct
    method write (line 70) | func (m *handshakeMagics) write(w io.Writer) {
  type kexAlgorithm (line 78) | type kexAlgorithm interface
  type dhGroup (line 90) | type dhGroup struct
    method diffieHellman (line 95) | func (group *dhGroup) diffieHellman(theirPublic, myPrivate *big.Int) (...
    method Client (line 102) | func (group *dhGroup) Client(c packetConn, randSource io.Reader, magic...
    method Server (line 155) | func (group *dhGroup) Server(c packetConn, randSource io.Reader, magic...
  type ecdh (line 221) | type ecdh struct
    method Client (line 225) | func (kex *ecdh) Client(c packetConn, rand io.Reader, magics *handshak...
    method Server (line 318) | func (kex *ecdh) Server(c packetConn, rand io.Reader, magics *handshak...
  function unmarshalECKey (line 277) | func unmarshalECKey(curve elliptic.Curve, pubkey []byte) (x, y *big.Int,...
  function validateECPublicKey (line 290) | func validateECPublicKey(curve elliptic.Curve, x, y *big.Int) bool {
  function ecHash (line 390) | func ecHash(curve elliptic.Curve) crypto.Hash {
  function init (line 403) | func init() {
  type curve25519sha256 (line 455) | type curve25519sha256 struct
    method Client (line 475) | func (kex *curve25519sha256) Client(c packetConn, rand io.Reader, magi...
    method Server (line 524) | func (kex *curve25519sha256) Server(c packetConn, rand io.Reader, magi...
  type curve25519KeyPair (line 457) | type curve25519KeyPair struct
    method generate (line 462) | func (kp *curve25519KeyPair) generate(rand io.Reader) error {
  type dhGEXSHA (line 590) | type dhGEXSHA struct
    method Client (line 600) | func (gex *dhGEXSHA) Client(c packetConn, randSource io.Reader, magics...
    method Server (line 694) | func (gex dhGEXSHA) Server(c packetConn, randSource io.Reader, magics ...
  constant dhGroupExchangeMinimumBits (line 595) | dhGroupExchangeMinimumBits   = 2048
  constant dhGroupExchangePreferredBits (line 596) | dhGroupExchangePreferredBits = 2048
  constant dhGroupExchangeMaximumBits (line 597) | dhGroupExchangeMaximumBits   = 8192

FILE: gossh/crypto/ssh/keys.go
  constant KeyAlgoRSA (line 39) | KeyAlgoRSA        = "ssh-rsa"
  constant KeyAlgoDSA (line 40) | KeyAlgoDSA        = "ssh-dss"
  constant KeyAlgoECDSA256 (line 41) | KeyAlgoECDSA256   = "ecdsa-sha2-nistp256"
  constant KeyAlgoSKECDSA256 (line 42) | KeyAlgoSKECDSA256 = "sk-ecdsa-sha2-nistp256@openssh.com"
  constant KeyAlgoECDSA384 (line 43) | KeyAlgoECDSA384   = "ecdsa-sha2-nistp384"
  constant KeyAlgoECDSA521 (line 44) | KeyAlgoECDSA521   = "ecdsa-sha2-nistp521"
  constant KeyAlgoED25519 (line 45) | KeyAlgoED25519    = "ssh-ed25519"
  constant KeyAlgoSKED25519 (line 46) | KeyAlgoSKED25519  = "sk-ssh-ed25519@openssh.com"
  constant KeyAlgoRSASHA256 (line 51) | KeyAlgoRSASHA256 = "rsa-sha2-256"
  constant KeyAlgoRSASHA512 (line 52) | KeyAlgoRSASHA512 = "rsa-sha2-512"
  constant SigAlgoRSA (line 57) | SigAlgoRSA = KeyAlgoRSA
  constant SigAlgoRSASHA2256 (line 59) | SigAlgoRSASHA2256 = KeyAlgoRSASHA256
  constant SigAlgoRSASHA2512 (line 61) | SigAlgoRSASHA2512 = KeyAlgoRSASHA512
  function parsePubKey (line 66) | func parsePubKey(in []byte, algo string) (pubKey PublicKey, rest []byte,...
  function parseAuthorizedKey (line 93) | func parseAuthorizedKey(in []byte) (out PublicKey, comment string, err e...
  function ParseKnownHosts (line 131) | func ParseKnownHosts(in []byte) (marker string, hosts []string, pubKey P...
  function ParseAuthorizedKey (line 191) | func ParseAuthorizedKey(in []byte) (out PublicKey, comment string, optio...
  function ParsePublicKey (line 273) | func ParsePublicKey(in []byte) (out PublicKey, err error) {
  function MarshalAuthorizedKey (line 289) | func MarshalAuthorizedKey(key PublicKey) []byte {
  function MarshalPrivateKey (line 302) | func MarshalPrivateKey(key crypto.PrivateKey, comment string) (*pem.Bloc...
  function MarshalPrivateKeyWithPassphrase (line 308) | func MarshalPrivateKeyWithPassphrase(key crypto.PrivateKey, comment stri...
  type PublicKey (line 315) | type PublicKey interface
  type CryptoPublicKey (line 332) | type CryptoPublicKey interface
  type Signer (line 339) | type Signer interface
  type AlgorithmSigner (line 356) | type AlgorithmSigner interface
  type MultiAlgorithmSigner (line 368) | type MultiAlgorithmSigner interface
  function NewSignerWithAlgorithms (line 380) | func NewSignerWithAlgorithms(signer AlgorithmSigner, algorithms []string...
  type multiAlgorithmSigner (line 407) | type multiAlgorithmSigner struct
    method Algorithms (line 412) | func (s *multiAlgorithmSigner) Algorithms() []string {
    method isAlgorithmSupported (line 416) | func (s *multiAlgorithmSigner) isAlgorithmSupported(algorithm string) ...
    method SignWithAlgorithm (line 428) | func (s *multiAlgorithmSigner) SignWithAlgorithm(rand io.Reader, data ...
  type rsaPublicKey (line 435) | type rsaPublicKey
    method Type (line 437) | func (r *rsaPublicKey) Type() string {
    method Marshal (line 466) | func (r *rsaPublicKey) Marshal() []byte {
    method Verify (line 482) | func (r *rsaPublicKey) Verify(data []byte, sig *Signature) error {
    method CryptoPublicKey (line 494) | func (r *rsaPublicKey) CryptoPublicKey() crypto.PublicKey {
  function parseRSA (line 442) | func parseRSA(in []byte) (out PublicKey, rest []byte, err error) {
  type dsaPublicKey (line 498) | type dsaPublicKey
    method Type (line 500) | func (k *dsaPublicKey) Type() string {
    method Marshal (line 541) | func (k *dsaPublicKey) Marshal() []byte {
    method Verify (line 558) | func (k *dsaPublicKey) Verify(data []byte, sig *Signature) error {
    method CryptoPublicKey (line 582) | func (k *dsaPublicKey) CryptoPublicKey() crypto.PublicKey {
  function checkDSAParams (line 504) | func checkDSAParams(param *dsa.Parameters) error {
  function parseDSA (line 516) | func parseDSA(in []byte) (out PublicKey, rest []byte, err error) {
  type dsaPrivateKey (line 586) | type dsaPrivateKey struct
    method PublicKey (line 590) | func (k *dsaPrivateKey) PublicKey() PublicKey {
    method Sign (line 594) | func (k *dsaPrivateKey) Sign(rand io.Reader, data []byte) (*Signature,...
    method Algorithms (line 598) | func (k *dsaPrivateKey) Algorithms() []string {
    method SignWithAlgorithm (line 602) | func (k *dsaPrivateKey) SignWithAlgorithm(rand io.Reader, data []byte,...
  type ecdsaPublicKey (line 628) | type ecdsaPublicKey
    method Type (line 630) | func (k *ecdsaPublicKey) Type() string {
    method nistID (line 634) | func (k *ecdsaPublicKey) nistID() string {
    method Marshal (line 735) | func (k *ecdsaPublicKey) Marshal() []byte {
    method Verify (line 753) | func (k *ecdsaPublicKey) Verify(data []byte, sig *Signature) error {
    method CryptoPublicKey (line 781) | func (k *ecdsaPublicKey) CryptoPublicKey() crypto.PublicKey {
  type ed25519PublicKey (line 646) | type ed25519PublicKey
    method Type (line 648) | func (k ed25519PublicKey) Type() string {
    method Marshal (line 669) | func (k ed25519PublicKey) Marshal() []byte {
    method Verify (line 680) | func (k ed25519PublicKey) Verify(b []byte, sig *Signature) error {
    method CryptoPublicKey (line 695) | func (k ed25519PublicKey) CryptoPublicKey() crypto.PublicKey {
  function parseED25519 (line 652) | func parseED25519(in []byte) (out PublicKey, rest []byte, err error) {
  function supportedEllipticCurve (line 699) | func supportedEllipticCurve(curve elliptic.Curve) bool {
  function parseECDSA (line 704) | func parseECDSA(in []byte) (out PublicKey, rest []byte, err error) {
  type skFields (line 787) | type skFields struct
  type skECDSAPublicKey (line 796) | type skECDSAPublicKey struct
    method Type (line 803) | func (k *skECDSAPublicKey) Type() string {
    method nistID (line 807) | func (k *skECDSAPublicKey) nistID() string {
    method Marshal (line 839) | func (k *skECDSAPublicKey) Marshal() []byte {
    method Verify (line 857) | func (k *skECDSAPublicKey) Verify(data []byte, sig *Signature) error {
  function parseSKECDSA (line 811) | func parseSKECDSA(in []byte) (out PublicKey, rest []byte, err error) {
  type skEd25519PublicKey (line 907) | type skEd25519PublicKey struct
    method Type (line 914) | func (k *skEd25519PublicKey) Type() string {
    method Marshal (line 940) | func (k *skEd25519PublicKey) Marshal() []byte {
    method Verify (line 953) | func (k *skEd25519PublicKey) Verify(data []byte, sig *Signature) error {
  function parseSKEd25519 (line 918) | func parseSKEd25519(in []byte) (out PublicKey, rest []byte, err error) {
  function NewSignerFromKey (line 1007) | func NewSignerFromKey(key any) (Signer, error) {
  function newDSAPrivateKey (line 1018) | func newDSAPrivateKey(key *dsa.PrivateKey) (Signer, error) {
  type wrappedSigner (line 1026) | type wrappedSigner struct
    method PublicKey (line 1043) | func (s *wrappedSigner) PublicKey() PublicKey {
    method Sign (line 1047) | func (s *wrappedSigner) Sign(rand io.Reader, data []byte) (*Signature,...
    method Algorithms (line 1051) | func (s *wrappedSigner) Algorithms() []string {
    method SignWithAlgorithm (line 1055) | func (s *wrappedSigner) SignWithAlgorithm(rand io.Reader, data []byte,...
  function NewSignerFromSigner (line 1034) | func NewSignerFromSigner(signer crypto.Signer) (Signer, error) {
  function NewPublicKey (line 1115) | func NewPublicKey(key any) (PublicKey, error) {
  function ParsePrivateKey (line 1139) | func ParsePrivateKey(pemBytes []byte) (Signer, error) {
  function ParsePrivateKeyWithPassphrase (line 1151) | func ParsePrivateKeyWithPassphrase(pemBytes, passphrase []byte) (Signer,...
  function encryptedBlock (line 1164) | func encryptedBlock(block *pem.Block) bool {
  type PassphraseMissingError (line 1170) | type PassphraseMissingError struct
    method Error (line 1176) | func (*PassphraseMissingError) Error() string {
  function ParseRawPrivateKey (line 1183) | func ParseRawPrivateKey(pemBytes []byte) (any, error) {
  function ParseRawPrivateKeyWithPassphrase (line 1213) | func ParseRawPrivateKeyWithPassphrase(pemBytes, passphrase []byte) (any,...
  function ParseDSAPrivateKey (line 1260) | func ParseDSAPrivateKey(der []byte) (*dsa.PrivateKey, error) {
  function unencryptedOpenSSHKey (line 1290) | func unencryptedOpenSSHKey(cipherName, kdfName, kdfOpts string, privKeyB...
  function passphraseProtectedOpenSSHKey (line 1300) | func passphraseProtectedOpenSSHKey(passphrase []byte) openSSHDecryptFunc {
  function unencryptedOpenSSHMarshaler (line 1345) | func unencryptedOpenSSHMarshaler(privKeyBlock []byte) ([]byte, string, s...
  function passphraseProtectedOpenSSHMarshaler (line 1350) | func passphraseProtectedOpenSSHMarshaler(passphrase []byte) openSSHEncry...
  constant privateKeyAuthMagic (line 1387) | privateKeyAuthMagic = "openssh-key-v1\x00"
  type openSSHDecryptFunc (line 1389) | type openSSHDecryptFunc
  type openSSHEncryptFunc (line 1390) | type openSSHEncryptFunc
  type openSSHEncryptedPrivateKey (line 1392) | type openSSHEncryptedPrivateKey struct
  type openSSHPrivateKey (line 1401) | type openSSHPrivateKey struct
  type openSSHRSAPrivateKey (line 1408) | type openSSHRSAPrivateKey struct
  type openSSHEd25519PrivateKey (line 1419) | type openSSHEd25519PrivateKey struct
  type openSSHECDSAPrivateKey (line 1426) | type openSSHECDSAPrivateKey struct
  function parseOpenSSHPrivateKey (line 1438) | func parseOpenSSHPrivateKey(key []byte, decrypt openSSHDecryptFunc) (cry...
  function marshalOpenSSHPrivateKey (line 1567) | func marshalOpenSSHPrivateKey(key crypto.PrivateKey, comment string, enc...
  function checkOpenSSHKeyPadding (line 1692) | func checkOpenSSHKeyPadding(pad []byte) error {
  function generateOpenSSHPadding (line 1701) | func generateOpenSSHPadding(block []byte, blockSize int) []byte {
  function FingerprintLegacyMD5 (line 1710) | func FingerprintLegacyMD5(pubKey PublicKey) string {
  function FingerprintSHA256 (line 1724) | func FingerprintSHA256(pubKey PublicKey) string {

FILE: gossh/crypto/ssh/knownhosts/knownhosts.go
  type addr (line 31) | type addr struct
    method String (line 33) | func (a *addr) String() string {
  type matcher (line 41) | type matcher interface
  type hostPattern (line 45) | type hostPattern struct
    method String (line 50) | func (p *hostPattern) String() string {
    method match (line 109) | func (p *hostPattern) match(a addr) bool {
  type hostPatterns (line 59) | type hostPatterns
    method match (line 61) | func (ps hostPatterns) match(a addr) bool {
  function wildcardMatch (line 78) | func wildcardMatch(pat []byte, str []byte) bool {
  type keyDBLine (line 113) | type keyDBLine struct
    method match (line 123) | func (l *keyDBLine) match(a addr) bool {
  function serialize (line 119) | func serialize(k ssh.PublicKey) string {
  type hostKeyDB (line 127) | type hostKeyDB struct
    method IsHostAuthority (line 146) | func (db *hostKeyDB) IsHostAuthority(remote ssh.PublicKey, address str...
    method IsRevoked (line 162) | func (db *hostKeyDB) IsRevoked(key *ssh.Certificate) bool {
    method parseLine (line 210) | func (db *hostKeyDB) parseLine(line []byte, filename string, linenum i...
    method check (line 329) | func (db *hostKeyDB) check(address string, remote net.Addr, remoteKey ...
    method checkAddr (line 356) | func (db *hostKeyDB) checkAddr(a addr, remoteKey ssh.PublicKey) error {
    method Read (line 392) | func (db *hostKeyDB) Read(r io.Reader, filename string) error {
  function newHostKeyDB (line 133) | func newHostKeyDB() *hostKeyDB {
  function keyEq (line 141) | func keyEq(a, b ssh.PublicKey) bool {
  constant markerCert (line 167) | markerCert = "@cert-authority"
  constant markerRevoked (line 168) | markerRevoked = "@revoked"
  function nextWord (line 170) | func nextWord(line []byte) (string, []byte) {
  function parseLine (line 179) | func parseLine(line []byte) (marker, host string, key ssh.PublicKey, err...
  function newHostnameMatcher (line 249) | func newHostnameMatcher(pattern string) (matcher, error) {
  type KnownKey (line 289) | type KnownKey struct
    method String (line 295) | func (k *KnownKey) String() string {
  type KeyError (line 303) | type KeyError struct
    method Error (line 311) | func (u *KeyError) Error() string {
  type RevokedError (line 319) | type RevokedError struct
    method Error (line 323) | func (r *RevokedError) Error() string {
  function New (line 417) | func New(files ...string) (ssh.HostKeyCallback, error) {
  function Normalize (line 439) | func Normalize(address string) string {
  function Line (line 455) | func Line(addresses []string, key ssh.PublicKey) string {
  function HashHostname (line 466) | func HashHostname(hostname string) string {
  function decodeHash (line 479) | func decodeHash(encoded string) (hashType string, salt, hash []byte, err...
  function encodeHash (line 500) | func encodeHash(typ string, salt []byte, hash []byte) string {
  function hashHost (line 509) | func hashHost(hostname string, salt []byte) []byte {
  type hashedHost (line 515) | type hashedHost struct
    method match (line 538) | func (h *hashedHost) match(a addr) bool {
  constant sha1HashType (line 520) | sha1HashType = "1"
  function newHashedHost (line 522) | func newHashedHost(encoded string) (*hashedHost, error) {

FILE: gossh/crypto/ssh/mac.go
  type macMode (line 17) | type macMode struct
  type truncatingMAC (line 25) | type truncatingMAC struct
    method Write (line 30) | func (t truncatingMAC) Write(data []byte) (int, error) {
    method Sum (line 34) | func (t truncatingMAC) Sum(in []byte) []byte {
    method Reset (line 39) | func (t truncatingMAC) Reset() {
    method Size (line 43) | func (t truncatingMAC) Size() int {
    method BlockSize (line 47) | func (t truncatingMAC) BlockSize() int { return t.hmac.BlockSize() }

FILE: gossh/crypto/ssh/messages.go
  constant msgIgnore (line 22) | msgIgnore        = 2
  constant msgUnimplemented (line 23) | msgUnimplemented = 3
  constant msgDebug (line 24) | msgDebug         = 4
  constant msgNewKeys (line 25) | msgNewKeys       = 21
  constant msgDisconnect (line 36) | msgDisconnect = 1
  type disconnectMsg (line 40) | type disconnectMsg struct
    method Error (line 46) | func (d *disconnectMsg) Error() string {
  constant msgKexInit (line 51) | msgKexInit = 20
  type kexInitMsg (line 53) | type kexInitMsg struct
  constant msgKexDHInit (line 72) | msgKexDHInit = 30
  type kexDHInitMsg (line 74) | type kexDHInitMsg struct
  constant msgKexECDHInit (line 78) | msgKexECDHInit = 30
  type kexECDHInitMsg (line 80) | type kexECDHInitMsg struct
  constant msgKexECDHReply (line 84) | msgKexECDHReply = 31
  type kexECDHReplyMsg (line 86) | type kexECDHReplyMsg struct
  constant msgKexDHReply (line 92) | msgKexDHReply = 31
  type kexDHReplyMsg (line 94) | type kexDHReplyMsg struct
  constant msgKexDHGexGroup (line 101) | msgKexDHGexGroup = 31
  type kexDHGexGroupMsg (line 103) | type kexDHGexGroupMsg struct
  constant msgKexDHGexInit (line 108) | msgKexDHGexInit = 32
  type kexDHGexInitMsg (line 110) | type kexDHGexInitMsg struct
  constant msgKexDHGexReply (line 114) | msgKexDHGexReply = 33
  type kexDHGexReplyMsg (line 116) | type kexDHGexReplyMsg struct
  constant msgKexDHGexRequest (line 122) | msgKexDHGexRequest = 34
  type kexDHGexRequestMsg (line 124) | type kexDHGexRequestMsg struct
  constant msgServiceRequest (line 131) | msgServiceRequest = 5
  type serviceRequestMsg (line 133) | type serviceRequestMsg struct
  constant msgServiceAccept (line 138) | msgServiceAccept = 6
  type serviceAcceptMsg (line 140) | type serviceAcceptMsg struct
  constant msgExtInfo (line 145) | msgExtInfo = 7
  type extInfoMsg (line 147) | type extInfoMsg struct
  constant msgUserAuthRequest (line 153) | msgUserAuthRequest = 50
  type userAuthRequestMsg (line 155) | type userAuthRequestMsg struct
  type userAuthSuccessMsg (line 163) | type userAuthSuccessMsg struct
  constant msgUserAuthFailure (line 167) | msgUserAuthFailure = 51
  type userAuthFailureMsg (line 169) | type userAuthFailureMsg struct
  constant msgUserAuthSuccess (line 175) | msgUserAuthSuccess = 52
  constant msgUserAuthBanner (line 178) | msgUserAuthBanner = 53
  type userAuthBannerMsg (line 180) | type userAuthBannerMsg struct
  constant msgUserAuthInfoRequest (line 187) | msgUserAuthInfoRequest = 60
  constant msgUserAuthInfoResponse (line 188) | msgUserAuthInfoResponse = 61
  type userAuthInfoRequestMsg (line 190) | type userAuthInfoRequestMsg struct
  constant msgChannelOpen (line 199) | msgChannelOpen = 90
  type channelOpenMsg (line 201) | type channelOpenMsg struct
  constant msgChannelExtendedData (line 209) | msgChannelExtendedData = 95
  constant msgChannelData (line 210) | msgChannelData = 94
  type channelDataMsg (line 213) | type channelDataMsg struct
  constant msgChannelOpenConfirm (line 220) | msgChannelOpenConfirm = 91
  type channelOpenConfirmMsg (line 222) | type channelOpenConfirmMsg struct
  constant msgChannelOpenFailure (line 231) | msgChannelOpenFailure = 92
  type channelOpenFailureMsg (line 233) | type channelOpenFailureMsg struct
  constant msgChannelRequest (line 240) | msgChannelRequest = 98
  type channelRequestMsg (line 242) | type channelRequestMsg struct
  constant msgChannelSuccess (line 250) | msgChannelSuccess = 99
  type channelRequestSuccessMsg (line 252) | type channelRequestSuccessMsg struct
  constant msgChannelFailure (line 257) | msgChannelFailure = 100
  type channelRequestFailureMsg (line 259) | type channelRequestFailureMsg struct
  constant msgChannelClose (line 264) | msgChannelClose = 97
  type channelCloseMsg (line 266) | type channelCloseMsg struct
  constant msgChannelEOF (line 271) | msgChannelEOF = 96
  type channelEOFMsg (line 273) | type channelEOFMsg struct
  constant msgGlobalRequest (line 278) | msgGlobalRequest = 80
  type globalRequestMsg (line 280) | type globalRequestMsg struct
  constant msgRequestSuccess (line 287) | msgRequestSuccess = 81
  type globalRequestSuccessMsg (line 289) | type globalRequestSuccessMsg struct
  constant msgRequestFailure (line 294) | msgRequestFailure = 82
  type globalRequestFailureMsg (line 296) | type globalRequestFailureMsg struct
  constant msgChannelWindowAdjust (line 301) | msgChannelWindowAdjust = 93
  type windowAdjustMsg (line 303) | type windowAdjustMsg struct
  constant msgUserAuthPubKeyOk (line 309) | msgUserAuthPubKeyOk = 60
  type userAuthPubKeyOkMsg (line 311) | type userAuthPubKeyOkMsg struct
  constant msgUserAuthGSSAPIResponse (line 317) | msgUserAuthGSSAPIResponse = 60
  type userAuthGSSAPIResponse (line 319) | type userAuthGSSAPIResponse struct
  constant msgUserAuthGSSAPIToken (line 323) | msgUserAuthGSSAPIToken = 61
  type userAuthGSSAPIToken (line 325) | type userAuthGSSAPIToken struct
  constant msgUserAuthGSSAPIMIC (line 329) | msgUserAuthGSSAPIMIC = 66
  type userAuthGSSAPIMIC (line 331) | type userAuthGSSAPIMIC struct
  constant msgUserAuthGSSAPIErrTok (line 336) | msgUserAuthGSSAPIErrTok = 64
  type userAuthGSSAPIErrTok (line 338) | type userAuthGSSAPIErrTok struct
  constant msgUserAuthGSSAPIError (line 343) | msgUserAuthGSSAPIError = 65
  type userAuthGSSAPIError (line 345) | type userAuthGSSAPIError struct
  constant msgPing (line 353) | msgPing = 192
  type pingMsg (line 355) | type pingMsg struct
  constant msgPong (line 360) | msgPong = 193
  type pongMsg (line 362) | type pongMsg struct
  function typeTags (line 368) | func typeTags(structType reflect.Type) (tags []byte) {
  function fieldError (line 381) | func fieldError(t reflect.Type, field int, problem string) error {
  function Unmarshal (line 396) | func Unmarshal(data []byte, out any) error {
  function Marshal (line 519) | func Marshal(msg any) []byte {
  function marshalStruct (line 524) | func marshalStruct(out []byte, msg any) []byte {
  function parseString (line 607) | func parseString(in []byte) (out, rest []byte, ok bool) {
  function parseNameList (line 627) | func parseNameList(in []byte) (out []string, rest []byte, ok bool) {
  function parseInt (line 644) | func parseInt(in []byte) (out *big.Int, rest []byte, ok bool) {
  function parseUint32 (line 668) | func parseUint32(in []byte) (uint32, []byte, bool) {
  function parseUint64 (line 675) | func parseUint64(in []byte) (uint64, []byte, bool) {
  function intLength (line 682) | func intLength(n *big.Int) int {
  function marshalUint32 (line 707) | func marshalUint32(to []byte, n uint32) []byte {
  function marshalUint64 (line 712) | func marshalUint64(to []byte, n uint64) []byte {
  function marshalInt (line 717) | func marshalInt(to []byte, n *big.Int) []byte {
  function writeInt (line 764) | func writeInt(w io.Writer, n *big.Int) {
  function writeString (line 771) | func writeString(w io.Writer, s []byte) {
  function stringLength (line 781) | func stringLength(n int) int {
  function marshalString (line 785) | func marshalString(to []byte, s []byte) []byte {
  function decode (line 798) | func decode(packet []byte) (any, error) {

FILE: gossh/crypto/ssh/mux.go
  constant debugMux (line 18) | debugMux = false
  type chanList (line 21) | type chanList struct
    method add (line 36) | func (c *chanList) add(ch *channel) uint32 {
    method getChan (line 50) | func (c *chanList) getChan(id uint32) *channel {
    method remove (line 61) | func (c *chanList) remove(id uint32) {
    method dropAll (line 71) | func (c *chanList) dropAll() []*channel {
  type mux (line 88) | type mux struct
    method Wait (line 106) | func (m *mux) Wait() error {
    method sendMessage (line 132) | func (m *mux) sendMessage(msg any) error {
    method SendRequest (line 140) | func (m *mux) SendRequest(name string, wantReply bool, payload []byte)...
    method ackRequest (line 174) | func (m *mux) ackRequest(ok bool, data []byte) error {
    method Close (line 181) | func (m *mux) Close() error {
    method loop (line 187) | func (m *mux) loop() {
    method onePacket (line 214) | func (m *mux) onePacket() error {
    method handleGlobalPacket (line 255) | func (m *mux) handleGlobalPacket(packet []byte) error {
    method handleChannelOpen (line 279) | func (m *mux) handleChannelOpen(packet []byte) error {
    method OpenChannel (line 303) | func (m *mux) OpenChannel(chanType string, extra []byte) (Channel, <-c...
    method openChannel (line 312) | func (m *mux) openChannel(chanType string, extra []byte) (*channel, er...
    method handleUnknownChannelPacket (line 338) | func (m *mux) handleUnknownChannelPacket(id uint32, packet []byte) err...
  function newMux (line 116) | func newMux(p packetConn) *mux {

FILE: gossh/crypto/ssh/server.go
  type Permissions (line 21) | type Permissions struct
  type GSSAPIWithMICConfig (line 48) | type GSSAPIWithMICConfig struct
  type ServerConfig (line 63) | type ServerConfig struct
    method AddHostKey (line 140) | func (s *ServerConfig) AddHostKey(key Signer) {
  type cachedPubKey (line 153) | type cachedPubKey struct
  constant maxCachedPubKeys (line 160) | maxCachedPubKeys = 16
  type pubKeyCache (line 166) | type pubKeyCache struct
    method get (line 171) | func (c *pubKeyCache) get(user string, pubKeyData []byte) (cachedPubKe...
    method add (line 181) | func (c *pubKeyCache) add(candidate cachedPubKey) {
  type ServerConn (line 189) | type ServerConn struct
  function NewServerConn (line 205) | func NewServerConn(c net.Conn, config *ServerConfig) (*ServerConn, <-cha...
  function signAndMarshal (line 243) | func signAndMarshal(k AlgorithmSigner, rand io.Reader, data []byte, algo...
  method serverHandshake (line 253) | func (s *connection) serverHandshake(config *ServerConfig) (*Permissions...
  function checkSourceAddress (line 312) | func checkSourceAddress(addr net.Addr, sourceAddrs string) error {
  function gssExchangeToken (line 342) | func gssExchangeToken(gssapiConfig *GSSAPIWithMICConfig, token []byte, s...
  function isAlgoCompatible (line 395) | func isAlgoCompatible(algo, sigFormat string) bool {
  type ServerAuthError (line 415) | type ServerAuthError struct
    method Error (line 421) | func (l ServerAuthError) Error() string {
  method serverAuthenticate (line 436) | func (s *connection) serverAuthenticate(config *ServerConfig) (*Permissi...
  type sshClientKeyboardInteractive (line 750) | type sshClientKeyboardInteractive struct
    method Challenge (line 754) | func (c *sshClientKeyboardInteractive) Challenge(name, instruction str...

FILE: gossh/crypto/ssh/session.go
  type Signal (line 19) | type Signal
  constant SIGABRT (line 23) | SIGABRT Signal = "ABRT"
  constant SIGALRM (line 24) | SIGALRM Signal = "ALRM"
  constant SIGFPE (line 25) | SIGFPE  Signal = "FPE"
  constant SIGHUP (line 26) | SIGHUP  Signal = "HUP"
  constant SIGILL (line 27) | SIGILL  Signal = "ILL"
  constant SIGINT (line 28) | SIGINT  Signal = "INT"
  constant SIGKILL (line 29) | SIGKILL Signal = "KILL"
  constant SIGPIPE (line 30) | SIGPIPE Signal = "PIPE"
  constant SIGQUIT (line 31) | SIGQUIT Signal = "QUIT"
  constant SIGSEGV (line 32) | SIGSEGV Signal = "SEGV"
  constant SIGTERM (line 33) | SIGTERM Signal = "TERM"
  constant SIGUSR1 (line 34) | SIGUSR1 Signal = "USR1"
  constant SIGUSR2 (line 35) | SIGUSR2 Signal = "USR2"
  type TerminalModes (line 52) | type TerminalModes
  constant tty_OP_END (line 56) | tty_OP_END    = 0
  constant VINTR (line 57) | VINTR         = 1
  constant VQUIT (line 58) | VQUIT         = 2
  constant VERASE (line 59) | VERASE        = 3
  constant VKILL (line 60) | VKILL         = 4
  constant VEOF (line 61) | VEOF          = 5
  constant VEOL (line 62) | VEOL          = 6
  constant VEOL2 (line 63) | VEOL2         = 7
  constant VSTART (line 64) | VSTART        = 8
  constant VSTOP (line 65) | VSTOP         = 9
  constant VSUSP (line 66) | VSUSP         = 10
  constant VDSUSP (line 67) | VDSUSP        = 11
  constant VREPRINT (line 68) | VREPRINT      = 12
  constant VWERASE (line 69) | VWERASE       = 13
  constant VLNEXT (line 70) | VLNEXT        = 14
  constant VFLUSH (line 71) | VFLUSH        = 15
  constant VSWTCH (line 72) | VSWTCH        = 16
  constant VSTATUS (line 73) | VSTATUS       = 17
  constant VDISCARD (line 74) | VDISCARD      = 18
  constant IGNPAR (line 75) | IGNPAR        = 30
  constant PARMRK (line 76) | PARMRK        = 31
  constant INPCK (line 77) | INPCK         = 32
  constant ISTRIP (line 78) | ISTRIP        = 33
  constant INLCR (line 79) | INLCR         = 34
  constant IGNCR (line 80) | IGNCR         = 35
  constant ICRNL (line 81) | ICRNL         = 36
  constant IUCLC (line 82) | IUCLC         = 37
  constant IXON (line 83) | IXON          = 38
  constant IXANY (line 84) | IXANY         = 39
  constant IXOFF (line 85) | IXOFF         = 40
  constant IMAXBEL (line 86) | IMAXBEL       = 41
  constant IUTF8 (line 87) | IUTF8         = 42
  constant ISIG (line 88) | ISIG          = 50
  constant ICANON (line 89) | ICANON        = 51
  constant XCASE (line 90) | XCASE         = 52
  constant ECHO (line 91) | ECHO          = 53
  constant ECHOE (line 92) | ECHOE         = 54
  constant ECHOK (line 93) | ECHOK         = 55
  constant ECHONL (line 94) | ECHONL        = 56
  constant NOFLSH (line 95) | NOFLSH        = 57
  constant TOSTOP (line 96) | TOSTOP        = 58
  constant IEXTEN (line 97) | IEXTEN        = 59
  constant ECHOCTL (line 98) | ECHOCTL       = 60
  constant ECHOKE (line 99) | ECHOKE        = 61
  constant PENDIN (line 100) | PENDIN        = 62
  constant OPOST (line 101) | OPOST         = 70
  constant OLCUC (line 102) | OLCUC         = 71
  constant ONLCR (line 103) | ONLCR         = 72
  constant OCRNL (line 104) | OCRNL         = 73
  constant ONOCR (line 105) | ONOCR         = 74
  constant ONLRET (line 106) | ONLRET        = 75
  constant CS7 (line 107) | CS7           = 90
  constant CS8 (line 108) | CS8           = 91
  constant PARENB (line 109) | PARENB        = 92
  constant PARODD (line 110) | PARODD        = 93
  constant TTY_OP_ISPEED (line 111) | TTY_OP_ISPEED = 128
  constant TTY_OP_OSPEED (line 112) | TTY_OP_OSPEED = 129
  type Session (line 116) | type Session struct
    method SendRequest (line 151) | func (s *Session) SendRequest(name string, wantReply bool, payload []b...
    method Close (line 155) | func (s *Session) Close() error {
    method Setenv (line 167) | func (s *Session) Setenv(name, value string) error {
    method RequestPty (line 190) | func (s *Session) RequestPty(term string, h, w int, termmodes Terminal...
    method RequestSubsystem (line 223) | func (s *Session) RequestSubsystem(subsystem string) error {
    method WindowChange (line 243) | func (s *Session) WindowChange(h, w int) error {
    method Signal (line 261) | func (s *Session) Signal(sig Signal) error {
    method Start (line 278) | func (s *Session) Start(cmd string) error {
    method Run (line 309) | func (s *Session) Run(cmd string) error {
    method Output (line 318) | func (s *Session) Output(cmd string) ([]byte, error) {
    method CombinedOutput (line 341) | func (s *Session) CombinedOutput(cmd string) ([]byte, error) {
    method Shell (line 357) | func (s *Session) Shell() error {
    method start (line 372) | func (s *Session) start() error {
    method Wait (line 399) | func (s *Session) Wait() error {
    method wait (line 420) | func (s *Session) wait(reqs <-chan *Request) error {
    method stdin (line 479) | func (s *Session) stdin() {
    method stdout (line 503) | func (s *Session) stdout() {
    method stderr (line 516) | func (s *Session) stderr() {
    method StdinPipe (line 541) | func (s *Session) StdinPipe() (io.WriteCloser, error) {
    method StdoutPipe (line 558) | func (s *Session) StdoutPipe() (io.Reader, error) {
    method StderrPipe (line 575) | func (s *Session) StderrPipe() (io.Reader, error) {
  type setenvRequest (line 160) | type setenvRequest struct
  type ptyRequestMsg (line 180) | type ptyRequestMsg struct
  type subsystemRequestMsg (line 217) | type subsystemRequestMsg struct
  type ptyWindowChangeMsg (line 235) | type ptyWindowChangeMsg struct
  type signalMsg (line 255) | type signalMsg struct
  type execMsg (line 271) | type execMsg struct
  type singleWriter (line 328) | type singleWriter struct
    method Write (line 333) | func (w *singleWriter) Write(p []byte) (int, error) {
  type ExitMissingError (line 473) | type ExitMissingError struct
    method Error (line 475) | func (e *ExitMissingError) Error() string {
  type sessionStdin (line 530) | type sessionStdin struct
    method Close (line 535) | func (s *sessionStdin) Close() error {
  function newSession (line 587) | func newSession(ch Channel, reqs <-chan *Request) (*Session, error) {
  type ExitError (line 600) | type ExitError struct
    method Error (line 604) | func (e *ExitError) Error() string {
  type Waitmsg (line 610) | type Waitmsg struct
    method ExitStatus (line 618) | func (w Waitmsg) ExitStatus() int {
    method Signal (line 624) | func (w Waitmsg) Signal() string {
    method Msg (line 629) | func (w Waitmsg) Msg() string {
    method Lang (line 634) | func (w Waitmsg) Lang() string {
    method String (line 638) | func (w Waitmsg) String() string {

FILE: gossh/crypto/ssh/ssh_gss.go
  function init (line 14) | func init() {
  type GSSAPIClient (line 19) | type GSSAPIClient interface
  type GSSAPIServer (line 58) | type GSSAPIServer interface
  type userAuthRequestGSSAPI (line 99) | type userAuthRequestGSSAPI struct
  function parseGSSAPIPayload (line 104) | func parseGSSAPIPayload(payload []byte) (*userAuthRequestGSSAPI, error) {
  function buildMIC (line 131) | func buildMIC(sessionID string, username string, service string, authMet...

FILE: gossh/crypto/ssh/streamlocal.go
  type streamLocalChannelOpenDirectMsg (line 14) | type streamLocalChannelOpenDirectMsg struct
  type forwardedStreamLocalPayload (line 22) | type forwardedStreamLocalPayload struct
  type streamLocalChannelForwardMsg (line 29) | type streamLocalChannelForwardMsg struct
  method ListenUnix (line 34) | func (c *Client) ListenUnix(socketPath string) (net.Listener, error) {
  method dialStreamLocal (line 52) | func (c *Client) dialStreamLocal(socketPath string) (Channel, error) {
  type unixListener (line 64) | type unixListener struct
    method Accept (line 72) | func (l *unixListener) Accept() (net.Conn, error) {
    method Close (line 97) | func (l *unixListener) Close() error {
    method Addr (line 111) | func (l *unixListener) Addr() net.Addr {

FILE: gossh/crypto/ssh/tcpip.go
  method Listen (line 25) | func (c *Client) Listen(n, addr string) (net.Listener, error) {
  constant openSSHPrefix (line 47) | openSSHPrefix = "OpenSSH_"
  function isBrokenOpenSSHVersion (line 54) | func isBrokenOpenSSHVersion(versionStr string) bool {
  method autoPortListenWorkaround (line 72) | func (c *Client) autoPortListenWorkaround(laddr *net.TCPAddr) (net.Liste...
  type channelForwardMsg (line 89) | type channelForwardMsg struct
  method handleForwards (line 97) | func (c *Client) handleForwards() {
  method ListenTCP (line 105) | func (c *Client) ListenTCP(laddr *net.TCPAddr) (net.Listener, error) {
  type forwardList (line 144) | type forwardList struct
    method add (line 164) | func (l *forwardList) add(addr net.Addr) chan forward {
    method handleChannels (line 195) | func (l *forwardList) handleChannels(in <-chan NewChannel) {
    method remove (line 255) | func (l *forwardList) remove(addr net.Addr) {
    method closeAll (line 268) | func (l *forwardList) closeAll() {
    method forward (line 277) | func (l *forwardList) forward(laddr, raddr net.Addr, ch NewChannel) bo...
  type forwardEntry (line 151) | type forwardEntry struct
  type forward (line 159) | type forward struct
  type forwardedTCPPayload (line 176) | type forwardedTCPPayload struct
  function parseTCPAddr (line 184) | func parseTCPAddr(addr string, port uint32) (*net.TCPAddr, error) {
  type tcpListener (line 289) | type tcpListener struct
    method Accept (line 297) | func (l *tcpListener) Accept() (net.Conn, error) {
    method Close (line 316) | func (l *tcpListener) Close() error {
    method Addr (line 332) | func (l *tcpListener) Addr() net.Addr {
  method DialContext (line 343) | func (c *Client) DialContext(ctx context.Context, n, addr string) (net.C...
  method Dial (line 372) | func (c *Client) Dial(n, addr string) (net.Conn, error) {
  method DialTCP (line 424) | func (c *Client) DialTCP(n string, laddr, raddr *net.TCPAddr) (net.Conn,...
  type channelOpenDirectMsg (line 443) | type channelOpenDirectMsg struct
  method dial (line 450) | func (c *Client) dial(laddr string, lport int, raddr string, rport int) ...
  type tcpChan (line 465) | type tcpChan struct
  type chanConn (line 471) | type chanConn struct
    method LocalAddr (line 477) | func (t *chanConn) LocalAddr() net.Addr {
    method RemoteAddr (line 482) | func (t *chanConn) RemoteAddr() net.Addr {
    method SetDeadline (line 488) | func (t *chanConn) SetDeadline(deadline time.Time) error {
    method SetReadDeadline (line 499) | func (t *chanConn) SetReadDeadline(deadline time.Time) error {
    method SetWriteDeadline (line 507) | func (t *chanConn) SetWriteDeadline(deadline time.Time) error {

FILE: gossh/crypto/ssh/terminal/terminal.go
  function NewTerminal (line 29) | func NewTerminal(c io.ReadWriter, prompt string) *Terminal {
  function IsTerminal (line 43) | func IsTerminal(fd int) bool {
  function ReadPassword (line 50) | func ReadPassword(fd int) ([]byte, error) {
  function MakeRaw (line 57) | func MakeRaw(fd int) (*State, error) {
  function Restore (line 63) | func Restore(fd int, oldState *State) error {
  function GetState (line 69) | func GetState(fd int) (*State, error) {
  function GetSize (line 74) | func GetSize(fd int) (width, height int, err error) {

FILE: gossh/crypto/ssh/transport.go
  constant debugTransport (line 17) | debugTransport = false
  constant gcm128CipherID (line 20) | gcm128CipherID = "aes128-gcm@openssh.com"
  constant gcm256CipherID (line 21) | gcm256CipherID = "aes256-gcm@openssh.com"
  constant aes128cbcID (line 22) | aes128cbcID    = "aes128-cbc"
  constant tripledescbcID (line 23) | tripledescbcID = "3des-cbc"
  type packetConn (line 28) | type packetConn interface
  type transport (line 43) | type transport struct
    method setStrictMode (line 80) | func (t *transport) setStrictMode() error {
    method setInitialKEXDone (line 88) | func (t *transport) setInitialKEXDone() {
    method prepareKeyChange (line 95) | func (t *transport) prepareKeyChange(algs *algorithms, kexResult *kexR...
    method printPacket (line 111) | func (t *transport) printPacket(p []byte, write bool) {
    method readPacket (line 128) | func (t *transport) readPacket() (p []byte, err error) {
    method writePacket (line 188) | func (t *transport) writePacket(packet []byte) error {
  type packetCipher (line 59) | type packetCipher interface
  type connectionState (line 73) | type connectionState struct
    method readPacket (line 146) | func (s *connectionState) readPacket(r *bufio.Reader, strictMode bool)...
    method writePacket (line 195) | func (s *connectionState) writePacket(w *bufio.Writer, rand io.Reader,...
  function newTransport (line 220) | func newTransport(rwc io.ReadWriteCloser, rand io.Reader, isClient bool)...
  type direction (line 248) | type direction struct
  function newPacketCipher (line 262) | func newPacketCipher(d direction, algs directionAlgorithms, kex *kexResu...
  function generateKeyMaterial (line 283) | func generateKeyMaterial(out, tag []byte, r *kexResult) {
  constant packageVersion (line 308) | packageVersion = "SSH-2.0-Go"
  function exchangeVersions (line 313) | func exchangeVersions(rw io.ReadWriter, versionLine []byte) (them []byte...
  constant maxVersionStringBytes (line 335) | maxVersionStringBytes = 255
  function readVersion (line 338) | func readVersion(r io.Reader) ([]byte, error) {

FILE: gossh/gin/auth.go
  constant AuthUserKey (line 17) | AuthUserKey = "user"
  constant AuthProxyUserKey (line 20) | AuthProxyUserKey = "proxy_user"
  type Accounts (line 23) | type Accounts
  type authPair (line 25) | type authPair struct
  type authPairs (line 30) | type authPairs
    method searchCredential (line 32) | func (a authPairs) searchCredential(authValue string) (string, bool) {
  function BasicAuthForRealm (line 48) | func BasicAuthForRealm(accounts Accounts, realm string) HandlerFunc {
  function BasicAuth (line 72) | func BasicAuth(accounts Accounts) HandlerFunc {
  function processAccounts (line 76) | func processAccounts(accounts Accounts) authPairs {
  function authorizationHeader (line 91) | func authorizationHeader(user, password string) string {
  function BasicAuthForProxy (line 98) | func BasicAuthForProxy(accounts Accounts, realm string) HandlerFunc {

FILE: gossh/gin/binding/binding.go
  constant MIMEJSON (line 11) | MIMEJSON              = "application/json"
  constant MIMEHTML (line 12) | MIMEHTML              = "text/html"
  constant MIMEXML (line 13) | MIMEXML               = "application/xml"
  constant MIMEXML2 (line 14) | MIMEXML2              = "text/xml"
  constant MIMEPlain (line 15) | MIMEPlain             = "text/plain"
  constant MIMEPOSTForm (line 16) | MIMEPOSTForm          = "application/x-www-form-urlencoded"
  constant MIMEMultipartPOSTForm (line 17) | MIMEMultipartPOSTForm = "multipart/form-data"
  type Binding (line 23) | type Binding interface
  type BindingBody (line 30) | type BindingBody interface
  type BindingUri (line 37) | type BindingUri interface
  type StructValidator (line 46) | type StructValidator interface
  function Default (line 80) | func Default(method, contentType string) Binding {
  function validate (line 97) | func validate(obj any) error {

FILE: gossh/gin/binding/default_validator.go
  type defaultValidator (line 16) | type defaultValidator struct
    method ValidateStruct (line 49) | func (v *defaultValidator) ValidateStruct(obj any) error {
    method validateStruct (line 81) | func (v *defaultValidator) validateStruct(obj any) error {
    method Engine (line 90) | func (v *defaultValidator) Engine() any {
    method lazyinit (line 95) | func (v *defaultValidator) lazyinit() {
  type SliceValidationError (line 21) | type SliceValidationError
    method Error (line 24) | func (err SliceValidationError) Error() string {

FILE: gossh/gin/binding/form.go
  constant defaultMemory (line 12) | defaultMemory = 32 << 20
  type formBinding (line 14) | type formBinding struct
    method Name (line 18) | func (formBinding) Name() string {
    method Bind (line 22) | func (formBinding) Bind(req *http.Request, obj any) error {
  type formPostBinding (line 15) | type formPostBinding struct
    method Name (line 35) | func (formPostBinding) Name() string {
    method Bind (line 39) | func (formPostBinding) Bind(req *http.Request, obj any) error {
  type formMultipartBinding (line 16) | type formMultipartBinding struct
    method Name (line 49) | func (formMultipartBinding) Name() string {
    method Bind (line 53) | func (formMultipartBinding) Bind(req *http.Request, obj any) error {

FILE: gossh/gin/binding/form_mapping.go
  function mapURI (line 30) | func mapURI(ptr any, m map[string][]string) error {
  function mapForm (line 34) | func mapForm(ptr any, form map[string][]string) error {
  function MapFormWithTag (line 38) | func MapFormWithTag(ptr any, form map[string][]string, tag string) error {
  function mapFormByTag (line 44) | func mapFormByTag(ptr any, form map[string][]string, tag string) error {
  type setter (line 64) | type setter interface
  type formSource (line 68) | type formSource
    method TrySet (line 73) | func (form formSource) TrySet(value reflect.Value, field reflect.Struc...
  function mappingByPtr (line 77) | func mappingByPtr(ptr any, setter setter, tag string) error {
  function mapping (line 82) | func mapping(value reflect.Value, field reflect.StructField, setter sett...
  type setOptions (line 136) | type setOptions struct
  function tryToSetValue (line 141) | func tryToSetValue(value reflect.Value, field reflect.StructField, sette...
  function setByForm (line 168) | func setByForm(value reflect.Value, field reflect.StructField, form map[...
  function setWithProperType (line 201) | func setWithProperType(val string, value reflect.Value, field reflect.St...
  function setIntField (line 256) | func setIntField(val string, bitSize int, field reflect.Value) error {
  function setUintField (line 267) | func setUintField(val string, bitSize int, field reflect.Value) error {
  function setBoolField (line 278) | func setBoolField(val string, field reflect.Value) error {
  function setFloatField (line 289) | func setFloatField(val string, bitSize int, field reflect.Value) error {
  function setTimeField (line 300) | func setTimeField(val string, structField reflect.StructField, value ref...
  function setArray (line 350) | func setArray(vals []string, value reflect.Value, field reflect.StructFi...
  function setSlice (line 360) | func setSlice(vals []string, value reflect.Value, field reflect.StructFi...
  function setTimeDuration (line 370) | func setTimeDuration(val string, value reflect.Value) error {
  function head (line 379) | func head(str, sep string) (head string, tail string) {
  function setFormMap (line 387) | func setFormMap(ptr any, form map[string][]string) error {

FILE: gossh/gin/binding/header.go
  type headerBinding (line 13) | type headerBinding struct
    method Name (line 15) | func (headerBinding) Name() string {
    method Bind (line 19) | func (headerBinding) Bind(req *http.Request, obj any) error {
  function mapHeader (line 28) | func mapHeader(ptr any, h map[string][]string) error {
  type headerSource (line 32) | type headerSource
    method TrySet (line 36) | func (hs headerSource) TrySet(value reflect.Value, field reflect.Struc...

FILE: gossh/gin/binding/json.go
  type jsonBinding (line 27) | type jsonBinding struct
    method Name (line 29) | func (jsonBinding) Name() string {
    method Bind (line 33) | func (jsonBinding) Bind(req *http.Request, obj any) error {
    method BindBody (line 40) | func (jsonBinding) BindBody(body []byte, obj any) error {
  function decodeJSON (line 44) | func decodeJSON(r io.Reader, obj any) error {

FILE: gossh/gin/binding/multipart_form_mapping.go
  type multipartRequest (line 14) | type multipartRequest
    method TrySet (line 27) | func (r *multipartRequest) TrySet(value reflect.Value, field reflect.S...
  function setByMultipartFormFile (line 35) | func setByMultipartFormFile(value reflect.Value, field reflect.StructFie...
  function setArrayOfMultipartFormFiles (line 63) | func setArrayOfMultipartFormFiles(value reflect.Value, field reflect.Str...

FILE: gossh/gin/binding/query.go
  type queryBinding (line 9) | type queryBinding struct
    method Name (line 11) | func (queryBinding) Name() string {
    method Bind (line 15) | func (queryBinding) Bind(req *http.Request, obj any) error {

FILE: gossh/gin/binding/uri.go
  type uriBinding (line 7) | type uriBinding struct
    method Name (line 9) | func (uriBinding) Name() string {
    method BindUri (line 13) | func (uriBinding) BindUri(m map[string][]string, obj any) error {

FILE: gossh/gin/binding/xml.go
  type xmlBinding (line 14) | type xmlBinding struct
    method Name (line 16) | func (xmlBinding) Name() string {
    method Bind (line 20) | func (xmlBinding) Bind(req *http.Request, obj any) error {
    method BindBody (line 24) | func (xmlBinding) BindBody(body []byte, obj any) error {
  function decodeXML (line 27) | func decodeXML(r io.Reader, obj any) error {

FILE: gossh/gin/context.go
  constant MIMEJSON (line 28) | MIMEJSON              = binding.MIMEJSON
  constant MIMEHTML (line 29) | MIMEHTML              = binding.MIMEHTML
  constant MIMEXML (line 30) | MIMEXML               = binding.MIMEXML
  constant MIMEPlain (line 31) | MIMEPlain             = binding.MIMEPlain
  constant MIMEPOSTForm (line 32) | MIMEPOSTForm          = binding.MIMEPOSTForm
  constant MIMEMultipartPOSTForm (line 33) | MIMEMultipartPOSTForm = binding.MIMEMultipartPOSTForm
  constant BodyBytesKey (line 37) | BodyBytesKey = "_gin-gonic/gin/bodybyteskey"
  constant ContextKey (line 40) | ContextKey = "_gin-gonic/gin/contextkey"
  type ContextKeyType (line 42) | type ContextKeyType
  constant ContextRequestKey (line 44) | ContextRequestKey ContextKeyType = 0
  constant abortIndex (line 47) | abortIndex int8 = math.MaxInt8 >> 1
  type Context (line 51) | type Context struct
    method reset (line 93) | func (c *Context) reset() {
    method Copy (line 112) | func (c *Context) Copy() *Context {
    method HandlerName (line 142) | func (c *Context) HandlerName() string {
    method HandlerNames (line 148) | func (c *Context) HandlerNames() []string {
    method Handler (line 157) | func (c *Context) Handler() HandlerFunc {
    method FullPath (line 167) | func (c *Context) FullPath() string {
    method Next (line 178) | func (c *Context) Next() {
    method IsAborted (line 187) | func (c *Context) IsAborted() bool {
    method Abort (line 195) | func (c *Context) Abort() {
    method AbortWithStatus (line 201) | func (c *Context) AbortWithStatus(code int) {
    method AbortWithStatusJSON (line 210) | func (c *Context) AbortWithStatusJSON(code int, jsonObj any) {
    method AbortWithError (line 218) | func (c *Context) AbortWithError(code int, err error) *Error {
    method Error (line 232) | func (c *Context) Error(err error) *Error {
    method Set (line 256) | func (c *Context) Set(key string, value any) {
    method Get (line 268) | func (c *Context) Get(key string) (value any, exists bool) {
    method MustGet (line 276) | func (c *Context) MustGet(key string) any {
    method GetString (line 284) | func (c *Context) GetString(key string) (s string) {
    method GetBool (line 292) | func (c *Context) GetBool(key string) (b bool) {
    method GetInt (line 300) | func (c *Context) GetInt(key string) (i int) {
    method GetInt64 (line 308) | func (c *Context) GetInt64(key string) (i64 int64) {
    method GetUint (line 316) | func (c *Context) GetUint(key string) (ui uint) {
    method GetUint64 (line 324) | func (c *Context) GetUint64(key string) (ui64 uint64) {
    method GetFloat64 (line 332) | func (c *Context) GetFloat64(key string) (f64 float64) {
    method GetTime (line 340) | func (c *Context) GetTime(key string) (t time.Time) {
    method GetDuration (line 348) | func (c *Context) GetDuration(key string) (d time.Duration) {
    method GetStringSlice (line 356) | func (c *Context) GetStringSlice(key string) (ss []string) {
    method GetStringMap (line 364) | func (c *Context) GetStringMap(key string) (sm map[string]any) {
    method GetStringMapString (line 372) | func (c *Context) GetStringMapString(key string) (sms map[string]strin...
    method GetStringMapStringSlice (line 380) | func (c *Context) GetStringMapStringSlice(key string) (smss map[string...
    method Param (line 400) | func (c *Context) Param(key string) string {
    method AddParam (line 409) | func (c *Context) AddParam(key, value string) {
    method Query (line 422) | func (c *Context) Query(key string) (value string) {
    method DefaultQuery (line 435) | func (c *Context) DefaultQuery(key, defaultValue string) string {
    method GetQuery (line 451) | func (c *Context) GetQuery(key string) (string, bool) {
    method QueryArray (line 460) | func (c *Context) QueryArray(key string) (values []string) {
    method initQueryCache (line 465) | func (c *Context) initQueryCache() {
    method GetQueryArray (line 477) | func (c *Context) GetQueryArray(key string) (values []string, ok bool) {
    method QueryMap (line 484) | func (c *Context) QueryMap(key string) (dicts map[string]string) {
    method GetQueryMap (line 491) | func (c *Context) GetQueryMap(key string) (map[string]string, bool) {
    method PostForm (line 498) | func (c *Context) PostForm(key string) (value string) {
    method DefaultPostForm (line 506) | func (c *Context) DefaultPostForm(key, defaultValue string) string {
    method GetPostForm (line 521) | func (c *Context) GetPostForm(key string) (string, bool) {
    method PostFormArray (line 530) | func (c *Context) PostFormArray(key string) (values []string) {
    method initFormCache (line 535) | func (c *Context) initFormCache() {
    method GetPostFormArray (line 550) | func (c *Context) GetPostFormArray(key string) (values []string, ok bo...
    method PostFormMap (line 557) | func (c *Context) PostFormMap(key string) (dicts map[string]string) {
    method GetPostFormMap (line 564) | func (c *Context) GetPostFormMap(key string) (map[string]string, bool) {
    method get (line 570) | func (c *Context) get(m map[string][]string, key string) (map[string]s...
    method FormFile (line 585) | func (c *Context) FormFile(name string) (*multipart.FileHeader, error) {
    method MultipartForm (line 600) | func (c *Context) MultipartForm() (*multipart.Form, error) {
    method SaveUploadedFile (line 606) | func (c *Context) SaveUploadedFile(file *multipart.FileHeader, dst str...
    method Bind (line 636) | func (c *Context) Bind(obj any) error {
    method BindJSON (line 642) | func (c *Context) BindJSON(obj any) error {
    method BindXML (line 647) | func (c *Context) BindXML(obj any) error {
    method BindQuery (line 652) | func (c *Context) BindQuery(obj any) error {
    method BindHeader (line 657) | func (c *Context) BindHeader(obj any) error {
    method BindUri (line 663) | func (c *Context) BindUri(obj any) error {
    method MustBindWith (line 674) | func (c *Context) MustBindWith(obj any, b binding.Binding) error {
    method ShouldBind (line 691) | func (c *Context) ShouldBind(obj any) error {
    method ShouldBindJSON (line 697) | func (c *Context) ShouldBindJSON(obj any) error {
    method ShouldBindXML (line 702) | func (c *Context) ShouldBindXML(obj any) error {
    method ShouldBindQuery (line 707) | func (c *Context) ShouldBindQuery(obj any) error {
    method ShouldBindHeader (line 712) | func (c *Context) ShouldBindHeader(obj any) error {
    method ShouldBindUri (line 717) | func (c *Context) ShouldBindUri(obj any) error {
    method ShouldBindWith (line 727) | func (c *Context) ShouldBindWith(obj any, b binding.Binding) error {
    method ShouldBindBodyWith (line 736) | func (c *Context) ShouldBindBodyWith(obj any, bb binding.BindingBody) ...
    method ShouldBindBodyWithJSON (line 754) | func (c *Context) ShouldBindBodyWithJSON(obj any) error {
    method ShouldBindBodyWithXML (line 759) | func (c *Context) ShouldBindBodyWithXML(obj any) error {
    method ClientIP (line 768) | func (c *Context) ClientIP() string {
    method RemoteIP (line 798) | func (c *Context) RemoteIP() string {
    method ContentType (line 807) | func (c *Context) ContentType() string {
    method IsWebsocket (line 813) | func (c *Context) IsWebsocket() bool {
    method requestHeader (line 821) | func (c *Context) requestHeader(key string) string {
    method Status (line 843) | func (c *Context) Status(code int) {
    method Header (line 850) | func (c *Context) Header(key, value string) {
    method GetHeader (line 859) | func (c *Context) GetHeader(key string) string {
    method GetRawData (line 864) | func (c *Context) GetRawData() ([]byte, error) {
    method SetSameSite (line 872) | func (c *Context) SetSameSite(samesite http.SameSite) {
    method SetCookie (line 879) | func (c *Context) SetCookie(name, value string, maxAge int, path, doma...
    method Cookie (line 899) | func (c *Context) Cookie(name string) (string, error) {
    method Render (line 909) | func (c *Context) Render(code int, r render.Render) {
    method HTML (line 928) | func (c *Context) HTML(code int, name string, obj any) {
    method IndentedJSON (line 937) | func (c *Context) IndentedJSON(code int, obj any) {
    method SecureJSON (line 944) | func (c *Context) SecureJSON(code int, obj any) {
    method JSONP (line 951) | func (c *Context) JSONP(code int, obj any) {
    method JSON (line 962) | func (c *Context) JSON(code int, obj any) {
    method AsciiJSON (line 968) | func (c *Context) AsciiJSON(code int, obj any) {
    method PureJSON (line 974) | func (c *Context) PureJSON(code int, obj any) {
    method XML (line 980) | func (c *Context) XML(code int, obj any) {
    method String (line 985) | func (c *Context) String(code int, format string, values ...any) {
    method Redirect (line 990) | func (c *Context) Redirect(code int, location string) {
    method Data (line 999) | func (c *Context) Data(code int, contentType string, data []byte) {
    method DataFromReader (line 1007) | func (c *Context) DataFromReader(code int, contentLength int64, conten...
    method File (line 1017) | func (c *Context) File(filepath string) {
    method FileFromFS (line 1022) | func (c *Context) FileFromFS(filepath string, fs http.FileSystem) {
    method FileAttachment (line 1040) | func (c *Context) FileAttachment(filepath, filename string) {
    method SSEvent (line 1050) | func (c *Context) SSEvent(name string, message any) {
    method Stream (line 1059) | func (c *Context) Stream(step func(w io.Writer) bool) bool {
    method Negotiate (line 1092) | func (c *Context) Negotiate(code int, config Negotiate) {
    method NegotiateFormat (line 1112) | func (c *Context) NegotiateFormat(offered ...string) string {
    method SetAccepted (line 1143) | func (c *Context) SetAccepted(formats ...string) {
    method hasRequestContext (line 1152) | func (c *Context) hasRequestContext() bool {
    method Deadline (line 1159) | func (c *Context) Deadline() (deadline time.Time, ok bool) {
    method Done (line 1167) | func (c *Context) Done() <-chan struct{} {
    method Err (line 1175) | func (c *Context) Err() error {
    method Value (line 1185) | func (c *Context) Value(key any) any {
  function bodyAllowedForStatus (line 830) | func bodyAllowedForStatus(status int) bool {
  function escapeQuotes (line 1034) | func escapeQuotes(s string) string {
  type Negotiate (line 1082) | type Negotiate struct

FILE: gossh/gin/debug.go
  constant ginSupportMinGoVer (line 15) | ginSupportMinGoVer = 18
  function IsDebugging (line 19) | func IsDebugging() bool {
  function debugPrintRoute (line 29) | func debugPrintRoute(httpMethod, absolutePath string, handlers HandlersC...
  function debugPrintLoadTemplate (line 41) | func debugPrintLoadTemplate(tmpl *template.Template) {
  function debugPrint (line 53) | func debugPrint(format string, values ...any) {
  function getMinVer (line 69) | func getMinVer(v string) (uint64, error) {
  function debugPrintWARNINGDefault (line 78) | func debugPrintWARNINGDefault() {
  function debugPrintWARNINGNew (line 89) | func debugPrintWARNINGNew() {
  function debugPrintWARNINGSetHTMLTemplate (line 97) | func debugPrintWARNINGSetHTMLTemplate() {
  function debugPrintError (line 107) | func debugPrintError(err error) {

FILE: gossh/gin/errors.go
  type ErrorType (line 16) | type ErrorType
  constant ErrorTypeBind (line 20) | ErrorTypeBind ErrorType = 1 << 63
  constant ErrorTypeRender (line 22) | ErrorTypeRender ErrorType = 1 << 62
  constant ErrorTypePrivate (line 24) | ErrorTypePrivate ErrorType = 1 << 0
  constant ErrorTypePublic (line 26) | ErrorTypePublic ErrorType = 1 << 1
  constant ErrorTypeAny (line 28) | ErrorTypeAny ErrorType = 1<<64 - 1
  constant ErrorTypeNu (line 30) | ErrorTypeNu = 2
  type Error (line 34) | type Error struct
    method SetType (line 45) | func (msg *Error) SetType(flags ErrorType) *Error {
    method SetMeta (line 51) | func (msg *Error) SetMeta(data any) *Error {
    method JSON (line 57) | func (msg *Error) JSON() any {
    method MarshalJSON (line 79) | func (msg *Error) MarshalJSON() ([]byte, error) {
    method Error (line 84) | func (msg Error) Error() string {
    method IsType (line 89) | func (msg *Error) IsType(flags ErrorType) bool {
    method Unwrap (line 94) | func (msg *Error) Unwrap() error {
  type errorMsgs (line 40) | type errorMsgs
    method ByType (line 100) | func (a errorMsgs) ByType(typ ErrorType) errorMsgs {
    method Last (line 118) | func (a errorMsgs) Last() *Error {
    method Errors (line 132) | func (a errorMsgs) Errors() []string {
    method JSON (line 143) | func (a errorMsgs) JSON() any {
    method MarshalJSON (line 159) | func (a errorMsgs) MarshalJSON() ([]byte, error) {
    method String (line 163) | func (a errorMsgs) String() string {

FILE: gossh/gin/fs.go
  type onlyFilesFS (line 12) | type onlyFilesFS struct
    method Open (line 33) | func (fs onlyFilesFS) Open(name string) (http.File, error) {
  type neuteredReaddirFile (line 16) | type neuteredReaddirFile struct
    method Readdir (line 42) | func (f neuteredReaddirFile) Readdir(_ int) ([]os.FileInfo, error) {
  function Dir (line 24) | func Dir(root string, listDirectory bool) http.FileSystem {

FILE: gossh/gin/gin.go
  constant defaultMultipartMemory (line 22) | defaultMultipartMemory = 32 << 20
  type HandlerFunc (line 46) | type HandlerFunc
  type OptionFunc (line 49) | type OptionFunc
  type HandlersChain (line 52) | type HandlersChain
    method Last (line 55) | func (c HandlersChain) Last() HandlerFunc {
  type RouteInfo (line 63) | type RouteInfo struct
  type RoutesInfo (line 71) | type RoutesInfo
  type Engine (line 75) | type Engine struct
    method Handler (line 205) | func (engine *Engine) Handler() http.Handler {
    method allocateContext (line 209) | func (engine *Engine) allocateContext(maxParams uint16) *Context {
    method Delims (line 216) | func (engine *Engine) Delims(left, right string) *Engine {
    method SecureJsonPrefix (line 222) | func (engine *Engine) SecureJsonPrefix(prefix string) *Engine {
    method LoadHTMLGlob (line 229) | func (engine *Engine) LoadHTMLGlob(pattern string) {
    method LoadHTMLFiles (line 245) | func (engine *Engine) LoadHTMLFiles(files ...string) {
    method SetHTMLTemplate (line 256) | func (engine *Engine) SetHTMLTemplate(templ *template.Template) {
    method SetFuncMap (line 265) | func (engine *Engine) SetFuncMap(funcMap template.FuncMap) {
    method NoRoute (line 270) | func (engine *Engine) NoRoute(handlers ...HandlerFunc) {
    method NoMethod (line 276) | func (engine *Engine) NoMethod(handlers ...HandlerFunc) {
    method Use (line 284) | func (engine *Engine) Use(middleware ...HandlerFunc) IRoutes {
    method With (line 292) | func (engine *Engine) With(opts ...OptionFunc) *Engine {
    method rebuild404Handlers (line 300) | func (engine *Engine) rebuild404Handlers() {
    method rebuild405Handlers (line 304) | func (engine *Engine) rebuild405Handlers() {
    method addRoute (line 308) | func (engine *Engine) addRoute(method, path string, handlers HandlersC...
    method Routes (line 334) | func (engine *Engine) Routes() (routes RoutesInfo) {
    method Run (line 361) | func (engine *Engine) Run(addr ...string) (err error) {
    method prepareTrustedCIDRs (line 375) | func (engine *Engine) prepareTrustedCIDRs() ([]*net.IPNet, error) {
    method SetTrustedProxies (line 412) | func (engine *Engine) SetTrustedProxies(trustedProxies []string) error {
    method isUnsafeTrustedProxies (line 418) | func (engine *Engine) isUnsafeTrustedProxies() bool {
    method parseTrustedProxies (line 423) | func (engine *Engine) parseTrustedProxies() error {
    method isTrustedProxy (line 430) | func (engine *Engine) isTrustedProxy(ip net.IP) bool {
    method validateHeader (line 443) | func (engine *Engine) validateHeader(header string) (clientIP string, ...
    method RunTLS (line 481) | func (engine *Engine) RunTLS(addr, certFile, keyFile string) (err erro...
    method RunUnix (line 497) | func (engine *Engine) RunUnix(file string) (err error) {
    method RunFd (line 520) | func (engine *Engine) RunFd(fd int) (err error) {
    method RunListener (line 541) | func (engine *Engine) RunListener(listener net.Listener) (err error) {
    method ServeHTTP (line 555) | func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Reque...
    method HandleContext (line 569) | func (engine *Engine) HandleContext(c *Context) {
    method handleHTTPRequest (line 577) | func (engine *Engine) handleHTTPRequest(c *Context) {
  function New (line 165) | func New(opts ...OptionFunc) *Engine {
  function Default (line 198) | func Default(opts ...OptionFunc) *Engine {
  function iterate (line 341) | func iterate(path, method string, routes RoutesInfo, root *node) RoutesI...
  function parseIP (line 466) | func parseIP(ip string) net.IP {
  function serveError (line 647) | func serveError(c *Context, code int, defaultMessage []byte) {
  function redirectTrailingSlash (line 664) | func redirectTrailingSlash(c *Context) {
  function redirectFixedPath (line 680) | func redirectFixedPath(c *Context, root *node, trailingSlash bool) bool {
  function redirectRequest (line 692) | func redirectRequest(c *Context) {

FILE: gossh/gin/ginS/gins.go
  function engine (line 18) | func engine() *gin.Engine {
  function LoadHTMLGlob (line 26) | func LoadHTMLGlob(pattern string) {
  function LoadHTMLFiles (line 31) | func LoadHTMLFiles(files ...string) {
  function SetHTMLTemplate (line 36) | func SetHTMLTemplate(templ *template.Template) {
  function NoRoute (line 41) | func NoRoute(handlers ...gin.HandlerFunc) {
  function NoMethod (line 46) | func NoMethod(handlers ...gin.HandlerFunc) {
  function Group (line 52) | func Group(relativePath string, handlers ...gin.HandlerFunc) *gin.Router...
  function Handle (line 57) | func Handle(httpMethod, relativePath string, handlers ...gin.HandlerFunc...
  function POST (line 62) | func POST(relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes {
  function GET (line 67) | func GET(relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes {
  function DELETE (line 72) | func DELETE(relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes {
  function PATCH (line 77) | func PATCH(relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes {
  function PUT (line 82) | func PUT(relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes {
  function OPTIONS (line 87) | func OPTIONS(relativePath string, handlers ...gin.HandlerFunc) gin.IRout...
  function HEAD (line 92) | func HEAD(relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes {
  function Any (line 97) | func Any(relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes {
  function StaticFile (line 102) | func StaticFile(relativePath, filepath string) gin.IRoutes {
  function Static (line 113) | func Static(relativePath, root string) gin.IRoutes {
  function StaticFS (line 118) | func StaticFS(relativePath string, fs http.FileSystem) gin.IRoutes {
  function Use (line 125) | func Use(middlewares ...gin.HandlerFunc) gin.IRoutes {
  function Routes (line 130) | func Routes() gin.RoutesInfo {
  function Run (line 137) | func Run(addr ...string) (err error) {
  function RunTLS (line 144) | func RunTLS(addr, certFile, keyFile string) (err error) {
  function RunUnix (line 151) | func RunUnix(file string) (err error) {
  function RunFd (line 158) | func RunFd(fd int) (err error) {

FILE: gossh/gin/internal/bytesconv/bytesconv.go
  function StringToBytes (line 13) | func StringToBytes(s string) []byte {
  function BytesToString (line 19) | func BytesToString(b []byte) string {

FILE: gossh/gin/jwt/claims.go
  type Claims (line 9) | type Claims interface

FILE: gossh/gin/jwt/cmd/jwt/main.go
  function main (line 38) | func main() {
  function start (line 62) | func start() error {
  function loadData (line 77) | func loadData(p string) ([]byte, error) {
  function printJSON (line 100) | func printJSON(j any) error {
  function verifyToken (line 119) | func verifyToken() error {
  function signToken (line 174) | func signToken() error {
  function showToken (line 263) | func showToken() error {
  function isEs (line 295) | func isEs() bool {
  function isRs (line 299) | func isRs() bool {
  function isEd (line 303) | func isEd() bool {
  function isNone (line 307) | func isNone() bool {
  function algHelp (line 311) | func algHelp() string {
  type ArgList (line 330) | type ArgList
    method String (line 332) | func (l ArgList) String() string {
    method Set (line 337) | func (l ArgList) Set(arg string) error {

FILE: gossh/gin/jwt/ecdsa.go
  type SigningMethodECDSA (line 18) | type SigningMethodECDSA struct
    method Alg (line 52) | func (m *SigningMethodECDSA) Alg() string {
    method Verify (line 58) | func (m *SigningMethodECDSA) Verify(signingString string, sig []byte, ...
    method Sign (line 92) | func (m *SigningMethodECDSA) Sign(signingString string, key any) ([]by...
  function init (line 32) | func init() {

FILE: gossh/gin/jwt/ecdsa_utils.go
  function ParseECPrivateKeyFromPEM (line 16) | func ParseECPrivateKeyFromPEM(key []byte) (*ecdsa.PrivateKey, error) {
  function ParseECPublicKeyFromPEM (line 43) | func ParseECPublicKeyFromPEM(key []byte) (*ecdsa.PublicKey, error) {

FILE: gossh/gin/jwt/ed25519.go
  type SigningMethodEd25519 (line 16) | type SigningMethodEd25519 struct
    method Alg (line 30) | func (m *SigningMethodEd25519) Alg() string {
    method Verify (line 36) | func (m *SigningMethodEd25519) Verify(signingString string, sig []byte...
    method Sign (line 58) | func (m *SigningMethodEd25519) Sign(signingString string, key any) ([]...
  function init (line 23) | func init() {

FILE: gossh/gin/jwt/ed25519_utils.go
  function ParseEdPrivateKeyFromPEM (line 17) | func ParseEdPrivateKeyFromPEM(key []byte) (crypto.PrivateKey, error) {
  function ParseEdPublicKeyFromPEM (line 42) | func ParseEdPublicKeyFromPEM(key []byte) (crypto.PublicKey, error) {

FILE: gossh/gin/jwt/errors.go
  type joinedError (line 30) | type joinedError struct
    method Error (line 34) | func (je joinedError) Error() string {
  function joinErrors (line 45) | func joinErrors(errs ...error) error {

FILE: gossh/gin/jwt/errors_go1_20.go
  method Unwrap (line 12) | func (je joinedError) Unwrap() []error {
  function newError (line 29) | func newError(message string, err error, more ...error) error {

FILE: gossh/gin/jwt/errors_go_other.go
  method Is (line 13) | func (je joinedError) Is(err error) bool {
  type wrappedErrors (line 28) | type wrappedErrors struct
    method Error (line 34) | func (we wrappedErrors) Error() string {
  function newError (line 52) | func newError(message string, err error, more ...error) error {

FILE: gossh/gin/jwt/hmac.go
  type SigningMethodHMAC (line 11) | type SigningMethodHMAC struct
    method Alg (line 44) | func (m *SigningMethodHMAC) Alg() string {
    method Verify (line 58) | func (m *SigningMethodHMAC) Verify(signingString string, sig []byte, k...
    method Sign (line 91) | func (m *SigningMethodHMAC) Sign(signingString string, key any) ([]byt...
  function init (line 24) | func init() {

FILE: gossh/gin/jwt/map_claims.go
  type MapClaims (line 10) | type MapClaims
    method GetExpirationTime (line 13) | func (m MapClaims) GetExpirationTime() (*NumericDate, error) {
    method GetNotBefore (line 18) | func (m MapClaims) GetNotBefore() (*NumericDate, error) {
    method GetIssuedAt (line 23) | func (m MapClaims) GetIssuedAt() (*NumericDate, error) {
    method GetAudience (line 28) | func (m MapClaims) GetAudience() (ClaimStrings, error) {
    method GetIssuer (line 33) | func (m MapClaims) GetIssuer() (string, error) {
    method GetSubject (line 38) | func (m MapClaims) GetSubject() (string, error) {
    method parseNumericDate (line 45) | func (m MapClaims) parseNumericDate(key string) (*NumericDate, error) {
    method parseClaimsString (line 69) | func (m MapClaims) parseClaimsString(key string) (ClaimStrings, error) {
    method parseString (line 92) | func (m MapClaims) parseString(key string) (string, error) {

FILE: gossh/gin/jwt/none.go
  constant UnsafeAllowNoneSignatureType (line 7) | UnsafeAllowNoneSignatureType unsafeNoneMagicConstant = "none signing met...
  type signingMethodNone (line 11) | type signingMethodNone struct
    method Alg (line 23) | func (m *signingMethodNone) Alg() string {
    method Verify (line 28) | func (m *signingMethodNone) Verify(signingString string, sig []byte, k...
    method Sign (line 44) | func (m *signingMethodNone) Sign(signingString string, key any) ([]byt...
  type unsafeNoneMagicConstant (line 12) | type unsafeNoneMagicConstant
  function init (line 14) | func init() {

FILE: gossh/gin/jwt/parser.go
  type Parser (line 11) | type Parser struct
    method Parse (line 44) | func (p *Parser) Parse(tokenString string, keyFunc Keyfunc) (*Token, e...
    method ParseWithClaims (line 55) | func (p *Parser) ParseWithClaims(tokenString string, claims Claims, ke...
    method ParseUnverified (line 138) | func (p *Parser) ParseUnverified(tokenString string, claims Claims) (t...
    method DecodeSegment (line 202) | func (p *Parser) DecodeSegment(seg string) ([]byte, error) {
  function NewParser (line 29) | func NewParser(options ...ParserOption) *Parser {
  function Parse (line 225) | func Parse(tokenString string, keyFunc Keyfunc, options ...ParserOption)...
  function ParseWithClaims (line 236) | func ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc,...

FILE: gossh/gin/jwt/parser_option.go
  type ParserOption (line 9) | type ParserOption
  function WithValidMethods (line 15) | func WithValidMethods(methods []string) ParserOption {
  function WithJSONNumber (line 23) | func WithJSONNumber() ParserOption {
  function WithoutClaimsValidation (line 31) | func WithoutClaimsValidation() ParserOption {
  function WithLeeway (line 38) | func WithLeeway(leeway time.Duration) ParserOption {
  function WithTimeFunc (line 47) | func WithTimeFunc(f func() time.Time) ParserOption {
  function WithIssuedAt (line 55) | func WithIssuedAt() ParserOption {
  function WithExpirationRequired (line 63) | func WithExpirationRequired() ParserOption {
  function WithAudience (line 77) | func WithAudience(aud string) ParserOption {
  function WithIssuer (line 91) | func WithIssuer(iss string) ParserOption {
  function WithSubject (line 105) | func WithSubject(sub string) ParserOption {
  function WithPaddingAllowed (line 115) | func WithPaddingAllowed() ParserOption {
  function WithStrictDecoding (line 124) | func WithStrictDecoding() ParserOption {

FILE: gossh/gin/jwt/registered_claims.go
  type RegisteredClaims (line 12) | type RegisteredClaims struct
    method GetExpirationTime (line 36) | func (c RegisteredClaims) GetExpirationTime() (*NumericDate, error) {
    method GetNotBefore (line 41) | func (c RegisteredClaims) GetNotBefore() (*NumericDate, error) {
    method GetIssuedAt (line 46) | func (c RegisteredClaims) GetIssuedAt() (*NumericDate, error) {
    method GetAudience (line 51) | func (c RegisteredClaims) GetAudience() (ClaimStrings, error) {
    method GetIssuer (line 56) | func (c RegisteredClaims) GetIssuer() (string, error) {
    method GetSubject (line 61) | func (c RegisteredClaims) GetSubject() (string, error) {

FILE: gossh/gin/jwt/request/extractor.go
  type Extractor (line 17) | type Extractor interface
  type HeaderExtractor (line 23) | type HeaderExtractor
    method ExtractToken (line 25) | func (e HeaderExtractor) ExtractToken(req *http.Request) (string, erro...
  type ArgumentExtractor (line 38) | type ArgumentExtractor
    method ExtractToken (line 40) | func (e ArgumentExtractor) ExtractToken(req *http.Request) (string, er...
  type MultiExtractor (line 55) | type MultiExtractor
    method ExtractToken (line 57) | func (e MultiExtractor) ExtractToken(req *http.Request) (string, error) {
  type PostExtractionFilter (line 71) | type PostExtractionFilter struct
    method ExtractToken (line 76) | func (e *PostExtractionFilter) ExtractToken(req *http.Request) (string...
  type BearerExtractor (line 87) | type BearerExtractor struct
    method ExtractToken (line 89) | func (e BearerExtractor) ExtractToken(req *http.Request) (string, erro...

FILE: gossh/gin/jwt/request/oauth2.go
  function stripBearerPrefixFromTokenString (line 8) | func stripBearerPrefixFromTokenString(tok string) (string, error) {

FILE: gossh/gin/jwt/request/request.go
  function ParseFromRequest (line 15) | func ParseFromRequest(req *http.Request, extractor Extractor, keyFunc jw...
  function ParseFromRequestWithClaims (line 45) | func ParseFromRequestWithClaims(req *http.Request, extractor Extractor, ...
  type fromRequestParser (line 49) | type fromRequestParser struct
  type ParseFromRequestOption (line 56) | type ParseFromRequestOption
  function WithClaims (line 59) | func WithClaims(claims jwt.Claims) ParseFromRequestOption {
  function WithParser (line 66) | func WithParser(parser *jwt.Parser) ParseFromRequestOption {

FILE: gossh/gin/jwt/rsa.go
  type SigningMethodRSA (line 11) | type SigningMethodRSA struct
    method Alg (line 43) | func (m *SigningMethodRSA) Alg() string {
    method Verify (line 49) | func (m *SigningMethodRSA) Verify(signingString string, sig []byte, ke...
    method Sign (line 70) | func (m *SigningMethodRSA) Sign(signingString string, key any) ([]byte...
  function init (line 23) | func init() {

FILE: gossh/gin/jwt/rsa_pss.go
  type SigningMethodRSAPSS (line 10) | type SigningMethodRSAPSS struct
    method Verify (line 82) | func (m *SigningMethodRSAPSS) Verify(signingString string, sig []byte,...
    method Sign (line 108) | func (m *SigningMethodRSAPSS) Sign(signingString string, key any) ([]b...
  function init (line 27) | func init() {

FILE: gossh/gin/jwt/rsa_utils.go
  function ParseRSAPrivateKeyFromPEM (line 17) | func ParseRSAPrivateKeyFromPEM(key []byte) (*rsa.PrivateKey, error) {
  function ParseRSAPrivateKeyFromPEMWithPassword (line 47) | func ParseRSAPrivateKeyFromPEMWithPassword(key []byte, password string) ...
  function ParseRSAPublicKeyFromPEM (line 79) | func ParseRSAPublicKeyFromPEM(key []byte) (*rsa.PublicKey, error) {

FILE: gossh/gin/jwt/signing_method.go
  type SigningMethod (line 14) | type SigningMethod interface
  function RegisterSigningMethod (line 22) | func RegisterSigningMethod(alg string, f func() SigningMethod) {
  function GetSigningMethod (line 30) | func GetSigningMethod(alg string) (method SigningMethod) {
  function GetAlgorithms (line 41) | func GetAlgorithms() (algs []string) {

FILE: gossh/gin/jwt/token.go
  type Keyfunc (line 16) | type Keyfunc
  type VerificationKey (line 19) | type VerificationKey interface
  type VerificationKeySet (line 24) | type VerificationKeySet struct
  type Token (line 30) | type Token struct
    method SignedString (line 63) | func (t *Token) SignedString(key any) (string, error) {
    method SigningString (line 80) | func (t *Token) SigningString() (string, error) {
    method EncodeSegment (line 98) | func (*Token) EncodeSegment(seg []byte) string {
  function New (line 41) | func New(method SigningMethod, opts ...TokenOption) *Token {
  function NewWithClaims (line 47) | func NewWithClaims(method SigningMethod, claims Claims, opts ...TokenOpt...

FILE: gossh/gin/jwt/token_option.go
  type TokenOption (line 5) | type TokenOption

FILE: gossh/gin/jwt/types.go
  type NumericDate (line 32) | type NumericDate struct
    method MarshalJSON (line 51) | func (date NumericDate) MarshalJSON() (b []byte, err error) {
    method UnmarshalJSON (line 80) | func (date *NumericDate) UnmarshalJSON(b []byte) (err error) {
  function NewNumericDate (line 38) | func NewNumericDate(t time.Time) *NumericDate {
  function newNumericDateFromSeconds (line 44) | func newNumericDateFromSeconds(f float64) *NumericDate {
  type ClaimStrings (line 103) | type ClaimStrings
    method UnmarshalJSON (line 105) | func (s *ClaimStrings) UnmarshalJSON(data []byte) (err error) {
    method MarshalJSON (line 138) | func (s ClaimStrings) MarshalJSON() (b []byte, err error) {

FILE: gossh/gin/jwt/validator.go
  type ClaimsValidator (line 26) | type ClaimsValidator interface
  type Validator (line 36) | type Validator struct
    method Validate (line 88) | func (v *Validator) Validate(claims Claims) error {
    method verifyExpiresAt (line 167) | func (v *Validator) verifyExpiresAt(claims Claims, cmp time.Time, requ...
    method verifyIssuedAt (line 188) | func (v *Validator) verifyIssuedAt(claims Claims, cmp time.Time, requi...
    method verifyNotBefore (line 209) | func (v *Validator) verifyNotBefore(claims Claims, cmp time.Time, requ...
    method verifyAudience (line 229) | func (v *Validator) verifyAudience(claims Claims, cmp string, required...
    method verifyIssuer (line 265) | func (v *Validator) verifyIssuer(claims Claims, cmp string, required b...
    method verifySubject (line 285) | func (v *Validator) verifySubject(claims Claims, cmp string, required ...
  function NewValidator (line 77) | func NewValidator(opts ...ParserOption) *Validator {
  function errorIfFalse (line 300) | func errorIfFalse(value bool, err error) error {
  function errorIfRequired (line 310) | func errorIfRequired(required bool, claim string) error {

FILE: gossh/gin/logger.go
  type consoleColorModeValue (line 15) | type consoleColorModeValue
  constant autoColor (line 18) | autoColor consoleColorModeValue = iota
  constant disableColor (line 19) | disableColor
  constant forceColor (line 20) | forceColor
  constant green (line 24) | green   = "\033[97;42m"
  constant white (line 25) | white   = "\033[90;47m"
  constant yellow (line 26) | yellow  = "\033[90;43m"
  constant red (line 27) | red     = "\033[97;41m"
  constant blue (line 28) | blue    = "\033[97;44m"
  constant magenta (line 29) | magenta = "\033[97;45m"
  constant cyan (line 30) | cyan    = "\033[97;46m"
  constant reset (line 31) | reset   = "\033[0m"
  type LoggerConfig (line 37) | type LoggerConfig struct
  type Skipper (line 55) | type Skipper
  type LogFormatter (line 58) | type LogFormatter
  type LogFormatterParams (line 61) | type LogFormatterParams struct
    method StatusCodeColor (line 87) | func (p *LogFormatterParams) StatusCodeColor() string {
    method MethodColor (line 105) | func (p *LogFormatterParams) MethodColor() string {
    method ResetColor (line 129) | func (p *LogFormatterParams) ResetColor() string {
    method IsOutputColor (line 134) | func (p *LogFormatterParams) IsOutputColor() bool {
  function DisableConsoleColor (line 162) | func DisableConsoleColor() {
  function ForceConsoleColor (line 167) | func ForceConsoleColor() {
  function ErrorLogger (line 172) | func ErrorLogger() HandlerFunc {
  function ErrorLoggerT (line 177) | func ErrorLoggerT(typ ErrorType) HandlerFunc {
  function Logger (line 189) | func Logger() HandlerFunc {
  function LoggerWithFormatter (line 194) | func LoggerWithFormatter(f LogFormatter) HandlerFunc {
  function LoggerWithWriter (line 202) | func LoggerWithWriter(out io.Writer, notlogged ...string) HandlerFunc {
  function LoggerWithConfig (line 210) | func LoggerWithConfig(conf LoggerConfig) HandlerFunc {

FILE: gossh/gin/mode.go
  constant EnvGinMode (line 16) | EnvGinMode = "GIN_MODE"
  constant DebugMode (line 20) | DebugMode = "debug"
  constant ReleaseMode (line 22) | ReleaseMode = "release"
  constant TestMode (line 24) | TestMode = "test"
  constant debugCode (line 28) | debugCode = iota
  constant releaseCode (line 29) | releaseCode
  constant testCode (line 30) | testCode
  function init (line 51) | func init() {
  function SetMode (line 57) | func SetMode(value string) {
  function DisableBindValidation (line 81) | func DisableBindValidation() {
  function EnableJsonDecoderUseNumber (line 87) | func EnableJsonDecoderUseNumber() {
  function EnableJsonDecoderDisallowUnknownFields (line 93) | func EnableJsonDecoderDisallowUnknownFields() {
  function Mode (line 98) | func Mode() string {

FILE: gossh/gin/path.go
  function cleanPath (line 21) | func cleanPath(p string) string {
  function bufApp (line 127) | func bufApp(buf *[]byte, s string, w int, c byte) {

FILE: gossh/gin/recovery.go
  type RecoveryFunc (line 30) | type RecoveryFunc
  function Recovery (line 33) | func Recovery() HandlerFunc {
  function CustomRecovery (line 38) | func CustomRecovery(handle RecoveryFunc) HandlerFunc {
  function RecoveryWithWriter (line 43) | func RecoveryWithWriter(out io.Writer, recovery ...RecoveryFunc) Handler...
  function CustomRecoveryWithWriter (line 51) | func CustomRecoveryWithWriter(out io.Writer, handle RecoveryFunc) Handle...
  function defaultHandleRecovery (line 106) | func defaultHandleRecovery(c *Context, _ any) {
  function stack (line 111) | func stack(skip int) []byte {
  function source (line 138) | func source(lines [][]byte, n int) []byte {
  function function (line 147) | func function(pc uintptr) []byte {
  function timeFormat (line 172) | func timeFormat(t time.Time) string {

FILE: gossh/gin/render/data.go
  type Data (line 10) | type Data struct
    method Render (line 16) | func (r Data) Render(w http.ResponseWriter) (err error) {
    method WriteContentType (line 23) | func (r Data) WriteContentType(w http.ResponseWriter) {

FILE: gossh/gin/render/html.go
  type Delims (line 13) | type Delims struct
  type HTMLRender (line 21) | type HTMLRender interface
  type HTMLProduction (line 27) | type HTMLProduction struct
    method Instance (line 50) | func (r HTMLProduction) Instance(name string, data any) Render {
  type HTMLDebug (line 33) | type HTMLDebug struct
    method Instance (line 59) | func (r HTMLDebug) Instance(name string, data any) Render {
    method loadTemplate (line 66) | func (r HTMLDebug) loadTemplate() *template.Template {
  type HTML (line 41) | type HTML struct
    method Render (line 80) | func (r HTML) Render(w http.ResponseWriter) error {
    method WriteContentType (line 90) | func (r HTML) WriteContentType(w http.ResponseWriter) {

FILE: gossh/gin/render/json.go
  type JSON (line 18) | type JSON struct
    method Render (line 56) | func (r JSON) Render(w http.ResponseWriter) error {
    method WriteContentType (line 61) | func (r JSON) WriteContentType(w http.ResponseWriter) {
  type IndentedJSON (line 23) | type IndentedJSON struct
    method Render (line 77) | func (r IndentedJSON) Render(w http.ResponseWriter) error {
    method WriteContentType (line 88) | func (r IndentedJSON) WriteContentType(w http.ResponseWriter) {
  type SecureJSON (line 28) | type SecureJSON struct
    method Render (line 93) | func (r SecureJSON) Render(w http.ResponseWriter) error {
    method WriteContentType (line 111) | func (r SecureJSON) WriteContentType(w http.ResponseWriter) {
  type JsonpJSON (line 34) | type JsonpJSON struct
    method Render (line 116) | func (r JsonpJSON) Render(w http.ResponseWriter) (err error) {
    method WriteContentType (line 149) | func (r JsonpJSON) WriteContentType(w http.ResponseWriter) {
  type AsciiJSON (line 40) | type AsciiJSON struct
    method Render (line 154) | func (r AsciiJSON) Render(w http.ResponseWriter) (err error) {
    method WriteContentType (line 175) | func (r AsciiJSON) WriteContentType(w http.ResponseWriter) {
  type PureJSON (line 45) | type PureJSON struct
    method Render (line 180) | func (r PureJSON) Render(w http.ResponseWriter) error {
    method WriteContentType (line 188) | func (r PureJSON) WriteContentType(w http.ResponseWriter) {
  function WriteJSON (line 66) | func WriteJSON(w http.ResponseWriter, obj any) error {

FILE: gossh/gin/render/reader.go
  type Reader (line 14) | type Reader struct
    method Render (line 22) | func (r Reader) Render(w http.ResponseWriter) (err error) {
    method WriteContentType (line 36) | func (r Reader) WriteContentType(w http.ResponseWriter) {
    method writeHeaders (line 41) | func (r Reader) writeHeaders(w http.ResponseWriter, headers map[string...

FILE: gossh/gin/render/redirect.go
  type Redirect (line 13) | type Redirect struct
    method Render (line 20) | func (r Redirect) Render(w http.ResponseWriter) error {
    method WriteContentType (line 29) | func (r Redirect) WriteContentType(http.ResponseWriter) {}

FILE: gossh/gin/render/render.go
  type Render (line 10) | type Render interface
  function writeContentType (line 33) | func writeContentType(w http.ResponseWriter, value []string) {

FILE: gossh/gin/render/text.go
  type String (line 15) | type String struct
    method Render (line 23) | func (r String) Render(w http.ResponseWriter) error {
    method WriteContentType (line 28) | func (r String) WriteContentType(w http.ResponseWriter) {
  function WriteString (line 33) | func WriteString(w http.ResponseWriter, format string, data []any) (err ...

FILE: gossh/gin/render/xml.go
  type XML (line 13) | type XML struct
    method Render (line 20) | func (r XML) Render(w http.ResponseWriter) error {
    method WriteContentType (line 26) | func (r XML) WriteContentType(w http.ResponseWriter) {

FILE: gossh/gin/response_writer.go
  constant noWritten (line 15) | noWritten     = -1
  constant defaultStatus (line 16) | defaultStatus = http.StatusOK
  type ResponseWriter (line 20) | type ResponseWriter interface
  type responseWriter (line 46) | type responseWriter struct
    method Unwrap (line 54) | func (w *responseWriter) Unwrap() http.ResponseWriter {
    method reset (line 58) | func (w *responseWriter) reset(writer http.ResponseWriter) {
    method WriteHeader (line 64) | func (w *responseWriter) WriteHeader(code int) {
    method WriteHeaderNow (line 74) | func (w *responseWriter) WriteHeaderNow() {
    method Write (line 81) | func (w *responseWriter) Write(data []byte) (n int, err error) {
    method WriteString (line 88) | func (w *responseWriter) WriteString(s string) (n int, err error) {
    method Status (line 95) | func (w *responseWriter) Status() int {
    method Size (line 99) | func (w *responseWriter) Size() int {
    method Written (line 103) | func (w *responseWriter) Written() bool {
    method Hijack (line 108) | func (w *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
    method CloseNotify (line 116) | func (w *responseWriter) CloseNotify() <-chan bool {
    method Flush (line 121) | func (w *responseWriter) Flush() {
    method Pusher (line 126) | func (w *responseWriter) Pusher() (pusher http.Pusher) {

FILE: gossh/gin/routergroup.go
  type IRouter (line 27) | type IRouter interface
  type IRoutes (line 33) | type IRoutes interface
  type RouterGroup (line 55) | type RouterGroup struct
    method Use (line 65) | func (group *RouterGroup) Use(middleware ...HandlerFunc) IRoutes {
    method Group (line 72) | func (group *RouterGroup) Group(relativePath string, handlers ...Handl...
    method BasePath (line 82) | func (group *RouterGroup) BasePath() string {
    method handle (line 86) | func (group *RouterGroup) handle(httpMethod, relativePath string, hand...
    method Handle (line 103) | func (group *RouterGroup) Handle(httpMethod, relativePath string, hand...
    method POST (line 111) | func (group *RouterGroup) POST(relativePath string, handlers ...Handle...
    method GET (line 116) | func (group *RouterGroup) GET(relativePath string, handlers ...Handler...
    method DELETE (line 121) | func (group *RouterGroup) DELETE(relativePath string, handlers ...Hand...
    method PATCH (line 126) | func (group *RouterGroup) PATCH(relativePath string, handlers ...Handl...
    method PUT (line 131) | func (group *RouterGroup) PUT(relativePath string, handlers ...Handler...
    method OPTIONS (line 136) | func (group *RouterGroup) OPTIONS(relativePath string, handlers ...Han...
    method HEAD (line 141) | func (group *RouterGroup) HEAD(relativePath string, handlers ...Handle...
    method Any (line 147) | func (group *RouterGroup) Any(relativePath string, handlers ...Handler...
    method Match (line 156) | func (group *RouterGroup) Match(methods []string, relativePath string,...
    method StaticFile (line 166) | func (group *RouterGroup) StaticFile(relativePath, filepath string) IR...
    method StaticFileFS (line 175) | func (group *RouterGroup) StaticFileFS(relativePath, filepath string, ...
    method staticFileHandler (line 181) | func (group *RouterGroup) staticFileHandler(relativePath string, handl...
    method Static (line 197) | func (group *RouterGroup) Static(relativePath, root string) IRoutes {
    method StaticFS (line 203) | func (group *RouterGroup) StaticFS(relativePath string, fs http.FileSy...
    method createStaticHandler (line 216) | func (group *RouterGroup) createStaticHandler(relativePath string, fs ...
    method combineHandlers (line 241) | func (group *RouterGroup) combineHandlers(handlers HandlersChain) Hand...
    method calculateAbsolutePath (line 250) | func (group *RouterGroup) calculateAbsolutePath(relativePath string) s...
    method returnObj (line 254) | func (group *RouterGroup) returnObj() IRoutes {

FILE: gossh/gin/sessions/context/context.go
  function Set (line 16) | func Set(r *http.Request, key, val any) {
  function Get (line 27) | func Get(r *http.Request, key any) any {
  function GetOk (line 39) | func GetOk(r *http.Request, key any) (any, bool) {
  function GetAll (line 51) | func GetAll(r *http.Request) map[any]any {
  function GetAllOk (line 67) | func GetAllOk(r *http.Request) (map[any]any, bool) {
  function Delete (line 79) | func Delete(r *http.Request, key any) {
  function Clear (line 91) | func Clear(r *http.Request) {
  function clear (line 98) | func clear(r *http.Request) {
  function Purge (line 112) | func Purge(maxAge int) int {
  function ClearHandler (line 134) | func ClearHandler(h http.Handler) http.Handler {

FILE: gossh/gin/sessions/cookie/cookie.go
  type Store (line 8) | type Store interface
  function NewStore (line 21) | func NewStore(keyPairs ...[]byte) Store {
  type store (line 25) | type store struct
    method Options (line 29) | func (c *store) Options(options sessions.Options) {

FILE: gossh/gin/sessions/memstore/cache.go
  type cache (line 7) | type cache struct
    method value (line 18) | func (c *cache) value(name string) (valueType, bool) {
    method setValue (line 26) | func (c *cache) setValue(name string, value valueType) {
    method delete (line 33) | func (c *cache) delete(name string) {
  function newCache (line 12) | func newCache() *cache {

FILE: gossh/gin/sessions/memstore/memstore.go
  type MemStore (line 19) | type MemStore struct
    method Get (line 62) | func (m *MemStore) Get(r *http.Request, name string) (*sessions.Sessio...
    method New (line 71) | func (m *MemStore) New(r *http.Request, name string) (*sessions.Sessio...
    method Save (line 104) | func (m *MemStore) Save(r *http.Request, w http.ResponseWriter, s *ses...
    method MaxAge (line 130) | func (m *MemStore) MaxAge(age int) {
    method copy (line 141) | func (m *MemStore) copy(v valueType) valueType {
  type valueType (line 25) | type valueType
  function NewMemStore (line 42) | func NewMemStore(keyPairs ...[]byte) *MemStore {

FILE: gossh/gin/sessions/memstore/store.go
  type Store (line 7) | type Store interface
  function NewStore (line 20) | func NewStore(keyPairs ...[]byte) Store {
  type store (line 24) | type store struct
    method Options (line 28) | func (c *store) Options(options sessions.Options) {

FILE: gossh/gin/sessions/securecookie/securecookie.go
  type Error (line 27) | type Error interface
  type errorType (line 58) | type errorType
  constant usageError (line 61) | usageError = errorType(1 << iota)
  constant decodeError (line 62) | decodeError
  constant internalError (line 63) | internalError
  type cookieError (line 66) | type cookieError struct
    method IsUsage (line 72) | func (e cookieError) IsUsage() bool    { return (e.typ & usageError) !...
    method IsDecode (line 73) | func (e cookieError) IsDecode() bool   { return (e.typ & decodeError) ...
    method IsInternal (line 74) | func (e cookieError) IsInternal() bool { return (e.typ & internalError...
    method Cause (line 76) | func (e cookieError) Cause() error { return e.cause }
    method Error (line 78) | func (e cookieError) Error() string {
  type Codec (line 116) | type Codec interface
  function New (line 135) | func New(hashKey, blockKey []byte) *SecureCookie {
  type SecureCookie (line 155) | type SecureCookie struct
    method MaxLength (line 194) | func (s *SecureCookie) MaxLength(value int) *SecureCookie {
    method MaxAge (line 202) | func (s *SecureCookie) MaxAge(value int) *SecureCookie {
    method MinAge (line 210) | func (s *SecureCookie) MinAge(value int) *SecureCookie {
    method HashFunc (line 218) | func (s *SecureCookie) HashFunc(f func() hash.Hash) *SecureCookie {
    method BlockFunc (line 226) | func (s *SecureCookie) BlockFunc(f func([]byte) (cipher.Block, error))...
    method SetSerializer (line 241) | func (s *SecureCookie) SetSerializer(sz Serializer) *SecureCookie {
    method Encode (line 259) | func (s *SecureCookie) Encode(name string, value any) (string, error) {
    method Decode (line 303) | func (s *SecureCookie) Decode(name, value string, dst any) error {
    method timestamp (line 364) | func (s *SecureCookie) timestamp() int64 {
  type Serializer (line 172) | type Serializer interface
  type GobEncoder (line 179) | type GobEncoder struct
    method Serialize (line 430) | func (e GobEncoder) Serialize(src any) ([]byte, error) {
    method Deserialize (line 440) | func (e GobEncoder) Deserialize(src []byte, dst any) error {
  type JSONEncoder (line 184) | type JSONEncoder struct
    method Serialize (line 449) | func (e JSONEncoder) Serialize(src any) ([]byte, error) {
    method Deserialize (line 459) | func (e JSONEncoder) Deserialize(src []byte, dst any) error {
  type NopEncoder (line 189) | type NopEncoder struct
    method Serialize (line 468) | func (e NopEncoder) Serialize(src any) ([]byte, error) {
    method Deserialize (line 477) | func (e NopEncoder) Deserialize(src []byte, dst any) error {
  function createMac (line 374) | func createMac(h hash.Hash, value []byte) []byte {
  function verifyMac (line 380) | func verifyMac(h hash.Hash, value []byte, mac []byte) error {
  function encrypt (line 396) | func encrypt(block cipher.Block, value []byte) ([]byte, error) {
  function decrypt (line 412) | func decrypt(block cipher.Block, value []byte) ([]byte, error) {
  function encode (line 488) | func encode(value []byte) []byte {
  function decode (line 495) | func decode(value []byte) ([]byte, error) {
  function GenerateRandomKey (line 515) | func GenerateRandomKey(length int) []byte {
  function CodecsFromPairs (line 547) | func CodecsFromPairs(keyPairs ...[]byte) []Codec {
  function EncodeMulti (line 565) | func EncodeMulti(name string, value any, codecs ...Codec) (string, error) {
  function DecodeMulti (line 587) | func DecodeMulti(name string, value string, dst any, codecs ...Codec) er...
  type MultiError (line 604) | type MultiError
    method IsUsage (line 606) | func (m MultiError) IsUsage() bool    { return m.any(func(e Error) boo...
    method IsDecode (line 607) | func (m MultiError) IsDecode() bool   { return m.any(func(e Error) boo...
    method IsInternal (line 608) | func (m MultiError) IsInternal() bool { return m.any(func(e Error) boo...
    method Cause (line 618) | func (m MultiError) Cause() error { return nil }
    method Error (line 620) | func (m MultiError) Error() string {
    method any (line 642) | func (m MultiError) any(pred func(Error) bool) bool {

FILE: gossh/gin/sessions/session_options_go1.10.go
  type Options (line 12) | type Options struct
    method ToGorillaOptions (line 23) | func (options Options) ToGorillaOptions() *gsessions.Options {

FILE: gossh/gin/sessions/session_options_go1.11.go
  type Options (line 14) | type Options struct
    method ToGorillaOptions (line 29) | func (options Options) ToGorillaOptions() *gsessions.Options {

FILE: gossh/gin/sessions/sessions.go
  constant DefaultKey (line 13) | DefaultKey  = "gin-sessions"
  constant errorFormat (line 14) | errorFormat = "[sessions] ERROR! %s\n"
  type Store (line 17) | type Store interface
  type Session (line 24) | type Session interface
  function Sessions (line 49) | func Sessions(name string, store Store) gin.HandlerFunc {
  function SessionsMany (line 58) | func SessionsMany(names []string, store Store) gin.HandlerFunc {
  type session (line 70) | type session struct
    method ID (line 79) | func (s *session) ID() string {
    method Get (line 83) | func (s *session) Get(key any) any {
    method Set (line 87) | func (s *session) Set(key any, val any) {
    method Delete (line 92) | func (s *session) Delete(key any) {
    method Clear (line 97) | func (s *session) Clear() {
    method AddFlash (line 103) | func (s *session) AddFlash(value any, vars ...string) {
    method Flashes (line 108) | func (s *session) Flashes(vars ...string) []any {
    method Options (line 113) | func (s *session) Options(options Options) {
    method Save (line 118) | func (s *session) Save() error {
    method Session (line 129) | func (s *session) Session() *sessions.Session {
    method Written (line 140) | func (s *session) Written() bool {
  function Default (line 145) | func Default(c *gin.Context) Session {
  function DefaultMany (line 150) | func DefaultMany(c *gin.Context, name string) Session {

FILE: gossh/gin/sessions/sessions/cookie.go
  function newCookieFromOptions (line 9) | func newCookieFromOptions(name, value string, options *Options) *http.Co...

FILE: gossh/gin/sessions/sessions/cookie_go111.go
  function newCookieFromOptions (line 9) | func newCookieFromOptions(name, value string, options *Options) *http.Co...

FILE: gossh/gin/sessions/sessions/lex.go
  function isToken (line 88) | func isToken(r rune) bool {
  function isNotToken (line 93) | func isNotToken(r rune) bool {
  function isCookieNameValid (line 97) | func isCookieNameValid(raw string) bool {

FILE: gossh/gin/sessions/sessions/options.go
  type Options (line 9) | type Options struct

FILE: gossh/gin/sessions/sessions/options_go111.go
  type Options (line 11) | type Options struct

FILE: gossh/gin/sessions/sessions/sessions.go
  constant flashesKey (line 16) | flashesKey = "_flash"
  function NewSession (line 21) | func NewSession(store Store, name string) *Session {
  type Session (line 31) | type Session struct
    method Flashes (line 47) | func (s *Session) Flashes(vars ...string) []any {
    method AddFlash (line 65) | func (s *Session) AddFlash(value any, vars ...string) {
    method Save (line 80) | func (s *Session) Save(r *http.Request, w http.ResponseWriter) error {
    method Name (line 85) | func (s *Session) Name() string {
    method Store (line 90) | func (s *Session) Store() Store {
  type sessionInfo (line 97) | type sessionInfo struct
  type contextKey (line 103) | type contextKey
  constant registryKey (line 106) | registryKey contextKey = 0
  function GetRegistry (line 109) | func GetRegistry(r *http.Request) *Registry {
  type Registry (line 124) | type Registry struct
    method Get (line 132) | func (s *Registry) Get(store Store, name string) (session *Session, er...
    method Save (line 148) | func (s *Registry) Save(w http.ResponseWriter) error {
  function init (line 168) | func init() {
  function Save (line 173) | func Save(r *http.Request, w http.ResponseWriter) error {
  function NewCookie (line 180) | func NewCookie(name, value string, options *Options) *http.Cookie {
  type MultiError (line 197) | type MultiError
    method Error (line 199) | func (m MultiError) Error() string {

FILE: gossh/gin/sessions/sessions/store.go
  type Store (line 20) | type Store interface
  function NewCookieStore (line 48) | func NewCookieStore(keyPairs ...[]byte) *CookieStore {
  type CookieStore (line 62) | type CookieStore struct
    method Get (line 74) | func (s *CookieStore) Get(r *http.Request, name string) (*Session, err...
    method New (line 83) | func (s *CookieStore) New(r *http.Request, name string) (*Session, err...
    method Save (line 100) | func (s *CookieStore) Save(r *http.Request, w http.ResponseWriter,
    method MaxAge (line 114) | func (s *CookieStore) MaxAge(age int) {
  function NewFilesystemStore (line 135) | func NewFilesystemStore(path string, keyPairs ...[]byte) *FilesystemStore {
  type FilesystemStore (line 157) | type FilesystemStore struct
    method MaxLength (line 166) | func (s *FilesystemStore) MaxLength(l int) {
    method Get (line 177) | func (s *FilesystemStore) Get(r *http.Request, name string) (*Session,...
    method New (line 184) | func (s *FilesystemStore) New(r *http.Request, name string) (*Session,...
    method Save (line 210) | func (s *FilesystemStore) Save(r *http.Request, w http.ResponseWriter,
    method MaxAge (line 242) | func (s *FilesystemStore) MaxAge(age int) {
    method save (line 254) | func (s *FilesystemStore) save(session *Session) error {
    method load (line 267) | func (s *FilesystemStore) load(session *Session) error {
    method erase (line 283) | func (s *FilesystemStore) erase(session *Session) error {

FILE: gossh/gin/sse/sse-decoder.go
  type decoder (line 12) | type decoder struct
    method dispatchEvent (line 21) | func (d *decoder) dispatchEvent(event Event, data string) {
    method decode (line 38) | func (d *decoder) decode(r io.Reader) ([]Event, error) {
  function Decode (line 16) | func Decode(r io.Reader) ([]Event, error) {

FILE: gossh/gin/sse/sse-encoder.go
  constant ContentType (line 21) | ContentType = "text/event-stream"
  type Event (line 34) | type Event struct
    method Render (line 89) | func (r Event) Render(w http.ResponseWriter) error {
    method WriteContentType (line 94) | func (r Event) WriteContentType(w http.ResponseWriter) {
  function Encode (line 41) | func Encode(writer io.Writer, event Event) error {
  function writeId (line 49) | func writeId(w stringWriter, id string) {
  function writeEvent (line 57) | func writeEvent(w stringWriter, event string) {
  function writeRetry (line 65) | func writeRetry(w stringWriter, retry uint) {
  function writeData (line 73) | func writeData(w stringWriter, data any) error {
  function kindOfData (line 103) | func kindOfData(data any) reflect.Kind {

FILE: gossh/gin/sse/writer.go
  type stringWriter (line 5) | type stringWriter interface
  type stringWrapper (line 10) | type stringWrapper struct
    method WriteString (line 14) | func (w stringWrapper) WriteString(str string) (int, error) {
  function checkWriter (line 18) | func checkWriter(writer io.Writer) stringWriter {

FILE: gossh/gin/tree.go
  type Param (line 24) | type Param struct
  type Params (line 32) | type Params
    method Get (line 36) | func (ps Params) Get(name string) (string, bool) {
    method ByName (line 47) | func (ps Params) ByName(name string) (va string) {
  type methodTree (line 52) | type methodTree struct
  type methodTrees (line 57) | type methodTrees
    method get (line 59) | func (trees methodTrees) get(method string) *node {
  function min (line 68) | func min(a, b int) int {
  function longestCommonPrefix (line 75) | func longestCommonPrefix(a, b string) int {
  function countParams (line 94) | func countParams(path string) uint16 {
  function countSections (line 102) | func countSections(path string) uint16 {
  type nodeType (line 107) | type nodeType
  constant static (line 110) | static nodeType = iota
  constant root (line 111) | root
  constant param (line 112) | param
  constant catchAll (line 113) | catchAll
  type node (line 116) | type node struct
    method addChild (line 85) | func (n *node) addChild(child *node) {
    method incrementChildPrio (line 128) | func (n *node) incrementChildPrio(pos int) int {
    method addRoute (line 152) | func (n *node) addRoute(path string, handlers HandlersChain) {
    method insertChild (line 293) | func (n *node) insertChild(path string, fullPath string, handlers Hand...
    method getValue (line 423) | func (n *node) getValue(path string, params *Params, skippedNodes *[]s...
    method findCaseInsensitivePath (line 676) | func (n *node) findCaseInsensitivePath(path string, fixTrailingSlash b...
    method findCaseInsensitivePathRec (line 713) | func (n *node) findCaseInsensitivePathRec(path string, ciPath []byte, ...
  function findWildcard (line 270) | func findWildcard(path string) (wildcard string, i int, valid bool) {
  type nodeValue (line 405) | type nodeValue struct
  type skippedNode (line 412) | type skippedNode struct
  function shiftNRuneBytes (line 697) | func shiftNRuneBytes(rb [4]byte, n int) [4]byte {

FILE: gossh/gin/utils.go
  constant BindKey (line 19) | BindKey = "_gin-gonic/gin/bindkey"
  function Bind (line 22) | func Bind(val any) HandlerFunc {
  function WrapF (line 40) | func WrapF(f http.HandlerFunc) HandlerFunc {
  function WrapH (line 47) | func WrapH(h http.Handler) HandlerFunc {
  type H (line 54) | type H
    method MarshalXML (line 57) | func (h H) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
  function assert1 (line 78) | func assert1(guard bool, text string) {
  function filterFlags (line 84) | func filterFlags(content string) string {
  function chooseData (line 93) | func chooseData(custom, wildcard any) any {
  function parseAccept (line 103) | func parseAccept(acceptHeader string) []string {
  function lastChar (line 117) | func lastChar(str string) uint8 {
  function nameOfFunction (line 124) | func nameOfFunction(f any) string {
  function joinPaths (line 128) | func joinPaths(absolutePath, relativePath string) string {
  function resolveAddress (line 140) | func resolveAddress(addr []string) string {
  function isASCII (line 157) | func isASCII(s string) bool {

FILE: gossh/gin/validator/baked_in.go
  type Func (line 24) | type Func
  type FuncCtx (line 28) | type FuncCtx
  function wrapFunc (line 31) | func wrapFunc(fn Func) FuncCtx {
  function parseOneOfParam2 (line 233) | func parseOneOfParam2(s string) []string {
  function isURLEncoded (line 249) | func isURLEncoded(fl FieldLevel) bool {
  function isHTMLEncoded (line 253) | func isHTMLEncoded(fl FieldLevel) bool {
  function isHTML (line 257) | func isHTML(fl FieldLevel) bool {
  function isOneOf (line 261) | func isOneOf(fl FieldLevel) bool {
  function isUnique (line 286) | func isUnique(fl FieldLevel) bool {
  function isMAC (line 359) | func isMAC(fl FieldLevel) bool {
  function isCIDRv4 (line 366) | func isCIDRv4(fl FieldLevel) bool {
  function isCIDRv6 (line 373) | func isCIDRv6(fl FieldLevel) bool {
  function isCIDR (line 380) | func isCIDR(fl FieldLevel) bool {
  function isIPv4 (line 387) | func isIPv4(fl FieldLevel) bool {
  function isIPv6 (line 394) | func isIPv6(fl FieldLevel) bool {
  function isIP (line 401) | func isIP(fl FieldLevel) bool {
  function isSSN (line 408) | func isSSN(fl FieldLevel) bool {
  function isLongitude (line 419) | func isLongitude(fl FieldLevel) bool {
  function isLatitude (line 442) | func isLatitude(fl FieldLevel) bool {
  function isDataURI (line 465) | func isDataURI(fl FieldLevel) bool {
  function hasMultiByteCharacter (line 480) | func hasMultiByteCharacter(fl FieldLevel) bool {
  function isPrintableASCII (line 491) | func isPrintableASCII(fl FieldLevel) bool {
  function isASCII (line 496) | func isASCII(fl FieldLevel) bool {
  function isUUID5 (line 501) | func isUUID5(fl FieldLevel) bool {
  function isUUID4 (line 506) | func isUUID4(fl FieldLevel) bool {
  function isUUID3 (line 511) | func isUUID3(fl FieldLevel) bool {
  function isUUID (line 516) | func isUUID(fl FieldLevel) bool {
  function isUUID5RFC4122 (line 521) | func isUUID5RFC4122(fl FieldLevel) bool {
  function isUUID4RFC4122 (line 526) | func isUUID4RFC4122(fl FieldLevel) bool {
  function isUUID3RFC4122 (line 531) | func isUUID3RFC4122(fl FieldLevel) bool {
  function isUUIDRFC4122 (line 536) | func isUUIDRFC4122(fl FieldLevel) bool {
  function isULID (line 541) | func isULID(fl FieldLevel) bool {
  function isMD4 (line 546) | func isMD4(fl FieldLevel) bool {
  function isMD5 (line 551) | func isMD5(fl FieldLevel) bool {
  function isSHA256 (line 556) | func isSHA256(fl FieldLevel) bool {
  function isSHA384 (line 561) | func isSHA384(fl FieldLevel) bool {
  function isSHA512 (line 566) | func isSHA512(fl FieldLevel) bool {
  function isRIPEMD128 (line 571) | func isRIPEMD128(fl FieldLevel) bool {
  function isRIPEMD160 (line 576) | func isRIPEMD160(fl FieldLevel) bool {
  function isTIGER128 (line 581) | func isTIGER128(fl FieldLevel) bool {
  function isTIGER160 (line 586) | func isTIGER160(fl FieldLevel) bool {
  function isTIGER192 (line 591) | func isTIGER192(fl FieldLevel) bool {
  function isISBN (line 596) | func isISBN(fl FieldLevel) bool {
  function isISBN13 (line 601) | func isISBN13(fl FieldLevel) bool {
  function isISBN10 (line 621) | func isISBN10(fl FieldLevel) bool {
  function isISSN (line 645) | func isISSN(fl FieldLevel) bool {
  function isEthereumAddress (line 671) | func isEthereumAddress(fl FieldLevel) bool {
  function isBitcoinAddress (line 678) | func isBitcoinAddress(fl FieldLevel) bool {
  function isBitcoinBech32Address (line 715) | func isBitcoinBech32Address(fl FieldLevel) bool {
  function excludesRune (line 795) | func excludesRune(fl FieldLevel) bool {
  function excludesAll (line 800) | func excludesAll(fl FieldLevel) bool {
  function excludes (line 805) | func excludes(fl FieldLevel) bool {
  function containsRune (line 810) | func containsRune(fl FieldLevel) bool {
  function containsAny (line 817) | func containsAny(fl FieldLevel) bool {
  function contains (line 822) | func contains(fl FieldLevel) bool {
  function startsWith (line 827) | func startsWith(fl FieldLevel) bool {
  function endsWith (line 832) | func endsWith(fl FieldLevel) bool {
  function startsNotWith (line 837) | func startsNotWith(fl FieldLevel) bool {
  function endsNotWith (line 842) | func endsNotWith(fl FieldLevel) bool {
  function fieldContains (line 847) | func fieldContains(fl FieldLevel) bool {
  function fieldExcludes (line 860) | func fieldExcludes(fl FieldLevel) bool {
  function isNeField (line 872) | func isNeField(fl FieldLevel) bool {
  function isNe (line 922) | func isNe(fl FieldLevel) bool {
  function isNeIgnoreCase (line 928) | func isNeIgnoreCase(fl FieldLevel) bool {
  function isLteCrossStructField (line 933) | func isLteCrossStructField(fl FieldLevel) bool {
  function isLtCrossStructField (line 980) | func isLtCrossStructField(fl FieldLevel) bool {
  function isGteCrossStructField (line 1026) | func isGteCrossStructField(fl FieldLevel) bool {
  function isGtCrossStructField (line 1072) | func isGtCrossStructField(fl FieldLevel) bool {
  function isNeCrossStructField (line 1118) | func isNeCrossStructField(fl FieldLevel) bool {
  function isEqCrossStructField (line 1167) | func isEqCrossStructField(fl FieldLevel) bool {
  function isEqField (line 1216) | func isEqField(fl FieldLevel) bool {
  function isEq (line 1265) | func isEq(fl FieldLevel) bool {
  function isEqIgnoreCase (line 1311) | func isEqIgnoreCase(fl FieldLevel) bool {
  function isPostcodeByIso3166Alpha2 (line 1326) | func isPostcodeByIso3166Alpha2(fl FieldLevel) bool {
  function isPostcodeByIso3166Alpha2Field (line 1340) | func isPostcodeByIso3166Alpha2Field(fl FieldLevel) bool {
  function isBase64 (line 1366) | func isBase64(fl FieldLevel) bool {
  function isBase64URL (line 1371) | func isBase64URL(fl FieldLevel) bool {
  function isBase64RawURL (line 1376) | func isBase64RawURL(fl FieldLevel) bool {
  function isURI (line 1381) | func isURI(fl FieldLevel) bool {
  function isFileURL (line 1408) | func isFileURL(path string) bool {
  function isURL (line 1417) | func isURL(fl FieldLevel) bool {
  function isHttpURL (line 1449) | func isHttpURL(fl FieldLevel) bool {
  function isFile (line 1472) | func isFile(fl FieldLevel) bool {
  function isFilePath (line 1489) | func isFilePath(fl FieldLevel) bool {
  function isE164 (line 1544) | func isE164(fl FieldLevel) bool {
  function isEmail (line 1549) | func isEmail(fl FieldLevel) bool {
  function isHSLA (line 1554) | func isHSLA(fl FieldLevel) bool {
  function isHSL (line 1559) | func isHSL(fl FieldLevel) bool {
  function isRGBA (line 1564) | func isRGBA(fl FieldLevel) bool {
  function isRGB (line 1569) | func isRGB(fl FieldLevel) bool {
  function isHEXColor (line 1574) | func isHEXColor(fl FieldLevel) bool {
  function isHexadecimal (line 1579) | func isHexadecimal(fl FieldLevel) bool {
  function isNumber (line 1584) | func isNumber(fl FieldLevel) bool {
  function isNumeric (line 1594) | func isNumeric(fl FieldLevel) bool {
  function isAlphanum (line 1604) | func isAlphanum(fl FieldLevel) bool {
  function isAlpha (line 1609) | func isAlpha(fl FieldLevel) bool {
  function isAlphanumUnicode (line 1614) | func isAlphanumUnicode(fl FieldLevel) bool {
  function isAlphaUnicode (line 1619) | func isAlphaUnicode(fl FieldLevel) bool {
  function isBoolean (line 1624) | func isBoolean(fl FieldLevel) bool {
  function isDefault (line 1635) | func isDefault(fl FieldLevel) bool {
  function hasValue (line 1640) | func hasValue(fl FieldLevel) bool {
  function requireCheckFieldKind (line 1654) | func requireCheckFieldKind(fl FieldLevel, param string, defaultNotFoundV...
  function requireCheckFieldValue (line 1678) | func requireCheckFieldValue(
  function requiredIf (line 1713) | func requiredIf(fl FieldLevel) bool {
  function excludedIf (line 1728) | func excludedIf(fl FieldLevel) bool {
  function requiredUnless (line 1744) | func requiredUnless(fl FieldLevel) bool {
  function skipUnless (line 1760) | func skipUnless(fl FieldLevel) bool {
  function excludedUnless (line 1775) | func excludedUnless(fl FieldLevel) bool {
  function excludedWith (line 1790) | func excludedWith(fl FieldLevel) bool {
  function requiredWith (line 1802) | func requiredWith(fl FieldLevel) bool {
  function excludedWithAll (line 1814) | func excludedWithAll(fl FieldLevel) bool {
  function requiredWithAll (line 1826) | func requiredWithAll(fl FieldLevel) bool {
  function excludedWithout (line 1838) | func excludedWithout(fl FieldLevel) bool {
  function requiredWithout (line 1847) | func requiredWithout(fl FieldLevel) bool {
  function excludedWithoutAll (line 1856) | func excludedWithoutAll(fl FieldLevel) bool {
  function requiredWithoutAll (line 1868) | func requiredWithoutAll(fl FieldLevel) bool {
  function isGteField (line 1879) | func isGteField(fl FieldLevel) bool {
  function isGtField (line 1925) | func isGtField(fl FieldLevel) bool {
  function isGte (line 1971) | func isGte(fl FieldLevel) bool {
  function isGt (line 2022) | func isGt(fl FieldLevel) bool {
  function hasLengthOf (line 2070) | func hasLengthOf(fl FieldLevel) bool {
  function hasMinOf (line 2111) | func hasMinOf(fl FieldLevel) bool {
  function isLteField (line 2116) | func isLteField(fl FieldLevel) bool {
  function isLtField (line 2162) | func isLtField(fl FieldLevel) bool {
  function isLte (line 2208) | func isLte(fl FieldLevel) bool {
  function isLt (line 2259) | func isLt(fl FieldLevel) bool {
  function hasMaxOf (line 2307) | func hasMaxOf(fl FieldLevel) bool {
  function isTCP4AddrResolvable (line 2312) | func isTCP4AddrResolvable(fl FieldLevel) bool {
  function isTCP6AddrResolvable (line 2322) | func isTCP6AddrResolvable(fl FieldLevel) bool {
  function isTCPAddrResolvable (line 2333) | func isTCPAddrResolvable(fl FieldLevel) bool {
  function isUDP4AddrResolvable (line 2344) | func isUDP4AddrResolvable(fl FieldLevel) bool {
  function isUDP6AddrResolvable (line 2355) | func isUDP6AddrResolvable(fl FieldLevel) bool {
  function isUDPAddrResolvable (line 2366) | func isUDPAddrResolvable(fl FieldLevel) bool {
  function isIP4AddrResolvable (line 2377) | func isIP4AddrResolvable(fl FieldLevel) bool {
  function isIP6AddrResolvable (line 2388) | func isIP6AddrResolvable(fl FieldLevel) bool {
  function isIPAddrResolvable (line 2399) | func isIPAddrResolvable(fl FieldLevel) bool {
  function isUnixAddrResolvable (line 2410) | func isUnixAddrResolvable(fl FieldLevel) bool {
  function isIP4Addr (line 2416) | func isIP4Addr(fl FieldLevel) bool {
  function isIP6Addr (line 2428) | func isIP6Addr(fl FieldLevel) bool {
  function isHostnameRFC952 (line 2442) | func isHostnameRFC952(fl FieldLevel) bool {
  function isHostnameRFC1123 (line 2446) | func isHostnameRFC1123(fl FieldLevel) bool {
  function isFQDN (line 2450) | func isFQDN(fl FieldLevel) bool {
  function isDir (line 2461) | func isDir(fl FieldLevel) bool {
  function isDirPath (line 2477) | func isDirPath(fl FieldLevel) bool {
  function isJSON (line 2535) | func isJSON(fl FieldLevel) bool {
  function isJWT (line 2555) | func isJWT(fl FieldLevel) bool {
  function isHostnamePort (line 2560) | func isHostnamePort(fl FieldLevel) bool {
  function isLowercase (line 2581) | func isLowercase(fl FieldLevel) bool {
  function isUppercase (line 2595) | func isUppercase(fl FieldLevel) bool {
  function isDatetime (line 2609) | func isDatetime(fl FieldLevel) bool {
  function isTimeZone (line 2623) | func isTimeZone(fl FieldLevel) bool {
  function isIso3166Alpha2 (line 2645) | func isIso3166Alpha2(fl FieldLevel) bool {
  function isIso3166Alpha3 (line 2651) | func isIso3166Alpha3(fl FieldLevel) bool {
  function isIso3166AlphaNumeric (line 2657) | func isIso3166AlphaNumeric(fl FieldLevel) bool {
  function isIso31662 (line 2679) | func isIso31662(fl FieldLevel) bool {
  function isIso4217 (line 2685) | func isIso4217(fl FieldLevel) bool {
  function isIso4217Numeric (line 2691) | func isIso4217Numeric(fl FieldLevel) bool {
  function isIsoBicFormat (line 2707) | func isIsoBicFormat(fl FieldLevel) bool {
  function isSemverFormat (line 2714) | func isSemverFormat(fl FieldLevel) bool {
  function isCveFormat (line 2721) | func isCveFormat(fl FieldLevel) bool {
  function isDnsRFC1035LabelFormat (line 2730) | func isDnsRFC1035LabelFormat(fl FieldLevel) bool {
  function digitsHaveLuhnChecksum (line 2736) | func digitsHaveLuhnChecksum(digits []string) bool {
  function isMongoDB (line 2759) | func isMongoDB(fl FieldLevel) bool {
  function isSpiceDB (line 2765) | func isSpiceDB(fl FieldLevel) bool {
  function isCreditCard (line 2782) | func isCreditCard(fl FieldLevel) bool {
  function hasLuhnChecksum (line 2803) | func hasLuhnChecksum(fl FieldLevel) bool {
  function isCron (line 2825) | func isCron(fl FieldLevel) bool {

FILE: gossh/gin/validator/cache.go
  type tagType (line 11) | type tagType
  constant typeDefault (line 14) | typeDefault tagType = iota
  constant typeOmitEmpty (line 15) | typeOmitEmpty
  constant typeIsDefault (line 16) | typeIsDefault
  constant typeNoStructLevel (line 17) | typeNoStructLevel
  constant typeStructOnly (line 18) | typeStructOnly
  constant typeDive (line 19) | typeDive
  constant typeOr (line 20) | typeOr
  constant typeKeys (line 21) | typeKeys
  constant typeEndKeys (line 22) | typeEndKeys
  constant typeOmitNil (line 23) | typeOmitNil
  constant invalidValidation (line 27) | invalidValidation   = "Invalid validation tag on field '%s'"
  constant undefinedValidation (line 28) | undefinedValidation = "Undefined validation function '%s' on field '%s'"
  constant keysTagNotDefined (line 29) | keysTagNotDefined   = "'" + endKeysTag + "' tag encountered without a co...
  type structCache (line 32) | type structCache struct
    method Get (line 37) | func (sc *structCache) Get(key reflect.Type) (c *cStruct, found bool) {
    method Set (line 42) | func (sc *structCache) Set(key reflect.Type, value *cStruct) {
  type tagCache (line 52) | type tagCache struct
    method Get (line 57) | func (tc *tagCache) Get(key string) (c *cTag, found bool) {
    method Set (line 62) | func (tc *tagCache) Set(key string, value *cTag) {
  type cStruct (line 72) | type cStruct struct
  type cField (line 78) | type cField struct
  type cTag (line 86) | type cTag struct
  method extractStructCache (line 102) | func (v *Validate) extractStructCache(current reflect.Value, sName strin...
  method parseFieldTagsRecursive (line 175) | func (v *Validate) parseFieldTagsRecursive(tag string, fieldName string,...
  method fetchCacheTag (line 316) | func (v *Validate) fetchCacheTag(tag string) *cTag {

FILE: gossh/gin/validator/errors.go
  constant fieldErrMsg (line 12) | fieldErrMsg = "Key: '%s' Error:Field validation for '%s' failed on the '...
  type ValidationErrorsTranslations (line 16) | type ValidationErrorsTranslations
  type InvalidValidationError (line 20) | type InvalidValidationError struct
    method Error (line 25) | func (e *InvalidValidationError) Error() string {
  type ValidationErrors (line 36) | type ValidationErrors
    method Error (line 42) | func (ve ValidationErrors) Error() string {
  type FieldError (line 56) | type FieldError interface
  type fieldError (line 143) | type fieldError struct
    method Translate (line 157) | func (fe *fieldError) Translate() string {
    method Tag (line 162) | func (fe *fieldError) Tag() string {
    method ActualTag (line 168) | func (fe *fieldError) ActualTag() string {
    method Namespace (line 174) | func (fe *fieldError) Namespace() string {
    method StructNamespace (line 180) | func (fe *fieldError) StructNamespace() string {
    method Field (line 186) | func (fe *fieldError) Field() string {
    method StructField (line 202) | func (fe *fieldError) StructField() string {
    method Value (line 209) | func (fe *fieldError) Value() any {
    method Param (line 215) | func (fe *fieldError) Param() string {
    method Kind (line 220) | func (fe *fieldError) Kind() reflect.Kind {
    method Type (line 225) | func (fe *fieldError) Type() reflect.Type {
    method Error (line 230) | func (fe *fieldError) Error() string {

FILE: gossh/gin/validator/field_level.go
  type FieldLevel (line 7) | type FieldLevel interface
  method Field (line 69) | func (v *validate) Field() reflect.Value {
  method FieldName (line 75) | func (v *validate) FieldName() string {
  method GetTag (line 80) | func (v *validate) GetTag() string {
  method StructFieldName (line 85) | func (v *validate) StructFieldName() string {
  method Param (line 90) | func (v *validate) Param() string {
  method GetStructFieldOK (line 97) | func (v *validate) GetStructFieldOK() (reflect.Value, reflect.Kind, bool) {
  method GetStructFieldOKAdvanced (line 106) | func (v *validate) GetStructFieldOKAdvanced(val reflect.Value, namespace...
  method GetStructFieldOK2 (line 112) | func (v *validate) GetStructFieldOK2() (reflect.Value, reflect.Kind, boo...
  method GetStructFieldOKAdvanced2 (line 118) | func (v *validate) GetStructFieldOKAdvanced2(val reflect.Value, namespac...

FILE: gossh/gin/validator/options.go
  type Option (line 4) | type Option
  function WithRequiredStructEnabled (line 12) | func WithRequiredStructEnabled() Option {

FILE: gossh/gin/validator/postcode_regexes.go
  function init (line 169) | func init() {

FILE: gossh/gin/validator/regexes.go
  constant alphaRegexString (line 6) | alphaRegexString                 = "^[a-zA-Z]+$"
  constant alphaNumericRegexString (line 7) | alphaNumericRegexString          = "^[a-zA-Z0-9]+$"
  constant alphaUnicodeRegexString (line 8) | alphaUnicodeRegexString          = "^[\\p{L}]+$"
  constant alphaUnicodeNumericRegexString (line 9) | alphaUnicodeNumericRegexString   = "^[\\p{L}\\p{N}]+$"
  constant numericRegexString (line 10) | numericRegexString               = "^[-+]?[0-9]+(?:\\.[0-9]+)?$"
  constant numberRegexString (line 11) | numberRegexString                = "^[0-9]+$"
  constant hexadecimalRegexString (line 12) | hexadecimalRegexString           = "^(0[xX])?[0-9a-fA-F]+$"
  constant hexColorRegexString (line 13) | hexColorRegexString              = "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[...
  constant rgbRegexString (line 14) | rgbRegexString                   = "^rgb\\(\\s*(?:(?:0|[1-9]\\d?|1\\d\\d...
  constant rgbaRegexString (line 15) | rgbaRegexString                  = "^rgba\\(\\s*(?:(?:0|[1-9]\\d?|1\\d\\...
  constant hslRegexString (line 16) | hslRegexString                   = "^hsl\\(\\s*(?:0|[1-9]\\d?|[12]\\d\\d...
  constant hslaRegexString (line 17) | hslaRegexString                  = "^hsla\\(\\s*(?:0|[1-9]\\d?|[12]\\d\\...
  constant emailRegexString (line 18) | emailRegexString                 = "^(?:(?:(?:(?:[a-zA-Z]|\\d|[!#\\$%&'\...
  constant e164RegexString (line 19) | e164RegexString                  = "^\\+[1-9]?[0-9]{7,14}$"
  constant base64RegexString (line 20) | base64RegexString                = "^(?:[A-Za-z0-9+\\/]{4})*(?:[A-Za-z0-...
  constant base64URLRegexString (line 21) | base64URLRegexString             = "^(?:[A-Za-z0-9-_]{4})*(?:[A-Za-z0-9-...
  constant base64RawURLRegexString (line 22) | base64RawURLRegexString          = "^(?:[A-Za-z0-9-_]{4})*(?:[A-Za-z0-9-...
  constant iSBN10RegexString (line 23) | iSBN10RegexString                = "^(?:[0-9]{9}X|[0-9]{10})$"
  constant iSBN13RegexString (line 24) | iSBN13RegexString                = "^(?:(?:97(?:8|9))[0-9]{10})$"
  constant iSSNRegexString (line 25) | iSSNRegexString                  = "^(?:[0-9]{4}-[0-9]{3}[0-9X])$"
  constant uUID3RegexString (line 26) | uUID3RegexString                 = "^[0-9a-f]{8}-[0-9a-f]{4}-3[0-9a-f]{3...
  constant uUID4RegexString (line 27) | uUID4RegexString                 = "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3...
  constant uUID5RegexString (line 28) | uUID5RegexString                 = "^[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3...
  constant uUIDRegexString (line 29) | uUIDRegexString                  = "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}...
  constant uUID3RFC4122RegexString (line 30) | uUID3RFC4122RegexString          = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-3[0-9...
  constant uUID4RFC4122RegexString (line 31) | uUID4RFC4122RegexString          = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9...
  constant uUID5RFC4122RegexString (line 32) | uUID5RFC4122RegexString          = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-5[0-9...
  constant uUIDRFC4122RegexString (line 33) | uUIDRFC4122RegexString           = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a...
  constant uLIDRegexString (line 34) | uLIDRegexString                  = "^[A-HJKMNP-TV-Z0-9]{26}$"
  constant md4RegexString (line 35) | md4RegexString                   = "^[0-9a-f]{32}$"
  constant md5RegexString (line 36) | md5RegexString                   = "^[0-9a-f]{32}$"
  constant sha256RegexString (line 37) | sha256RegexString                = "^[0-9a-f]{64}$"
  constant sha384RegexString (line 38) | sha384RegexString                = "^[0-9a-f]{96}$"
  constant sha512RegexString (line 39) | sha512RegexString                = "^[0-9a-f]{128}$"
  constant ripemd128RegexString (line 40) | ripemd128RegexString             = "^[0-9a-f]{32}$"
  constant ripemd160RegexString (line 41) | ripemd160RegexString             = "^[0-9a-f]{40}$"
  constant tiger128RegexString (line 42) | tiger128RegexString              = "^[0-9a-f]{32}$"
  constant tiger160RegexString (line 43) | tiger160RegexString              = "^[0-9a-f]{40}$"
  constant tiger192RegexString (line 44) | tiger192RegexString              = "^[0-9a-f]{48}$"
  constant aSCIIRegexString (line 45) | aSCIIRegexString                 = "^[\x00-\x7F]*$"
  constant printableASCIIRegexString (line 46) | printableASCIIRegexString        = "^[\x20-\x7E]*$"
  constant multibyteRegexString (line 47) | multibyteRegexString             = "[^\x00-\x7F]"
  constant dataURIRegexString (line 48) | dataURIRegexString               = `^data:((?:\w+\/(?:([^;]|;[^;]).)+)?)`
  constant latitudeRegexString (line 49) | latitudeRegexString              = "^[-+]?([1-8]?\\d(\\.\\d+)?|90(\\.0+)...
  constant longitudeRegexString (line 50) | longitudeRegexString             = "^[-+]?(180(\\.0+)?|((1[0-7]\\d)|([1-...
  constant sSNRegexString (line 51) | sSNRegexString                   = `^[0-9]{3}[ -]?(0[1-9]|[1-9][0-9])[ -...
  constant hostnameRegexStringRFC952 (line 52) | hostnameRegexStringRFC952        = `^[a-zA-Z]([a-zA-Z0-9\-]+[\.]?)*[a-zA...
  constant hostnameRegexStringRFC1123 (line 53) | hostnameRegexStringRFC1123       = `^([a-zA-Z0-9]{1}[a-zA-Z0-9-]{0,62}){...
  constant fqdnRegexStringRFC1123 (line 54) | fqdnRegexStringRFC1123           = `^([a-zA-Z0-9]{1}[a-zA-Z0-9-]{0,62})(...
  constant btcAddressRegexString (line 55) | btcAddressRegexString            = `^[13][a-km-zA-HJ-NP-Z1-9]{25,34}$`
  constant btcAddressUpperRegexStringBech32 (line 56) | btcAddressUpperRegexStringBech32 = `^BC1[02-9AC-HJ-NP-Z]{7,76}$`
  constant btcAddressLowerRegexStringBech32 (line 57) | btcAddressLowerRegexStringBech32 = `^bc1[02-9ac-hj-np-z]{7,76}$`
  constant ethAddressRegexString (line 58) | ethAddressRegexString            = `^0x[0-9a-fA-F]{40}$`
  constant ethAddressUpperRegexString (line 59) | ethAddressUpperRegexString       = `^0x[0-9A-F]{40}$`
  constant ethAddressLowerRegexString (line 60) | et
Copy disabled (too large) Download .json
Condensed preview — 997 files, each showing path, character count, and a content snippet. Download the .json file for the full structured content (14,250K chars).
[
  {
    "path": ".github/workflows/build-and-release.yml",
    "chars": 2572,
    "preview": "name: Build & Release\n\non:\n  push:\n    tags:\n      - 'v*'\n\njobs:\n  build-release:\n    runs-on: ubuntu-latest\n    name: B"
  },
  {
    "path": ".gitignore",
    "chars": 1866,
    "preview": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n\n# Diagnostic reports (https://nodejs."
  },
  {
    "path": "Dockerfile",
    "chars": 313,
    "preview": "# 第一阶段:构建\nFROM golang:1.23.4 AS builder\nWORKDIR /mnt\nCOPY gossh ./gossh\nRUN cd /mnt/gossh && CGO_ENABLED=0 go build -o /"
  },
  {
    "path": "LICENSE",
    "chars": 1063,
    "preview": "MIT License\n\nCopyright (c) 2021 o8oo8o\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof "
  },
  {
    "path": "README.md",
    "chars": 3126,
    "preview": "## GoWebSSH\n<br/>\n\n### 项目介绍:\n* **Web版ssh客户端 + (sshd,sftp)服务端实现**\n<br/>\n\n### 概要:\n* Golang 1.23 + (Vue3.5 + Vite6)  实现一个We"
  },
  {
    "path": "gossh/Makefile",
    "chars": 664,
    "preview": "\n.PHONY: clean all\n\nall: linux-amd64 linux-arm64 macos-amd64 macos-arm64 windows-amd64\n\nlinux-amd64:\n\tCGO_ENABLED=0 GOOS"
  },
  {
    "path": "gossh/app/config/config.go",
    "chars": 4279,
    "preview": "package config\n\nimport (\n\t\"flag\"\n\t\"gossh/app/utils\"\n\t\"gossh/toml\"\n\t\"log/slog\"\n\t\"os\"\n\t\"path\"\n\t\"time\"\n)\n\ntype AppConfig st"
  },
  {
    "path": "gossh/app/middleware/db_check.go",
    "chars": 551,
    "preview": "package middleware\n\nimport (\n\t\"gossh/app/config\"\n\t\"gossh/app/model\"\n\t\"gossh/gin\"\n)\n\nfunc DbCheck() gin.HandlerFunc {\n\tre"
  },
  {
    "path": "gossh/app/middleware/jwt_auth.go",
    "chars": 2262,
    "preview": "package middleware\n\nimport (\n\t\"errors\"\n\t\"gossh/app/config\"\n\t\"gossh/gin\"\n\t\"gossh/gin/jwt\"\n\t\"strings\"\n\t\"time\"\n)\n\n// JwtSec"
  },
  {
    "path": "gossh/app/middleware/net_filter.go",
    "chars": 1639,
    "preview": "package middleware\n\nimport (\n\t\"fmt\"\n\t\"gossh/app/config\"\n\t\"gossh/app/model\"\n\t\"gossh/gin\"\n\t\"log/slog\"\n\t\"net\"\n)\n\nfunc check"
  },
  {
    "path": "gossh/app/middleware/perm_check.go",
    "chars": 2676,
    "preview": "package middleware\n\nimport (\n\t\"fmt\"\n\t\"gossh/app/config\"\n\t\"gossh/app/model\"\n\t\"gossh/gin\"\n\t\"slices\"\n\t\"strings\"\n)\n\nvar chec"
  },
  {
    "path": "gossh/app/middleware/sys_init.go",
    "chars": 279,
    "preview": "package middleware\n\nimport (\n\t\"gossh/app/config\"\n\t\"gossh/gin\"\n)\n\nfunc SysInit() gin.HandlerFunc {\n\treturn func(c *gin.Co"
  },
  {
    "path": "gossh/app/model/cmd_note.go",
    "chars": 1369,
    "preview": "package model\n\ntype CmdNote struct {\n\tID      uint   `gorm:\"column:id;primaryKey,autoIncrement\" form:\"id\" json:\"id\"`\n\tUi"
  },
  {
    "path": "gossh/app/model/datetime.go",
    "chars": 1376,
    "preview": "package model\n\nimport (\n\t\"database/sql/driver\"\n\t\"fmt\"\n\t\"time\"\n)\n\nconst (\n\tTimeFormat = \"2006-01-02 15:04:05\"\n)\n\ntype Dat"
  },
  {
    "path": "gossh/app/model/db_init.go",
    "chars": 2301,
    "preview": "package model\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"gossh/app/config\"\n\t\"gossh/gorm\"\n\t\"gossh/gorm/driver/mysql\"\n\t\"gossh/gorm/drive"
  },
  {
    "path": "gossh/app/model/login_audit.go",
    "chars": 2215,
    "preview": "package model\n\ntype LoginAudit struct {\n\tID        uint     `gorm:\"column:id;primaryKey,autoIncrement\" form:\"id\" json:\"i"
  },
  {
    "path": "gossh/app/model/net_filter.go",
    "chars": 1941,
    "preview": "package model\n\nimport \"time\"\n\ntype NetFilter struct {\n\tID        uint     `gorm:\"column:id;primaryKey,autoIncrement\" for"
  },
  {
    "path": "gossh/app/model/policy_conf.go",
    "chars": 1053,
    "preview": "package model\n\ntype PolicyConf struct {\n\tID        uint   `gorm:\"column:id;primaryKey,autoIncrement\" form:\"id\" json:\"id\""
  },
  {
    "path": "gossh/app/model/ssh_conf.go",
    "chars": 4881,
    "preview": "package model\n\nimport (\n\t\"errors\"\n\t\"gossh/app/config\"\n\t\"gossh/app/utils\"\n\t\"gossh/gorm\"\n)\n\ntype SshConf struct {\n\tID     "
  },
  {
    "path": "gossh/app/model/sshd_cert.go",
    "chars": 2009,
    "preview": "package model\n\nimport \"time\"\n\ntype SshdCert struct {\n\tID       uint     `gorm:\"column:id;primaryKey,autoIncrement\" form:"
  },
  {
    "path": "gossh/app/model/sshd_conf.go",
    "chars": 2858,
    "preview": "package model\n\nimport (\n\t\"gossh/app/config\"\n\t\"gossh/app/utils\"\n\t\"gossh/gorm\"\n)\n\ntype SshdConf struct {\n\tID            ui"
  },
  {
    "path": "gossh/app/model/sshd_user.go",
    "chars": 2798,
    "preview": "package model\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"gossh/app/config\"\n\t\"gossh/app/utils\"\n\t\"gossh/gorm\"\n\t\"time\"\n)\n\ntype SshdUser s"
  },
  {
    "path": "gossh/app/model/web_user.go",
    "chars": 2971,
    "preview": "package model\n\nimport (\n\t\"errors\"\n\t\"gossh/app/config\"\n\t\"gossh/app/utils\"\n\t\"gossh/gorm\"\n)\n\ntype WebUser struct {\n\tID     "
  },
  {
    "path": "gossh/app/service/cmd_note.go",
    "chars": 1990,
    "preview": "package service\n\nimport (\n\t\"gossh/app/model\"\n\t\"gossh/gin\"\n\t\"strconv\"\n)\n\nfunc CmdNoteCreate(c *gin.Context) {\n\tvar cmd mo"
  },
  {
    "path": "gossh/app/service/db_conn.go",
    "chars": 1573,
    "preview": "package service\n\nimport (\n\t\"gossh/app/config\"\n\t\"gossh/app/model\"\n\t\"gossh/gin\"\n\t\"gossh/gorm\"\n\t\"gossh/gorm/driver/mysql\"\n\t"
  },
  {
    "path": "gossh/app/service/login_audit.go",
    "chars": 1786,
    "preview": "package service\n\nimport (\n\t\"gossh/app/model\"\n\t\"gossh/gin\"\n\t\"strconv\"\n)\n\nfunc AuditFindByID(c *gin.Context) {\n\tid, err :="
  },
  {
    "path": "gossh/app/service/net_filter.go",
    "chars": 2008,
    "preview": "package service\n\nimport (\n\t\"gossh/app/model\"\n\t\"gossh/gin\"\n\t\"strconv\"\n)\n\nfunc NetFilterCreate(c *gin.Context) {\n\tvar netF"
  },
  {
    "path": "gossh/app/service/policy_conf.go",
    "chars": 2101,
    "preview": "package service\n\nimport (\n\t\"gossh/app/model\"\n\t\"gossh/gin\"\n\t\"strconv\"\n)\n\nfunc PolicyConfCreate(c *gin.Context) {\n\tvar con"
  },
  {
    "path": "gossh/app/service/service_init.go",
    "chars": 2309,
    "preview": "package service\n\nimport (\n\t\"gossh/app/config\"\n\t\"io\"\n\t\"log/slog\"\n\t\"sync\"\n\t\"time\"\n)\n\n// OnlineClients 存储的客户端信息\nvar OnlineC"
  },
  {
    "path": "gossh/app/service/ssh_conf.go",
    "chars": 2108,
    "preview": "package service\n\nimport (\n\t\"gossh/app/model\"\n\t\"gossh/gin\"\n\t\"strconv\"\n)\n\nfunc ConfCreate(c *gin.Context) {\n\tvar config mo"
  },
  {
    "path": "gossh/app/service/ssh_conn.go",
    "chars": 10483,
    "preview": "package service\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"gossh/app/model\"\n\t\"gossh/app/utils\"\n\t\"gossh/crypto/ssh\"\n\t\"gossh/gin\""
  },
  {
    "path": "gossh/app/service/ssh_sftp.go",
    "chars": 6680,
    "preview": "package service\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"gossh/gin\"\n\t\"io\"\n\t\"log/slog\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"path\"\n\t\"strconv\"\n\t\"st"
  },
  {
    "path": "gossh/app/service/ssh_status.go",
    "chars": 1447,
    "preview": "package service\n\nimport (\n\t\"gossh/app/config\"\n\t\"gossh/gin\"\n\t\"gossh/gin/sse\"\n\t\"net/http\"\n\t\"sort\"\n\t\"time\"\n)\n\ntype SshConnB"
  },
  {
    "path": "gossh/app/service/sshd_cert.go",
    "chars": 3578,
    "preview": "package service\n\nimport (\n\t\"gossh/app/model\"\n\t\"gossh/gin\"\n\t\"log/slog\"\n\t\"strconv\"\n)\n\nfunc SshdCertCreate(c *gin.Context) "
  },
  {
    "path": "gossh/app/service/sshd_server.go",
    "chars": 14116,
    "preview": "package service\n\nimport (\n\t\"bytes\"\n\t\"crypto/rand\"\n\t\"crypto/rsa\"\n\t\"crypto/sha256\"\n\t\"crypto/sha512\"\n\t\"crypto/x509\"\n\t\"encod"
  },
  {
    "path": "gossh/app/service/sshd_user.go",
    "chars": 3193,
    "preview": "package service\n\nimport (\n\t\"gossh/app/model\"\n\t\"gossh/gin\"\n\t\"log/slog\"\n\t\"strconv\"\n)\n\nfunc SshdUserCreate(c *gin.Context) "
  },
  {
    "path": "gossh/app/service/sys_init.go",
    "chars": 5189,
    "preview": "package service\n\nimport (\n\t\"gossh/app/config\"\n\t\"gossh/app/model\"\n\t\"gossh/gin\"\n\t\"log/slog\"\n\t\"os/exec\"\n\t\"runtime\"\n)\n\nfunc "
  },
  {
    "path": "gossh/app/service/web_user.go",
    "chars": 6722,
    "preview": "package service\n\nimport (\n\t\"gossh/app/config\"\n\t\"gossh/app/middleware\"\n\t\"gossh/app/model\"\n\t\"gossh/app/utils\"\n\t\"gossh/gin\""
  },
  {
    "path": "gossh/app/utils/crypto.go",
    "chars": 3760,
    "preview": "package utils\n\nimport (\n\t\"bytes\"\n\t\"crypto/aes\"\n\t\"crypto/cipher\"\n\t\"crypto/rand\"\n\t\"encoding/base64\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\""
  },
  {
    "path": "gossh/app/utils/utils.go",
    "chars": 572,
    "preview": "package utils\n\nimport (\n\t\"math/rand\"\n\t\"time\"\n\t\"unicode/utf8\"\n)\n\n// RandString 生成指定长度随机字符串\nfunc RandString(length int) st"
  },
  {
    "path": "gossh/crypto/blowfish/block.go",
    "chars": 6161,
    "preview": "// Copyright 2010 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/blowfish/cipher.go",
    "chars": 3536,
    "preview": "// Copyright 2010 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/blowfish/const.go",
    "chars": 13132,
    "preview": "// Copyright 2010 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/chacha20/chacha_arm64.go",
    "chars": 441,
    "preview": "// Copyright 2018 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/chacha20/chacha_arm64.s",
    "chars": 8130,
    "preview": "// Copyright 2018 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/chacha20/chacha_generic.go",
    "chars": 14175,
    "preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/chacha20/chacha_noasm.go",
    "chars": 361,
    "preview": "// Copyright 2018 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/chacha20/chacha_ppc64le.go",
    "chars": 447,
    "preview": "// Copyright 2019 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/chacha20/chacha_ppc64le.s",
    "chars": 9315,
    "preview": "// Copyright 2019 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/chacha20/chacha_s390x.go",
    "chars": 736,
    "preview": "// Copyright 2018 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/chacha20/chacha_s390x.s",
    "chars": 5460,
    "preview": "// Copyright 2018 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/chacha20/xor.go",
    "chars": 1274,
    "preview": "// Copyright 2018 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/chacha20poly1305/chacha20poly1305.go",
    "chars": 2853,
    "preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/chacha20poly1305/chacha20poly1305_amd64.go",
    "chars": 2434,
    "preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/chacha20poly1305/chacha20poly1305_amd64.s",
    "chars": 107823,
    "preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/chacha20poly1305/chacha20poly1305_generic.go",
    "chars": 2183,
    "preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/chacha20poly1305/chacha20poly1305_noasm.go",
    "chars": 534,
    "preview": "// Copyright 2016 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/chacha20poly1305/xchacha20poly1305.go",
    "chars": 2574,
    "preview": "// Copyright 2018 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/curve25519/curve25519.go",
    "chars": 2156,
    "preview": "// Copyright 2019 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/curve25519/curve25519_compat.go",
    "chars": 2314,
    "preview": "// Copyright 2019 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/curve25519/curve25519_go120.go",
    "chars": 1113,
    "preview": "// Copyright 2022 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/curve25519/internal/field/fe.go",
    "chars": 11828,
    "preview": "// Copyright (c) 2017 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// lice"
  },
  {
    "path": "gossh/crypto/curve25519/internal/field/fe_amd64.go",
    "chars": 410,
    "preview": "// Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT.\n\n"
  },
  {
    "path": "gossh/crypto/curve25519/internal/field/fe_amd64.s",
    "chars": 5738,
    "preview": "// Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT.\n\n"
  },
  {
    "path": "gossh/crypto/curve25519/internal/field/fe_amd64_noasm.go",
    "chars": 326,
    "preview": "// Copyright (c) 2019 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// lice"
  },
  {
    "path": "gossh/crypto/curve25519/internal/field/fe_arm64.go",
    "chars": 338,
    "preview": "// Copyright (c) 2020 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// lice"
  },
  {
    "path": "gossh/crypto/curve25519/internal/field/fe_arm64.s",
    "chars": 1064,
    "preview": "// Copyright (c) 2020 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// lice"
  },
  {
    "path": "gossh/crypto/curve25519/internal/field/fe_arm64_noasm.go",
    "chars": 297,
    "preview": "// Copyright (c) 2021 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// lice"
  },
  {
    "path": "gossh/crypto/curve25519/internal/field/fe_generic.go",
    "chars": 8385,
    "preview": "// Copyright (c) 2017 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// lice"
  },
  {
    "path": "gossh/crypto/curve25519/internal/field/sync.checkpoint",
    "chars": 41,
    "preview": "b0c49ae9f59d233526f8934262c5bbbe14d4358d\n"
  },
  {
    "path": "gossh/crypto/curve25519/internal/field/sync.sh",
    "chars": 611,
    "preview": "#! /bin/bash\nset -euo pipefail\n\ncd \"$(git rev-parse --show-toplevel)\"\n\nSTD_PATH=src/crypto/ed25519/internal/edwards25519"
  },
  {
    "path": "gossh/crypto/internal/alias/alias.go",
    "chars": 1130,
    "preview": "// Copyright 2018 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/internal/alias/alias_purego.go",
    "chars": 1260,
    "preview": "// Copyright 2018 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/internal/poly1305/mac_noasm.go",
    "chars": 268,
    "preview": "// Copyright 2018 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/internal/poly1305/poly1305.go",
    "chars": 3386,
    "preview": "// Copyright 2012 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/internal/poly1305/sum_amd64.go",
    "chars": 1119,
    "preview": "// Copyright 2012 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/internal/poly1305/sum_amd64.s",
    "chars": 2545,
    "preview": "// Copyright 2012 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/internal/poly1305/sum_generic.go",
    "chars": 9682,
    "preview": "// Copyright 2018 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/internal/poly1305/sum_ppc64le.go",
    "chars": 1119,
    "preview": "// Copyright 2019 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/internal/poly1305/sum_ppc64le.s",
    "chars": 3298,
    "preview": "// Copyright 2019 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/internal/poly1305/sum_s390x.go",
    "chars": 2019,
    "preview": "// Copyright 2018 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/internal/poly1305/sum_s390x.s",
    "chars": 17106,
    "preview": "// Copyright 2018 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/internal/testenv/exec.go",
    "chars": 4629,
    "preview": "// Copyright 2023 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/internal/testenv/testenv_notunix.go",
    "chars": 401,
    "preview": "// Copyright 2021 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/internal/testenv/testenv_unix.go",
    "chars": 348,
    "preview": "// Copyright 2021 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/ssh/agent/client.go",
    "chars": 23738,
    "preview": "// Copyright 2012 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/ssh/agent/forward.go",
    "chars": 2207,
    "preview": "// Copyright 2014 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/ssh/agent/keyring.go",
    "chars": 5386,
    "preview": "// Copyright 2014 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/ssh/agent/server.go",
    "chars": 13617,
    "preview": "// Copyright 2012 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/ssh/buffer.go",
    "chars": 2180,
    "preview": "// Copyright 2012 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/ssh/certs.go",
    "chars": 17920,
    "preview": "// Copyright 2012 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/ssh/channel.go",
    "chars": 16479,
    "preview": "// Copyright 2011 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/ssh/cipher.go",
    "chars": 21743,
    "preview": "// Copyright 2011 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/ssh/client.go",
    "chars": 8789,
    "preview": "// Copyright 2011 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/ssh/client_auth.go",
    "chars": 23827,
    "preview": "// Copyright 2011 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/ssh/common.go",
    "chars": 13513,
    "preview": "// Copyright 2011 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/ssh/connection.go",
    "chars": 3413,
    "preview": "// Copyright 2013 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/ssh/doc.go",
    "chars": 1007,
    "preview": "// Copyright 2011 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/ssh/handshake.go",
    "chars": 22251,
    "preview": "// Copyright 2013 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/ssh/internal/bcrypt_pbkdf/bcrypt_pbkdf.go",
    "chars": 2423,
    "preview": "// Copyright 2014 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/ssh/kex.go",
    "chars": 22709,
    "preview": "// Copyright 2013 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/ssh/keys.go",
    "chars": 45753,
    "preview": "// Copyright 2012 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/ssh/knownhosts/knownhosts.go",
    "chars": 12565,
    "preview": "// Copyright 2017 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/ssh/mac.go",
    "chars": 1576,
    "preview": "// Copyright 2012 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/ssh/messages.go",
    "chars": 20723,
    "preview": "// Copyright 2011 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/ssh/mux.go",
    "chars": 8048,
    "preview": "// Copyright 2013 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/ssh/server.go",
    "chars": 26553,
    "preview": "// Copyright 2011 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/ssh/session.go",
    "chars": 15437,
    "preview": "// Copyright 2011 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/ssh/ssh_gss.go",
    "chars": 5570,
    "preview": "// Copyright 2011 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/ssh/streamlocal.go",
    "chars": 2939,
    "preview": "package ssh\n\nimport (\n\t\"errors\"\n\t\"io\"\n\t\"net\"\n)\n\n// streamLocalChannelOpenDirectMsg is a struct used for SSH_MSG_CHANNEL_"
  },
  {
    "path": "gossh/crypto/ssh/tcpip.go",
    "chars": 13152,
    "preview": "// Copyright 2011 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/ssh/terminal/terminal.go",
    "chars": 2570,
    "preview": "// Copyright 2011 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/crypto/ssh/transport.go",
    "chars": 9996,
    "preview": "// Copyright 2011 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "gossh/gin/auth.go",
    "chars": 3823,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "gossh/gin/binding/binding.go",
    "chars": 3492,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "gossh/gin/binding/default_validator.go",
    "chars": 2366,
    "preview": "// Copyright 2017 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "gossh/gin/binding/form.go",
    "chars": 1346,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "gossh/gin/binding/form_mapping.go",
    "chars": 9387,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "gossh/gin/binding/header.go",
    "chars": 869,
    "preview": "// Copyright 2022 Gin Core Team. All rights reserved.\n// Use of this source code is governed by a MIT style\n// license t"
  },
  {
    "path": "gossh/gin/binding/json.go",
    "chars": 1527,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "gossh/gin/binding/multipart_form_mapping.go",
    "chars": 2244,
    "preview": "// Copyright 2019 Gin Core Team. All rights reserved.\n// Use of this source code is governed by a MIT style\n// license t"
  },
  {
    "path": "gossh/gin/binding/query.go",
    "chars": 460,
    "preview": "// Copyright 2017 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "gossh/gin/binding/uri.go",
    "chars": 399,
    "preview": "// Copyright 2018 Gin Core Team. All rights reserved.\n// Use of this source code is governed by a MIT style\n// license t"
  },
  {
    "path": "gossh/gin/binding/xml.go",
    "chars": 676,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "gossh/gin/context.go",
    "chars": 36759,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "gossh/gin/debug.go",
    "chars": 2929,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "gossh/gin/errors.go",
    "chars": 3985,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "gossh/gin/fs.go",
    "chars": 1119,
    "preview": "// Copyright 2017 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "gossh/gin/gin.go",
    "chars": 22766,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "gossh/gin/ginS/README.md",
    "chars": 220,
    "preview": "# Gin Default Server\n\nThis is API experiment for Gin.\n\n```go\npackage main\n\nimport (\n\t\"gossh/gin\"\n\t\"gossh/gin/ginS\"\n)\n\nfu"
  },
  {
    "path": "gossh/gin/ginS/gins.go",
    "chars": 5575,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "gossh/gin/internal/bytesconv/bytesconv.go",
    "chars": 719,
    "preview": "// Copyright 2023 Gin Core Team. All rights reserved.\n// Use of this source code is governed by a MIT style\n// license t"
  },
  {
    "path": "gossh/gin/internal/json/json.go",
    "chars": 587,
    "preview": "// Copyright 2017 Bo-Yi Wu. All rights reserved.\n// Use of this source code is governed by a MIT style\n// license that c"
  },
  {
    "path": "gossh/gin/jwt/README.md",
    "chars": 7796,
    "preview": "# jwt-go\n\n[![build](https://github.com/golang-jwt/jwt/actions/workflows/build.yml/badge.svg)](https://github.com/golang-"
  },
  {
    "path": "gossh/gin/jwt/claims.go",
    "chars": 638,
    "preview": "package jwt\n\n// Claims represent any form of a JWT Claims Set according to\n// https://datatracker.ietf.org/doc/html/rfc7"
  },
  {
    "path": "gossh/gin/jwt/cmd/jwt/README.md",
    "chars": 624,
    "preview": "`jwt` command-line tool\n=======================\n\nThis is a simple tool to sign, verify and show JSON Web Tokens from\nthe"
  },
  {
    "path": "gossh/gin/jwt/cmd/jwt/main.go",
    "chars": 8118,
    "preview": "// A useful example app.  You can use this to debug your tokens on the command line.\n// This is also a great place to lo"
  },
  {
    "path": "gossh/gin/jwt/ecdsa.go",
    "chars": 3463,
    "preview": "package jwt\n\nimport (\n\t\"crypto\"\n\t\"crypto/ecdsa\"\n\t\"crypto/rand\"\n\t\"errors\"\n\t\"math/big\"\n)\n\nvar (\n\t// Sadly this is missing "
  },
  {
    "path": "gossh/gin/jwt/ecdsa_utils.go",
    "chars": 1580,
    "preview": "package jwt\n\nimport (\n\t\"crypto/ecdsa\"\n\t\"crypto/x509\"\n\t\"encoding/pem\"\n\t\"errors\"\n)\n\nvar (\n\tErrNotECPublicKey  = errors.New"
  },
  {
    "path": "gossh/gin/jwt/ed25519.go",
    "chars": 2074,
    "preview": "package jwt\n\nimport (\n\t\"crypto\"\n\t\"crypto/ed25519\"\n\t\"crypto/rand\"\n\t\"errors\"\n)\n\nvar (\n\tErrEd25519Verification = errors.New"
  },
  {
    "path": "gossh/gin/jwt/ed25519_utils.go",
    "chars": 1398,
    "preview": "package jwt\n\nimport (\n\t\"crypto\"\n\t\"crypto/ed25519\"\n\t\"crypto/x509\"\n\t\"encoding/pem\"\n\t\"errors\"\n)\n\nvar (\n\tErrNotEdPrivateKey "
  },
  {
    "path": "gossh/gin/jwt/errors.go",
    "chars": 1836,
    "preview": "package jwt\n\nimport (\n\t\"errors\"\n\t\"strings\"\n)\n\nvar (\n\tErrInvalidKey                = errors.New(\"key is invalid\")\n\tErrInv"
  },
  {
    "path": "gossh/gin/jwt/errors_go1_20.go",
    "chars": 1120,
    "preview": "//go:build go1.20\n// +build go1.20\n\npackage jwt\n\nimport (\n\t\"fmt\"\n)\n\n// Unwrap implements the multiple error unwrapping f"
  },
  {
    "path": "gossh/gin/jwt/errors_go_other.go",
    "chars": 2126,
    "preview": "//go:build !go1.20\n// +build !go1.20\n\npackage jwt\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n)\n\n// Is implements checking for multiple e"
  },
  {
    "path": "gossh/gin/jwt/hmac.go",
    "chars": 3411,
    "preview": "package jwt\n\nimport (\n\t\"crypto\"\n\t\"crypto/hmac\"\n\t\"errors\"\n)\n\n// SigningMethodHMAC implements the HMAC-SHA family of signi"
  },
  {
    "path": "gossh/gin/jwt/map_claims.go",
    "chars": 2691,
    "preview": "package jwt\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n)\n\n// MapClaims is a claims type that uses the map[string]interface{} for "
  },
  {
    "path": "gossh/gin/jwt/none.go",
    "chars": 1615,
    "preview": "package jwt\n\n// SigningMethodNone implements the none signing method.  This is required by the spec\n// but you probably "
  },
  {
    "path": "gossh/gin/jwt/parser.go",
    "chars": 7975,
    "preview": "package jwt\n\nimport (\n\t\"bytes\"\n\t\"encoding/base64\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"strings\"\n)\n\ntype Parser struct {\n\t// If popu"
  },
  {
    "path": "gossh/gin/jwt/parser_option.go",
    "chars": 4565,
    "preview": "package jwt\n\nimport \"time\"\n\n// ParserOption is used to implement functional-style options that modify the\n// behavior of"
  },
  {
    "path": "gossh/gin/jwt/registered_claims.go",
    "chars": 2321,
    "preview": "package jwt\n\n// RegisteredClaims are a structured version of the JWT Claims Set,\n// restricted to Registered Claim Names"
  },
  {
    "path": "gossh/gin/jwt/request/doc.go",
    "chars": 247,
    "preview": "// Utility package for extracting JWT tokens from\n// HTTP requests.\n//\n// The main function is ParseFromRequest and it's"
  },
  {
    "path": "gossh/gin/jwt/request/extractor.go",
    "chars": 3071,
    "preview": "package request\n\nimport (\n\t\"errors\"\n\t\"net/http\"\n\t\"strings\"\n)\n\n// Errors\nvar (\n\tErrNoTokenInRequest = errors.New(\"no toke"
  },
  {
    "path": "gossh/gin/jwt/request/oauth2.go",
    "chars": 821,
    "preview": "package request\n\nimport (\n\t\"strings\"\n)\n\n// Strips 'Bearer ' prefix from bearer token string\nfunc stripBearerPrefixFromTo"
  },
  {
    "path": "gossh/gin/jwt/request/request.go",
    "chars": 1928,
    "preview": "package request\n\nimport (\n\t\"net/http\"\n\n\t\"gossh/gin/jwt\"\n)\n\n// ParseFromRequest extracts and parses a JWT token from an H"
  },
  {
    "path": "gossh/gin/jwt/rsa.go",
    "chars": 2401,
    "preview": "package jwt\n\nimport (\n\t\"crypto\"\n\t\"crypto/rand\"\n\t\"crypto/rsa\"\n)\n\n// SigningMethodRSA implements the RSA family of signing"
  },
  {
    "path": "gossh/gin/jwt/rsa_pss.go",
    "chars": 3411,
    "preview": "package jwt\n\nimport (\n\t\"crypto\"\n\t\"crypto/rand\"\n\t\"crypto/rsa\"\n)\n\n// SigningMethodRSAPSS implements the RSAPSS family of s"
  },
  {
    "path": "gossh/gin/jwt/rsa_utils.go",
    "chars": 2916,
    "preview": "package jwt\n\nimport (\n\t\"crypto/rsa\"\n\t\"crypto/x509\"\n\t\"encoding/pem\"\n\t\"errors\"\n)\n\nvar (\n\tErrKeyMustBePEMEncoded = errors.N"
  },
  {
    "path": "gossh/gin/jwt/signing_method.go",
    "chars": 1539,
    "preview": "package jwt\n\nimport (\n\t\"sync\"\n)\n\nvar signingMethods = map[string]func() SigningMethod{}\nvar signingMethodLock = new(sync"
  },
  {
    "path": "gossh/gin/jwt/token.go",
    "chars": 3548,
    "preview": "package jwt\n\nimport (\n\t\"crypto\"\n\t\"encoding/base64\"\n\t\"encoding/json\"\n)\n\n// Keyfunc will be used by the Parse methods as a"
  },
  {
    "path": "gossh/gin/jwt/token_option.go",
    "chars": 185,
    "preview": "package jwt\n\n// TokenOption is a reserved type, which provides some forward compatibility,\n// if we ever want to introdu"
  },
  {
    "path": "gossh/gin/jwt/types.go",
    "chars": 4879,
    "preview": "package jwt\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"math\"\n\t\"strconv\"\n\t\"time\"\n)\n\n// TimePrecision sets the precision of times"
  },
  {
    "path": "gossh/gin/jwt/validator.go",
    "chars": 9751,
    "preview": "package jwt\n\nimport (\n\t\"crypto/subtle\"\n\t\"fmt\"\n\t\"time\"\n)\n\n// ClaimsValidator is an interface that can be implemented by c"
  },
  {
    "path": "gossh/gin/logger.go",
    "chars": 6986,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "gossh/gin/mode.go",
    "chars": 2342,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "gossh/gin/path.go",
    "chars": 3691,
    "preview": "// Copyright 2013 Julien Schmidt. All rights reserved.\n// Based on the path package, Copyright 2009 The Go Authors.\n// U"
  },
  {
    "path": "gossh/gin/recovery.go",
    "chars": 5205,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "gossh/gin/render/data.go",
    "chars": 639,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "gossh/gin/render/html.go",
    "chars": 2527,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "gossh/gin/render/json.go",
    "chars": 4804,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "gossh/gin/render/reader.go",
    "chars": 1208,
    "preview": "// Copyright 2018 Gin Core Team. All rights reserved.\n// Use of this source code is governed by a MIT style\n// license t"
  },
  {
    "path": "gossh/gin/render/redirect.go",
    "chars": 904,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "gossh/gin/render/render.go",
    "chars": 1084,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "gossh/gin/render/text.go",
    "chars": 1076,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "gossh/gin/render/xml.go",
    "chars": 730,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "gossh/gin/response_writer.go",
    "chars": 2854,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "gossh/gin/routergroup.go",
    "chars": 9280,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "gossh/gin/sessions/context/context.go",
    "chars": 3258,
    "preview": "package context\n\nimport (\n\t\"net/http\"\n\t\"sync\"\n\t\"time\"\n)\n\nvar (\n\tmutex sync.RWMutex\n\tdata  = make(map[*http.Request]map[a"
  },
  {
    "path": "gossh/gin/sessions/cookie/cookie.go",
    "chars": 931,
    "preview": "package cookie\n\nimport (\n\t\"gossh/gin/sessions\"\n\tgsessions \"gossh/gin/sessions/sessions\"\n)\n\ntype Store interface {\n\tsessi"
  },
  {
    "path": "gossh/gin/sessions/memstore/cache.go",
    "chars": 592,
    "preview": "package memstore\n\nimport (\n\t\"sync\"\n)\n\ntype cache struct {\n\tdata  map[string]valueType\n\tmutex sync.RWMutex\n}\n\nfunc newCac"
  },
  {
    "path": "gossh/gin/sessions/memstore/memstore.go",
    "chars": 4648,
    "preview": "package memstore\n\nimport (\n\t\"bytes\"\n\t\"encoding/base32\"\n\t\"encoding/gob\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"gossh/gin/sessio"
  },
  {
    "path": "gossh/gin/sessions/memstore/store.go",
    "chars": 863,
    "preview": "package memstore\n\nimport (\n\t\"gossh/gin/sessions\"\n)\n\ntype Store interface {\n\tsessions.Store\n}\n\n// Keys are defined in pai"
  },
  {
    "path": "gossh/gin/sessions/securecookie/securecookie.go",
    "chars": 20105,
    "preview": "// Copyright 2012 The Gorilla Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// lic"
  },
  {
    "path": "gossh/gin/sessions/session_options_go1.10.go",
    "chars": 739,
    "preview": "//go:build !go1.11\n// +build !go1.11\n\npackage sessions\n\nimport (\n\tgsessions \"gossh/gin/sessions/sessions\"\n)\n\n// Options "
  },
  {
    "path": "gossh/gin/sessions/session_options_go1.11.go",
    "chars": 1044,
    "preview": "//go:build go1.11\n// +build go1.11\n\npackage sessions\n\nimport (\n\t\"net/http\"\n\n\tgsessions \"gossh/gin/sessions/sessions\"\n)\n\n"
  },
  {
    "path": "gossh/gin/sessions/sessions/cookie.go",
    "chars": 428,
    "preview": "//go:build !go1.11\n// +build !go1.11\n\npackage sessions\n\nimport \"net/http\"\n\n// newCookieFromOptions returns an http.Cooki"
  },
  {
    "path": "gossh/gin/sessions/sessions/cookie_go111.go",
    "chars": 456,
    "preview": "//go:build go1.11\n// +build go1.11\n\npackage sessions\n\nimport \"net/http\"\n\n// newCookieFromOptions returns an http.Cookie "
  },
  {
    "path": "gossh/gin/sessions/sessions/doc.go",
    "chars": 7555,
    "preview": "// Copyright 2012 The Gorilla Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// lic"
  },
  {
    "path": "gossh/gin/sessions/sessions/lex.go",
    "chars": 1505,
    "preview": "// This file contains code adapted from the Go standard library\n// https://github.com/golang/go/blob/39ad0fd0789872f9469"
  },
  {
    "path": "gossh/gin/sessions/sessions/options.go",
    "chars": 497,
    "preview": "//go:build !go1.11\n// +build !go1.11\n\npackage sessions\n\n// Options stores configuration for a session or session store.\n"
  },
  {
    "path": "gossh/gin/sessions/sessions/options_go111.go",
    "chars": 579,
    "preview": "//go:build go1.11\n// +build go1.11\n\npackage sessions\n\nimport \"net/http\"\n\n// Options stores configuration for a session o"
  },
  {
    "path": "gossh/gin/sessions/sessions/sessions.go",
    "chars": 5767,
    "preview": "// Copyright 2012 The Gorilla Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// lic"
  },
  {
    "path": "gossh/gin/sessions/sessions/store.go",
    "chars": 8626,
    "preview": "// Copyright 2012 The Gorilla Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// lic"
  },
  {
    "path": "gossh/gin/sessions/sessions.go",
    "chars": 3553,
    "preview": "package sessions\n\nimport (\n\t\"log\"\n\t\"net/http\"\n\n\t\"gossh/gin\"\n\t\"gossh/gin/sessions/context\"\n\t\"gossh/gin/sessions/sessions\""
  },
  {
    "path": "gossh/gin/sse/sse-decoder.go",
    "chars": 3721,
    "preview": "// Copyright 2014 Manu Martinez-Almeida.  All rights reserved.\n// Use of this source code is governed by a MIT style\n// "
  },
  {
    "path": "gossh/gin/sse/sse-encoder.go",
    "chars": 2232,
    "preview": "// Copyright 2014 Manu Martinez-Almeida.  All rights reserved.\n// Use of this source code is governed by a MIT style\n// "
  },
  {
    "path": "gossh/gin/sse/writer.go",
    "chars": 395,
    "preview": "package sse\n\nimport \"io\"\n\ntype stringWriter interface {\n\tio.Writer\n\tWriteString(string) (int, error)\n}\n\ntype stringWrapp"
  },
  {
    "path": "gossh/gin/tree.go",
    "chars": 22897,
    "preview": "// Copyright 2013 Julien Schmidt. All rights reserved.\n// Use of this source code is governed by a BSD-style license tha"
  },
  {
    "path": "gossh/gin/utils.go",
    "chars": 3595,
    "preview": "// Copyright 2014 Manu Martinez-Almeida. All rights reserved.\n// Use of this source code is governed by a MIT style\n// l"
  },
  {
    "path": "gossh/gin/validator/baked_in.go",
    "chars": 83073,
    "preview": "package validator\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"crypto/sha256\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"net\"\n\t\"net/url\"\n\t\"os"
  },
  {
    "path": "gossh/gin/validator/cache.go",
    "chars": 7766,
    "preview": "package validator\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"strings\"\n\t\"sync\"\n\t\"sync/atomic\"\n)\n\ntype tagType uint8\n\nconst (\n\ttypeDefa"
  }
]

// ... and 797 more files (download for full content)

About this extraction

This page contains the full source code of the o8oo8o/GoWebSSH GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 997 files (12.8 MB), approximately 3.4M tokens, and a symbol index with 107986 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.

Copied to clipboard!