beach
Types
ssh client connection.
pub type Connection =
@internal Connection
ssh client connection information.
pub type ConnectionInfo {
ConnectionInfo(username: String, ip_address: String, port: Int)
}
Constructors
-
ConnectionInfo(username: String, ip_address: String, port: Int)
pub type StartError {
AddressInUse
SshApplicationNotStarted
HostKeyNotFound
SshDaemonFault(String)
}
Constructors
-
AddressInUsePort in use by another application
-
SshApplicationNotStartedErlang ssh application is not running
-
HostKeyNotFoundssh host key files not found
-
SshDaemonFault(String)unexpected other term() provided by ssh:daemon (which should be converted to strict value, open issue/pr if found)
Values
pub fn auth_anonymous() -> @internal Auth
Allow anyone to connect without requiring a password or public key
pub fn auth_password(
auth: fn(String, String) -> Bool,
) -> @internal Auth
Provide a password challenge for users to complete
Example
fn user_login(username: String, password: String) -> Bool {
case username, password {
"Joe", "Hello!" -> True
_, _ -> False
}
}
fn main() {
let auth = auth_password(user_login)
config(auth:, ..)
}
pub fn auth_public_key(
auth: fn(String, @internal PublicKey) -> Bool,
) -> @internal Auth
Provide public key challenge. public key must be present in
authorized_keys file held in the user_directory folder.
Requires a callback function which containers the username on successful authentication. Can be used for further validation, logging, etc.
Note: It is safe to have this function always return True e.g. fn(_) { True }
Example
fn user_login(username: String, public_key: PublicKey) -> Bool {
let challenge =
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOE7rwqgX3K2Cj8wY/gAOiEQ0T9lEINdNwFq9HEVXB71 username@shore"
|> public_key
challenge == public_key && username == "Joe"
}
fn main() {
let auth = auth_public_key(user_login)
config(auth:, ..)
}
pub fn auth_public_key_or_password(
password_auth password_auth: fn(String, String) -> Bool,
key_auth key_auth: fn(String, @internal PublicKey) -> Bool,
) -> @internal Auth
Provide public key challenge, falling back to password challenge if no matching public key.
Alternatively, uses can set their preferred auth method via the -o PreferredAuthentications=password,publickey.
See individual examples for auth_public_key and auth_password for implementation.
pub fn config(
port port: Int,
host_key_directory host_key_directory: String,
auth auth: @internal Auth,
on_connect on_connect: fn(
@internal Connection,
process.Subject(@internal Event(msg)),
) -> Nil,
on_disconnect on_disconnect: fn(
@internal Connection,
process.Subject(@internal Event(msg)),
) -> Nil,
max_sessions max_sessions: option.Option(Int),
) -> @internal Config(msg)
Configuration for a beach ssh server
port: defines the port to expose the ssh server on
host_key_directory: the directory which contains an ssh public and private host key
auth: the authentication challenge type to use (anonymous, password, keys)
can be created from cli with ssh-keygen -t ed25519 -f ssh_host_ed25519_key -N ''
on_connect: a callback to run on a new connection, exposes the ssh username
as well as the newly started shore subject (this can be sent messages via actor.send)
on_disconnect: a callback to run when a connection terminates for any
reason, exposes the ssh username as well as the specific shore subject.
max_sessions: the maximum number of ssh sessions that can be open at once,
this includes login attempts.
Example
beach.config(
port: 2222,
host_key_directory: ".",
auth: beach.auth_anonymous(),
on_connect: fn(_connection, _shore) { Nil },
on_disconnect: fn(_connection, _shore) { Nil },
max_sessions: Some(1000),
)
pub fn connection_info(
info: @internal Connection,
) -> ConnectionInfo
Provides information from an ssh connection.
pub fn public_key(public_key: String) -> @internal PublicKey
Converts an OpenSSH public key string into a PublicKey type for comparison
Example
public_key("ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOE7rwqgX3K2Cj8wY/gAOiEQ0T9lEINdNwFq9HEVXB71 username@shore")
pub fn start(
spec: @internal Spec(model, msg),
config: @internal Config(msg),
) -> Result(process.Pid, StartError)
Starts an ssh server serving shore application to connecting clients.
Example
pub fn main() {
let spec =
shore.spec(
init:,
update:,
view:,
exit: process.new_subject(),
keybinds: shore.default_keybinds(),
redraw: shore.on_timer(16),
)
let config =
beach.config(
port: 2222,
host_key_directory: ".",
auth: beach.auth_anonymous(),
on_connect: fn(_connection, _shore) { Nil },
on_disconnect: fn(_connection, _shore) { Nil },
max_sessions: Some(1000),
)
let assert Ok(_) = beach.start(spec, config)
process.sleep_forever()
}