Bumps BP_VERSION to 0.2.0, BP_MIN_COMPATIBLE_VERSION to 0.2.0, adds the comprehensive 0.2.0 CHANGELOG entry. Fixes the last asymmetry surfaced by the TCP-loopback ED25519 test: the originator's ED25519 M_PWD path didn't populate FSessionPwd, so post-auth CRYPT activation was asymmetric (answerer set up the stream, originator didn't, both hung waiting to decrypt each other's garbage). The originator now runs the same OnLookupPassword lookup the answerer's OnFrame_MPWD uses, so CRYPT keys agree or don't activate on either side. Examples grew FPC_BINKP_PRIVKEY / FPC_BINKP_PEERKEY env var hooks so a two-process TCP loopback can exercise the full ED25519+CRYPT+GZ stack end-to-end. example_outbound also prints the session's final AuthMethod + TX block. Live loopback result (same-machine TCP, both ends fpc-binkp): - 64 KB AAAA file, ED25519 auth + CRYPT stream cipher + EXTCMD GZ + secure-routing, delivered in 607 wire bytes, SHA-verified byte-identical on inbound secure dir. - Inbound trace confirms full ED25519 path: keypair derived, answerer challenge issued, originator's signature verified, AuthMethod=bpAuthED25519. All 98 checks across 7 test programs green, 5 platforms clean (x86_64-linux, i386-go32v2, i386-os2, i386-win32, i386-linux, i386-freebsd). Live Argus regression still passes (regular + FREQ-client).
143 lines
3.9 KiB
ObjectPascal
143 lines
3.9 KiB
ObjectPascal
{ example_outbound -- connect to a remote BinkP peer and send
|
|
one file. Uses the library's reference TCP transport and
|
|
filesystem provider.
|
|
|
|
Build: fpc -Mobjfpc -Fu../src -Fu../../fpc-msgbase/src
|
|
-Fu../../fpc-log/src example_outbound.pas
|
|
|
|
Run: ./example_outbound host[:port] password file-to-send
|
|
|
|
Example:
|
|
./example_outbound 192.0.2.5:24554 SecretPwd /tmp/TEST.PKT
|
|
|
|
UNIX only (Linux / FreeBSD) — reference transport is UNIX-only
|
|
for v0.1.0. Windows / OS2 / DOS consumers provide their own
|
|
IBPTransport. }
|
|
|
|
program example_outbound;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
uses
|
|
SysUtils,
|
|
log.types, log.console,
|
|
mb.address,
|
|
bp.types, bp.config, bp.session,
|
|
bp.transport.tcp, bp.provider.fs;
|
|
|
|
type
|
|
TPwdLookup = class
|
|
public
|
|
Password: string;
|
|
PeerPubHex: string; { from FPC_BINKP_PEERKEY env -- empty ok }
|
|
function Lookup(const Addr: TFTNAddress): string;
|
|
function LookupPub(const Addr: TFTNAddress): string;
|
|
end;
|
|
|
|
function TPwdLookup.Lookup(const Addr: TFTNAddress): string;
|
|
begin
|
|
Result := Password;
|
|
end;
|
|
|
|
function TPwdLookup.LookupPub(const Addr: TFTNAddress): string;
|
|
begin
|
|
Result := PeerPubHex;
|
|
end;
|
|
|
|
procedure Usage;
|
|
begin
|
|
WriteLn('usage: example_outbound host[:port] password file-to-send');
|
|
Halt(2);
|
|
end;
|
|
|
|
var
|
|
HostArg, Pwd, FilePath, Host: string;
|
|
Port: Word;
|
|
ColonPos: Integer;
|
|
Cfg: TBPSessionConfig;
|
|
Transport: TBPTcpTransport;
|
|
Provider: TBPFsProvider;
|
|
Session: TBPSession;
|
|
Logger: TConsoleLogger;
|
|
PwdLookup: TPwdLookup;
|
|
begin
|
|
if ParamCount < 3 then Usage;
|
|
HostArg := ParamStr(1);
|
|
Pwd := ParamStr(2);
|
|
FilePath := ParamStr(3);
|
|
|
|
Port := 24554;
|
|
ColonPos := Pos(':', HostArg);
|
|
if ColonPos > 0 then
|
|
begin
|
|
Port := StrToIntDef(Copy(HostArg, ColonPos + 1, Length(HostArg)), 24554);
|
|
Host := Copy(HostArg, 1, ColonPos - 1);
|
|
end
|
|
else
|
|
Host := HostArg;
|
|
|
|
Logger := TConsoleLogger.Create(llDebug);
|
|
PwdLookup := TPwdLookup.Create;
|
|
PwdLookup.Password := Pwd;
|
|
PwdLookup.PeerPubHex := GetEnvironmentVariable('FPC_BINKP_PEERKEY');
|
|
Provider := TBPFsProvider.Create('', ''); { no inbound needed here }
|
|
Provider.Enqueue(FilePath, bpFsKeep);
|
|
|
|
try
|
|
Transport := TBPTcpTransport.CreateClient(Host, Port);
|
|
except
|
|
on E: Exception do
|
|
begin
|
|
WriteLn('connect failed: ', E.Message);
|
|
Halt(3);
|
|
end;
|
|
end;
|
|
|
|
BPConfigDefaults(Cfg);
|
|
SetLength(Cfg.LocalAddrs, 1);
|
|
Cfg.LocalAddrs[0] := MakeFTNAddress(1, 218, 720, 0);
|
|
Cfg.SystemName := 'fpc-binkp example';
|
|
Cfg.MailerName := 'example_outbound/0.1';
|
|
Cfg.Transport := Transport;
|
|
Cfg.Provider := Provider;
|
|
Cfg.Log := @Logger.Log;
|
|
Cfg.OnLookupPassword := @PwdLookup.Lookup;
|
|
Cfg.PrivateKey := GetEnvironmentVariable('FPC_BINKP_PRIVKEY');
|
|
Cfg.OnLookupPubKey := @PwdLookup.LookupPub;
|
|
|
|
Session := TBPSession.Create(bpDirOutbound, Cfg);
|
|
try
|
|
while Session.NextStep do
|
|
Transport.WaitReady(True, False, 50); { yield 50ms when idle }
|
|
if Session.Result_.Success then
|
|
begin
|
|
WriteLn(Format('OK: sent %d files, %d uncompressed bytes (%d on wire)',
|
|
[Session.Result_.FilesSent,
|
|
Session.Result_.BytesSent,
|
|
Session.Result_.WireBytesSent]));
|
|
WriteLn(Format(' final TX-block: %d',
|
|
[Session.Stats.CurrentTxBlock]));
|
|
case Session.Result_.AuthMethod of
|
|
bpAuthNone: WriteLn(' auth: NOPWD');
|
|
bpAuthPlain: WriteLn(' auth: plain');
|
|
bpAuthCRAM: WriteLn(' auth: CRAM-MD5');
|
|
bpAuthED25519: WriteLn(' auth: ED25519');
|
|
else WriteLn(' auth: other ', Ord(Session.Result_.AuthMethod));
|
|
end;
|
|
Halt(0);
|
|
end
|
|
else
|
|
begin
|
|
WriteLn(Format('FAIL: %s (code %d)',
|
|
[Session.Result_.ErrorMessage, Ord(Session.Result_.ErrorCode)]));
|
|
Halt(1);
|
|
end;
|
|
finally
|
|
Session.Free;
|
|
PwdLookup.Free;
|
|
Logger.Free;
|
|
{ Transport and Provider are TInterfacedObject and free
|
|
via ref-count when Cfg goes out of scope. }
|
|
end;
|
|
end.
|