Croc's Password Relay Authentication Mechanism Using the --pass Flag
Croc's password relay authentication mechanism validates custom passwords during the TCP handshake by passing the --pass flag value through the determinePass function in src/cli/cli.go to tcp.ConnectToTCPServer in src/croc/croc.go, ensuring only authenticated clients can join the transfer room.
The schollz/croc tool enables secure cross-platform file transfers using relay servers to bridge network gaps. When operating a private relay or requiring additional access control beyond the default passphrase, Croc's password relay authentication mechanism allows users to specify a custom credential using the --pass command-line flag or the CROC_PASS environment variable.
Parsing the Password in the CLI Layer
The authentication flow begins in src/cli/cli.go, where the determinePass helper function extracts the password from user input. This function checks for the explicit --pass flag first, then falls back to the CROC_PASS environment variable, and finally defaults to the standard passphrase if neither is provided.
// src/cli/cli.go (approximate line 379)
RelayPassword: determinePass(c),
The implementation sanitizes the input by trimming whitespace and assigns the result to the Options.RelayPassword field. This field is defined in src/models/options.go alongside the DEFAULT_PASSPHRASE constant, which the system uses as a baseline for comparison.
Propagating the Password to the Transfer Command
Once parsed, the password flows into the core client logic in src/croc/croc.go. When generating the command string that receivers must execute, the code explicitly checks whether Options.RelayPassword differs from models.DEFAULT_PASSPHRASE. If a custom value is detected, it appends the flag to the generated command using a strings.Builder.
// src/croc/croc.go (lines 1345-1347)
if c.Options.RelayPassword != models.DEFAULT_PASSPHRASE {
flags.WriteString("--pass " + c.Options.RelayPassword + " ")
}
This constructed command is printed to standard error and copied to the system clipboard, ensuring the receiver receives the exact authentication credential required to access the transfer.
Authenticating with the Relay Server
The actual authentication occurs during the TCP handshake. In src/croc/croc.go, the client invokes tcp.ConnectToTCPServer and passes Options.RelayPassword as the second argument. This function transmits the credential to the relay server for validation before establishing the encrypted data channel.
// src/croc/croc.go (lines 1410-1412)
conn, banner, ipaddr, err = tcp.ConnectToTCPServer(
address,
c.Options.RelayPassword,
c.Options.RoomName,
durations[i],
)
If the relay rejects the password, the connection attempt fails immediately with an authentication error. This prevents unauthorized clients from joining the room even if they possess the correct room code.
Practical Usage Examples
Sending Files with a Custom Password
To protect a file transfer with a specific credential, include the flag when invoking the send command:
croc send --pass mySecretPassword document.pdf
Croc will output a receiver command that includes the authentication flag:
Code is: 1234-5678-9012
On the other computer run:
croc --pass mySecretPassword 1234-5678-9012
Receiving with Password Authentication
The receiver must execute the complete command including the password to authenticate successfully:
croc --pass mySecretPassword 1234-5678-9012
Omitting the flag or providing an incorrect password results in an immediate connection failure with a "could not secure channel" error.
Using Environment Variables
For automation scripts where command-line arguments might expose sensitive data in shell history, use the environment variable:
export CROC_PASS=mySecretPassword
croc send document.pdf
The determinePass function in src/cli/cli.go automatically reads this variable when the --pass flag is absent.
Programmatic Implementation in Go
When embedding Croc's client library directly in Go applications, set the password in the Options struct:
import "github.com/schollz/croc/v9/src/croc"
opts := croc.Options{
RelayAddress: "relay://custom.example.com:9009",
RelayPassword: "mySecretPassword",
RoomName: "secure-room",
}
client, err := croc.NewClient(opts)
if err != nil {
log.Fatal(err)
}
This approach bypasses the CLI parsing layer and injects the password directly into the connection logic.
Summary
Croc's password relay authentication mechanism operates through three distinct phases:
- CLI Parsing: The determinePass function in
src/cli/cli.goextracts passwords from the--passflag orCROC_PASSenvironment variable. - Command Construction: In
src/croc/croc.go, custom passwords are appended to the receiver's command string via flags.WriteString when they differ from models.DEFAULT_PASSPHRASE. - Network Authentication: The tcp.ConnectToTCPServer function in
src/croc/croc.gotransmits the password during the initial TCP handshake, validating the client before data transfer begins.
Frequently Asked Questions
How does Croc handle the --pass flag internally?
Croc processes the flag through the determinePass helper in src/cli/cli.go, which assigns the value to Options.RelayPassword. This value is then passed to tcp.ConnectToTCPServer during the relay connection phase to authenticate the client session against the relay's access control list.
Can I set a custom password via environment variables?
Yes. The determinePass function checks for the CROC_PASS environment variable as a fallback when the --pass flag is not explicitly provided. This allows secure configuration in CI/CD pipelines without exposing credentials in command history or process listings.
What happens if the relay password is incorrect?
If the password provided via --pass or CROC_PASS does not match the relay's expected credential, tcp.ConnectToTCPServer returns an authentication error immediately after the TCP handshake. The client displays a "could not secure channel" message and terminates the connection attempt before any file data is exchanged.
Is the password visible in process listings when using --pass?
Yes, when passed as a command-line flag, the password may appear in process listings (ps output) and shell history. For sensitive transfers, use the CROC_PASS environment variable instead, which keeps the credential out of the process argument list while still being processed by the determinePass function in src/cli/cli.go.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →