# Getting Started with TWSSH

This guide will help you get up and running with TWSSH quickly.

## Table of Contents

1. [Installation](#installation)
2. [License Setup](#license-setup)
3. [Your First Connection](#your-first-connection)
4. [Running Commands](#running-commands)
5. [Authentication Methods](#authentication-methods)
6. [Error Handling](#error-handling)
7. [Next Steps](#next-steps)

---

## Installation

### Using NuGet (Recommended)

```bash
# .NET CLI
dotnet add package TwSsh

# Package Manager Console
Install-Package TwSsh
```

### From Package Files

If you received TWSSH as a package distribution:

1. Copy the `.nupkg` files from the `lib` folder to a local directory
2. Add the directory as a NuGet source:

```bash
dotnet nuget add source ./path/to/lib --name TwSshLocal
dotnet add package TwSsh
```

### Project Configuration

TWSSH supports the following frameworks:

```xml
<TargetFramework>net8.0</TargetFramework>  <!-- Recommended -->
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>netstandard2.1</TargetFramework>
```

---

## License Setup

TWSSH requires a valid license for production use. Choose one of the following activation methods:

### Option 1: License Key String

```csharp
using TwSsh.Licensing;

// Call this once at application startup
LicenseManager.Instance.Initialize("eyJJZCI6IjQwMmZmN2Q2Y2E2...");
```

### Option 2: License File

```csharp
// Load from specific path
LicenseManager.Instance.InitializeFromFile("C:/licenses/twssh.lic");
```

### Option 3: Auto-Discovery

Place a file named `twssh.lic` in your application directory. TWSSH will automatically find and load it.

### Option 4: Auto-Initialize (Recommended for Production)

Use `TryAutoInitialize()` to automatically search for and load a license from common locations:

```csharp
// Try to find and load license from standard locations
if (LicenseManager.Instance.TryAutoInitialize())
{
    Console.WriteLine("License loaded successfully!");
}
else
{
    Console.WriteLine("No license found. Get a trial at https://twssh.io");
}
```

### Getting a Trial License

Get a free 30-day trial license at [https://twssh.io](https://twssh.io). Download includes a trial license file.

**Search locations (in order):**
1. `twssh.lic` in current directory
2. `license.lic` in current directory
3. Application directory
4. `%APPDATA%\TwSsh\license.lic` (Windows)
5. `%PROGRAMDATA%\TwSsh\license.lic` (Windows)
6. `~/.config/twssh/license.lic` (Linux/macOS)

### Verify License Status

```csharp
if (LicenseManager.Instance.IsInitialized)
{
    var info = LicenseManager.Instance.LicenseInfo;
    Console.WriteLine($"License Type: {info.Type}");
    Console.WriteLine($"Expires: {info.Expires?.ToString("yyyy-MM-dd") ?? "Never"}");
    Console.WriteLine($"Max Connections: {info.MaxConnections}");
}
```

---

## Your First Connection

Here's a complete example of connecting to an SSH server:

```csharp
using System;
using System.Threading.Tasks;
using TwSsh.Client;
using TwSsh.Authentication;
using TwSsh.Licensing;

class Program
{
    static async Task Main(string[] args)
    {
        // Step 1: Initialize license (do this once at startup)
        LicenseManager.Instance.Initialize("YOUR-LICENSE-KEY");

        // Step 2: Configure connection settings
        var settings = new SshClientSettings
        {
            Host = "192.168.1.100",
            Port = 22,
            Credential = new PasswordCredential("username", "password"),
            ConnectionTimeout = TimeSpan.FromSeconds(30)
        };

        // Step 3: Create client and connect
        await using var client = new SshClient(settings);

        try
        {
            await client.ConnectAndAuthenticateAsync();
            Console.WriteLine("Connected successfully!");
            Console.WriteLine($"Server: {client.ConnectionInfo?.ServerVersion}");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Connection failed: {ex.Message}");
        }
    }
}
```

### Simplified Constructor

For quick connections, use the simplified constructor:

```csharp
await using var client = new SshClient(
    "192.168.1.100",
    22,
    new PasswordCredential("user", "pass"));

await client.ConnectAndAuthenticateAsync();
```

---

## Running Commands

### Simple Command Execution

```csharp
// Run a command and get the result
var result = await client.RunCommandAsync("uname -a");

Console.WriteLine($"Exit Code: {result.ExitCode}");
Console.WriteLine($"Output: {result.Output}");
Console.WriteLine($"Errors: {result.ErrorOutput}");

// Check success
if (result.IsSuccess)
{
    Console.WriteLine("Command succeeded!");
}
```

### Multiple Commands

```csharp
// Run multiple commands
var commands = new[] { "hostname", "whoami", "pwd", "date" };

foreach (var cmd in commands)
{
    var result = await client.RunCommandAsync(cmd);
    Console.WriteLine($"{cmd}: {result.Output.Trim()}");
}
```

### Command with Long Output

```csharp
// Commands with large output work seamlessly
var result = await client.RunCommandAsync("find /var/log -name '*.log' 2>/dev/null");

foreach (var line in result.Output.Split('\n'))
{
    Console.WriteLine(line);
}
```

### Command with Exit Code

```csharp
var result = await client.RunCommandAsync("test -f /etc/passwd && echo 'exists'");

if (result.ExitCode == 0)
{
    Console.WriteLine("File exists!");
}
else
{
    Console.WriteLine("File not found");
}
```

---

## Authentication Methods

### Password Authentication

```csharp
var credential = new PasswordCredential("username", "password");

var settings = new SshClientSettings
{
    Host = "example.com",
    Credential = credential
};
```

### Public Key Authentication

```csharp
using TwSsh.Core.Authentication;  // For PrivateKeyParser
using TwSsh.Authentication;

// Load private key from file (second parameter is passphrase, null if unencrypted)
var privateKey = PrivateKeyParser.LoadFromFile("/home/user/.ssh/id_rsa", null);

// Or from string (second parameter is passphrase, null if unencrypted)
var keyContent = File.ReadAllText("/home/user/.ssh/id_ed25519");
var privateKey = PrivateKeyParser.Parse(keyContent, null);

// Load encrypted key with passphrase
var encryptedKey = PrivateKeyParser.LoadFromFile("/home/user/.ssh/id_rsa", "passphrase");

var credential = new PrivateKeyCredential("username", privateKey);

var settings = new SshClientSettings
{
    Host = "example.com",
    Credential = credential
};

// Remember to dispose the credential when done
using (credential)
{
    await using var client = new SshClient(settings);
    await client.ConnectAndAuthenticateAsync();
    // ... use client
}
```

### Keyboard-Interactive Authentication

```csharp
// Simple password-based keyboard-interactive
var credential = KeyboardInteractiveCredential.FromPassword("user", "password");

// Custom handler for multi-factor authentication
var mfaCredential = new KeyboardInteractiveCredential("user",
    (instruction, prompts, echo) =>
    {
        var responses = new string[prompts.Length];

        for (int i = 0; i < prompts.Length; i++)
        {
            Console.Write(prompts[i]);

            if (echo[i])
                responses[i] = Console.ReadLine();
            else
                responses[i] = ReadPassword(); // Your secure input method
        }

        return responses;
    });
```

### Multiple Authentication Attempts

```csharp
await using var client = new SshClient(settings);
await client.ConnectAsync();

// Try public key first
var keyCredential = new PrivateKeyCredential("user", privateKey);
if (!await client.AuthenticateAsync(keyCredential))
{
    // Fall back to password
    var passCredential = new PasswordCredential("user", "password");
    await client.AuthenticateAsync(passCredential);
}
```

---

## Error Handling

### Connection Errors

```csharp
using TwSsh.Common;     // For SshConnectionException, SshAuthenticationException
using TwSsh.Licensing;  // For LicenseException

try
{
    await client.ConnectAndAuthenticateAsync();
}
catch (SshConnectionException ex)
{
    // Network errors, timeout, host unreachable
    Console.WriteLine($"Connection failed: {ex.Message}");
}
catch (SshAuthenticationException ex)
{
    // Wrong credentials, auth method not supported
    Console.WriteLine($"Authentication failed: {ex.Message}");
}
catch (LicenseException ex)
{
    // License not valid, expired, or feature not available
    Console.WriteLine($"License error: {ex.Message}");
}
```

### Command Errors

```csharp
var result = await client.RunCommandAsync("some_command");

if (!result.IsSuccess)
{
    Console.WriteLine($"Command failed with exit code: {result.ExitCode}");
    Console.WriteLine($"Error output: {result.ErrorOutput}");
}
```

### Timeouts

```csharp
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));

try
{
    var result = await client.RunCommandAsync("long_running_command", cts.Token);
}
catch (OperationCanceledException)
{
    Console.WriteLine("Command timed out");
}
catch (TimeoutException)
{
    Console.WriteLine("Operation timed out");
}
```

### Host Key Verification

```csharp
var settings = new SshClientSettings
{
    Host = "example.com",
    Credential = credential,
    HostKeyVerification = HostKeyVerificationMode.Callback,
    HostKeyCallback = (args) =>
    {
        Console.WriteLine($"Host key fingerprint: {args.Fingerprint}");
        Console.WriteLine($"Key type: {args.KeyType}");

        // Verify against known fingerprint
        return args.Fingerprint == "SHA256:expected_fingerprint_here";
    }
};
```

---

## Next Steps

Now that you have the basics, explore these advanced features:

### Interactive Shell

```csharp
await using var shell = await client.CreateShellAsync();

// Wait for prompt
await shell.ExpectAsync("$");

// Execute command interactively
shell.WriteLine("ls -la");
var output = await shell.ExpectAsync("$");
Console.WriteLine(output);
```

See: [Shell Interaction Tutorial](TUTORIALS.md#interactive-shell)

### SFTP File Transfer

```csharp
using TwSsh.Sftp;

// Create SFTP client from authenticated SSH connection
await using var sftp = await SftpClient.ConnectAsync(client);

// Upload a file
await sftp.UploadFileAsync("C:/local/file.txt", "/remote/file.txt");

// Download a file
await sftp.DownloadFileAsync("/remote/data.csv", "C:/local/data.csv");

// List directory
var files = await sftp.ListDirectoryAsync("/home/user");
foreach (var file in files)
{
    Console.WriteLine($"{file.FileName} - {file.Size} bytes");
}
```

See: [SFTP Tutorial](TUTORIALS.md#sftp-file-transfer)

### Port Forwarding

```csharp
// Local port forwarding (SSH -L)
await using var tunnel = await client.ForwardLocalPortAsync(
    "127.0.0.1", 8080,
    "127.0.0.1", 3306);

// Now localhost:8080 connects to remote MySQL
```

See: [Port Forwarding Tutorial](TUTORIALS.md#port-forwarding)

---

## Complete Example Application

Here's a complete console application demonstrating various features:

```csharp
using System;
using System.Threading.Tasks;
using TwSsh.Client;
using TwSsh.Authentication;
using TwSsh.Licensing;

namespace TwSshDemo
{
    class Program
    {
        static async Task Main(string[] args)
        {
            // Initialize license
            LicenseManager.Instance.Initialize("YOUR-LICENSE-KEY");

            Console.Write("Host: ");
            var host = Console.ReadLine();

            Console.Write("Username: ");
            var username = Console.ReadLine();

            Console.Write("Password: ");
            var password = ReadPassword();

            var settings = new SshClientSettings
            {
                Host = host,
                Port = 22,
                Credential = new PasswordCredential(username, password),
                ConnectionTimeout = TimeSpan.FromSeconds(30),
                OperationTimeout = TimeSpan.FromMinutes(1)
            };

            try
            {
                await using var client = new SshClient(settings);
                await client.ConnectAndAuthenticateAsync();

                Console.WriteLine($"\nConnected to {client.ConnectionInfo.ServerVersion}");
                Console.WriteLine("Enter commands (type 'exit' to quit):\n");

                while (true)
                {
                    Console.Write($"{username}@{host}$ ");
                    var command = Console.ReadLine();

                    if (string.IsNullOrWhiteSpace(command))
                        continue;

                    if (command.Equals("exit", StringComparison.OrdinalIgnoreCase))
                        break;

                    var result = await client.RunCommandAsync(command);

                    if (!string.IsNullOrEmpty(result.Output))
                        Console.Write(result.Output);

                    if (!string.IsNullOrEmpty(result.ErrorOutput))
                        Console.Error.Write(result.ErrorOutput);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"\nError: {ex.Message}");
                return;
            }

            Console.WriteLine("\nDisconnected.");
        }

        static string ReadPassword()
        {
            var password = "";
            ConsoleKeyInfo key;

            do
            {
                key = Console.ReadKey(true);

                if (key.Key != ConsoleKey.Enter && key.Key != ConsoleKey.Backspace)
                {
                    password += key.KeyChar;
                    Console.Write("*");
                }
                else if (key.Key == ConsoleKey.Backspace && password.Length > 0)
                {
                    password = password[..^1];
                    Console.Write("\b \b");
                }
            }
            while (key.Key != ConsoleKey.Enter);

            Console.WriteLine();
            return password;
        }
    }
}
```

---

## Troubleshooting

### Common Issues

**"License not initialized"**
- Call `LicenseManager.Instance.Initialize()` before creating any `SshClient`

**"Connection timed out"**
- Check firewall rules
- Verify host and port are correct
- Increase `ConnectionTimeout` in settings

**"Authentication failed"**
- Verify credentials are correct
- Check if the authentication method is supported by the server
- Check server logs for more details

**"Feature not available"**
- Upgrade your license tier to access the feature
- Use `LicenseManager.Instance.HasFeature()` to check availability
- Note: The enum is named `LicenseFeatures` (plural): `LicenseManager.Instance.HasFeature(LicenseFeatures.PortForwarding)`

---

For more information, see:
- [API Reference](API-REFERENCE.md)
- [Tutorials](TUTORIALS.md)
- [Licensing Guide](LICENSING.md)

---

Copyright 2025 Terminalworks Ltd. All rights reserved.
