sboc add
This commit is contained in:
parent
95c40e4ae9
commit
04318ec2eb
|
@ -0,0 +1,42 @@
|
|||
BIN = sbotc
|
||||
|
||||
PREFIX = /usr/local
|
||||
BINDIR = $(PREFIX)/bin
|
||||
MANDIR = $(PREFIX)/share/man
|
||||
|
||||
CFLAGS = -Wall -Werror -Wextra
|
||||
|
||||
ifdef STATIC
|
||||
LDLIBS = -l:libsodium.a
|
||||
else
|
||||
LDLIBS = -lsodium
|
||||
endif
|
||||
|
||||
all: $(BIN)
|
||||
|
||||
$(BIN): $(BIN).c base64.c jsmn.c
|
||||
|
||||
install: all
|
||||
@mkdir -vp $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man1
|
||||
@cp -vf $(BIN) $(DESTDIR)$(BINDIR)
|
||||
@cp -vf $(BIN).1 $(DESTDIR)$(MANDIR)/man1
|
||||
|
||||
link: all
|
||||
@mkdir -vp $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man1
|
||||
@ln -svf $(shell realpath $(BIN)) $(DESTDIR)$(BINDIR)
|
||||
@ln -svf $(shell realpath $(BIN).1) $(DESTDIR)$(MANDIR)/man1
|
||||
|
||||
uninstall:
|
||||
@rm -vf \
|
||||
$(DESTDIR)$(BINDIR)/$(BIN) \
|
||||
$(DESTDIR)$(MANDIR)/man1/$(BIN).1
|
||||
|
||||
test-shs1:
|
||||
@# %lzzcAZlM21slUIoiH4yd/wgDnXu8raNLvwqjxqrU06k=.sha256
|
||||
shs1testclient ./test-shs-inner.sh $(SHS1_TEST_SEED)
|
||||
|
||||
clean:
|
||||
@rm -vf $(BIN)
|
||||
|
||||
.PHONY:
|
||||
all install link uninstall test-shs1 clean
|
|
@ -0,0 +1,31 @@
|
|||
# sbotc
|
||||
|
||||
A command-line SSB client in C. Use like the `sbot` command (except for `server`/`start`).
|
||||
|
||||
## Install
|
||||
|
||||
Install the dependency, *sodium*. On Debian: `sudo apt-get install libsodium-dev`
|
||||
|
||||
Compile and install the program:
|
||||
|
||||
```sh
|
||||
make
|
||||
sudo make install
|
||||
```
|
||||
|
||||
## Compile options
|
||||
|
||||
To build a binary statically linked with libsodium, use `make STATIC=1`
|
||||
|
||||
## Usage
|
||||
|
||||
```sh
|
||||
sbotc [-j] [-T] [-l] [-r] [-e]
|
||||
[ -n | [-c <cap>] [-k <key>] [-K <keypair_seed>] ]
|
||||
[ [-s <host>] [-p <port>] [ -4 | -6 ] | [-u <socket_path>] ]
|
||||
[ -a | [-t <type>] <method> [<argument>...] ]
|
||||
```
|
||||
|
||||
Arguments must be explicitly JSON-encoded.
|
||||
|
||||
For more information, see the manual page `sbotc(1)`.
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
|
||||
This code is public domain software.
|
||||
|
||||
*/
|
||||
|
||||
#include "base64.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
// single base64 character conversion
|
||||
//
|
||||
static int POS(char c)
|
||||
{
|
||||
if (c>='A' && c<='Z') return c - 'A';
|
||||
if (c>='a' && c<='z') return c - 'a' + 26;
|
||||
if (c>='0' && c<='9') return c - '0' + 52;
|
||||
if (c == '+') return 62;
|
||||
if (c == '/') return 63;
|
||||
if (c == '=') return -1;
|
||||
return -2;
|
||||
}
|
||||
|
||||
// base64 decoding
|
||||
//
|
||||
// s: base64 string
|
||||
// str_len size of the base64 string
|
||||
// data: output buffer for decoded data
|
||||
// data_len expected size of decoded data
|
||||
// return: 0 on success, -1 on failure
|
||||
//
|
||||
int base64_decode(const char* s, size_t str_len, void *data, size_t data_len)
|
||||
{
|
||||
const char *p, *str_end;
|
||||
unsigned char *q, *end;
|
||||
int n[4] = { 0, 0, 0, 0 };
|
||||
|
||||
if (str_len % 4) { errno = EBADMSG; return -1; }
|
||||
q = (unsigned char*) data;
|
||||
end = q + data_len;
|
||||
str_end = s + str_len;
|
||||
|
||||
for (p = s; p < str_end; ) {
|
||||
n[0] = POS(*p++);
|
||||
n[1] = POS(*p++);
|
||||
n[2] = POS(*p++);
|
||||
n[3] = POS(*p++);
|
||||
|
||||
if (n[0] == -2 || n[1] == -2 || n[2] == -2 || n[3] == -2)
|
||||
{ errno = EBADMSG; return -1; }
|
||||
|
||||
if (n[0] == -1 || n[1] == -1)
|
||||
{ errno = EBADMSG; return -1; }
|
||||
|
||||
if (n[2] == -1 && n[3] != -1)
|
||||
{ errno = EBADMSG; return -1; }
|
||||
|
||||
if (q >= end) { errno = EMSGSIZE; return -1; }
|
||||
q[0] = (n[0] << 2) + (n[1] >> 4);
|
||||
if (n[2] != -1) {
|
||||
if (q+1 >= end) { errno = EMSGSIZE; return -1; }
|
||||
q[1] = ((n[1] & 15) << 4) + (n[2] >> 2);
|
||||
}
|
||||
if (n[3] != -1) {
|
||||
if (q+2 >= end) { errno = EMSGSIZE; return -1; }
|
||||
q[2] = ((n[2] & 3) << 6) + n[3];
|
||||
}
|
||||
q += 3;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int base64_encode(const void* buf, size_t size, char *str, size_t out_size) {
|
||||
static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
char* p = str;
|
||||
const unsigned char* q = (const unsigned char*) buf;
|
||||
size_t i = 0;
|
||||
|
||||
if ((size+3)*4/3 + 1 > out_size) {
|
||||
errno = EMSGSIZE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (i < size) {
|
||||
int c = q[i++];
|
||||
c *= 256;
|
||||
if (i < size)
|
||||
c += q[i];
|
||||
i++;
|
||||
|
||||
c *= 256;
|
||||
if (i < size)
|
||||
c += q[i];
|
||||
i++;
|
||||
|
||||
*p++ = base64[(c & 0x00fc0000) >> 18];
|
||||
*p++ = base64[(c & 0x0003f000) >> 12];
|
||||
|
||||
if (i > size + 1)
|
||||
*p++ = '=';
|
||||
else
|
||||
*p++ = base64[(c & 0x00000fc0) >> 6];
|
||||
|
||||
if (i > size)
|
||||
*p++ = '=';
|
||||
else
|
||||
*p++ = base64[c & 0x0000003f];
|
||||
}
|
||||
|
||||
*p = 0;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
int base64_encode(const void* buf, size_t size, char *str, size_t out_size);
|
||||
int base64_decode(const char *s, size_t str_len, void *data, size_t data_len);
|
|
@ -0,0 +1,278 @@
|
|||
/**
|
||||
* jsmn
|
||||
* Copyright (c) 2010 Serge A. Zaitsev
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "jsmn.h"
|
||||
|
||||
/**
|
||||
* Allocates a fresh unused token from the token pull.
|
||||
*/
|
||||
static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
|
||||
jsmntok_t *tokens, size_t num_tokens) {
|
||||
jsmntok_t *tok;
|
||||
if (parser->toknext >= (int)num_tokens) {
|
||||
return NULL;
|
||||
}
|
||||
tok = &tokens[parser->toknext++];
|
||||
tok->start = tok->end = -1;
|
||||
tok->size = 0;
|
||||
#ifdef JSMN_PARENT_LINKS
|
||||
tok->parent = -1;
|
||||
#endif
|
||||
return tok;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills token type and boundaries.
|
||||
*/
|
||||
static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
|
||||
int start, int end) {
|
||||
token->type = type;
|
||||
token->start = start;
|
||||
token->end = end;
|
||||
token->size = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills next available token with JSON primitive.
|
||||
*/
|
||||
static jsmnerr_t jsmn_parse_primitive(jsmn_parser *parser, const char *js,
|
||||
jsmntok_t *tokens, size_t num_tokens) {
|
||||
jsmntok_t *token;
|
||||
int start;
|
||||
|
||||
start = parser->pos;
|
||||
|
||||
for (; js[parser->pos] != '\0'; parser->pos++) {
|
||||
switch (js[parser->pos]) {
|
||||
#ifndef JSMN_STRICT
|
||||
/* In strict mode primitive must be followed by "," or "}" or "]" */
|
||||
case ':':
|
||||
#endif
|
||||
case '\t' : case '\r' : case '\n' : case ' ' :
|
||||
case ',' : case ']' : case '}' :
|
||||
goto found;
|
||||
}
|
||||
if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
|
||||
parser->pos = start;
|
||||
return JSMN_ERROR_INVAL;
|
||||
}
|
||||
}
|
||||
#ifdef JSMN_STRICT
|
||||
/* In strict mode primitive must be followed by a comma/object/array */
|
||||
parser->pos = start;
|
||||
return JSMN_ERROR_PART;
|
||||
#endif
|
||||
|
||||
found:
|
||||
token = jsmn_alloc_token(parser, tokens, num_tokens);
|
||||
if (token == NULL) {
|
||||
parser->pos = start;
|
||||
return JSMN_ERROR_NOMEM;
|
||||
}
|
||||
jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
|
||||
#ifdef JSMN_PARENT_LINKS
|
||||
token->parent = parser->toksuper;
|
||||
#endif
|
||||
parser->pos--;
|
||||
return JSMN_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filsl next token with JSON string.
|
||||
*/
|
||||
static jsmnerr_t jsmn_parse_string(jsmn_parser *parser, const char *js,
|
||||
jsmntok_t *tokens, size_t num_tokens) {
|
||||
jsmntok_t *token;
|
||||
|
||||
int start = parser->pos;
|
||||
|
||||
parser->pos++;
|
||||
|
||||
/* Skip starting quote */
|
||||
for (; js[parser->pos] != '\0'; parser->pos++) {
|
||||
char c = js[parser->pos];
|
||||
|
||||
/* Quote: end of string */
|
||||
if (c == '\"') {
|
||||
token = jsmn_alloc_token(parser, tokens, num_tokens);
|
||||
if (token == NULL) {
|
||||
parser->pos = start;
|
||||
return JSMN_ERROR_NOMEM;
|
||||
}
|
||||
jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos);
|
||||
#ifdef JSMN_PARENT_LINKS
|
||||
token->parent = parser->toksuper;
|
||||
#endif
|
||||
return JSMN_SUCCESS;
|
||||
}
|
||||
|
||||
/* Backslash: Quoted symbol expected */
|
||||
if (c == '\\') {
|
||||
parser->pos++;
|
||||
switch (js[parser->pos]) {
|
||||
/* Allowed escaped symbols */
|
||||
case '\"': case '/' : case '\\' : case 'b' :
|
||||
case 'f' : case 'r' : case 'n' : case 't' :
|
||||
break;
|
||||
/* Allows escaped symbol \uXXXX */
|
||||
case 'u':
|
||||
/* TODO */
|
||||
break;
|
||||
/* Unexpected symbol */
|
||||
default:
|
||||
parser->pos = start;
|
||||
return JSMN_ERROR_INVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
parser->pos = start;
|
||||
return JSMN_ERROR_PART;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse JSON string and fill tokens.
|
||||
*/
|
||||
jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, jsmntok_t *tokens,
|
||||
unsigned int num_tokens) {
|
||||
jsmnerr_t r;
|
||||
int i;
|
||||
jsmntok_t *token;
|
||||
|
||||
for (; js[parser->pos] != '\0'; parser->pos++) {
|
||||
char c;
|
||||
jsmntype_t type;
|
||||
|
||||
c = js[parser->pos];
|
||||
switch (c) {
|
||||
case '{': case '[':
|
||||
token = jsmn_alloc_token(parser, tokens, num_tokens);
|
||||
if (token == NULL)
|
||||
return JSMN_ERROR_NOMEM;
|
||||
if (parser->toksuper != -1) {
|
||||
tokens[parser->toksuper].size++;
|
||||
#ifdef JSMN_PARENT_LINKS
|
||||
token->parent = parser->toksuper;
|
||||
#endif
|
||||
}
|
||||
token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
|
||||
token->start = parser->pos;
|
||||
parser->toksuper = parser->toknext - 1;
|
||||
break;
|
||||
case '}': case ']':
|
||||
type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
|
||||
#ifdef JSMN_PARENT_LINKS
|
||||
if (parser->toknext < 1) {
|
||||
return JSMN_ERROR_INVAL;
|
||||
}
|
||||
token = &tokens[parser->toknext - 1];
|
||||
for (;;) {
|
||||
if (token->start != -1 && token->end == -1) {
|
||||
if (token->type != type) {
|
||||
return JSMN_ERROR_INVAL;
|
||||
}
|
||||
token->end = parser->pos + 1;
|
||||
parser->toksuper = token->parent;
|
||||
break;
|
||||
}
|
||||
if (token->parent == -1) {
|
||||
break;
|
||||
}
|
||||
token = &tokens[token->parent];
|
||||
}
|
||||
#else
|
||||
for (i = parser->toknext - 1; i >= 0; i--) {
|
||||
token = &tokens[i];
|
||||
if (token->start != -1 && token->end == -1) {
|
||||
if (token->type != type) {
|
||||
return JSMN_ERROR_INVAL;
|
||||
}
|
||||
parser->toksuper = -1;
|
||||
token->end = parser->pos + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Error if unmatched closing bracket */
|
||||
if (i == -1) return JSMN_ERROR_INVAL;
|
||||
for (; i >= 0; i--) {
|
||||
token = &tokens[i];
|
||||
if (token->start != -1 && token->end == -1) {
|
||||
parser->toksuper = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case '\"':
|
||||
r = jsmn_parse_string(parser, js, tokens, num_tokens);
|
||||
if (r < 0) return r;
|
||||
if (parser->toksuper != -1)
|
||||
tokens[parser->toksuper].size++;
|
||||
break;
|
||||
case '\t' : case '\r' : case '\n' : case ':' : case ',': case ' ':
|
||||
break;
|
||||
#ifdef JSMN_STRICT
|
||||
/* In strict mode primitives are: numbers and booleans */
|
||||
case '-': case '0': case '1' : case '2': case '3' : case '4':
|
||||
case '5': case '6': case '7' : case '8': case '9':
|
||||
case 't': case 'f': case 'n' :
|
||||
#else
|
||||
/* In non-strict mode every unquoted value is a primitive */
|
||||
default:
|
||||
#endif
|
||||
r = jsmn_parse_primitive(parser, js, tokens, num_tokens);
|
||||
if (r < 0) return r;
|
||||
if (parser->toksuper != -1)
|
||||
tokens[parser->toksuper].size++;
|
||||
break;
|
||||
|
||||
#ifdef JSMN_STRICT
|
||||
/* Unexpected char in strict mode */
|
||||
default:
|
||||
return JSMN_ERROR_INVAL;
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
for (i = parser->toknext - 1; i >= 0; i--) {
|
||||
/* Unmatched opened object or array */
|
||||
if (tokens[i].start != -1 && tokens[i].end == -1) {
|
||||
return JSMN_ERROR_PART;
|
||||
}
|
||||
}
|
||||
|
||||
return JSMN_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new parser based over a given buffer with an array of tokens
|
||||
* available.
|
||||
*/
|
||||
void jsmn_init(jsmn_parser *parser) {
|
||||
parser->pos = 0;
|
||||
parser->toknext = 0;
|
||||
parser->toksuper = -1;
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
#ifndef __JSMN_H_
|
||||
#define __JSMN_H_
|
||||
|
||||
/**
|
||||
* JSON type identifier. Basic types are:
|
||||
* o Object
|
||||
* o Array
|
||||
* o String
|
||||
* o Other primitive: number, boolean (true/false) or null
|
||||
*/
|
||||
typedef enum {
|
||||
JSMN_PRIMITIVE = 0,
|
||||
JSMN_OBJECT = 1,
|
||||
JSMN_ARRAY = 2,
|
||||
JSMN_STRING = 3
|
||||
} jsmntype_t;
|
||||
|
||||
typedef enum {
|
||||
/* Not enough tokens were provided */
|
||||
JSMN_ERROR_NOMEM = -1,
|
||||
/* Invalid character inside JSON string */
|
||||
JSMN_ERROR_INVAL = -2,
|
||||
/* The string is not a full JSON packet, more bytes expected */
|
||||
JSMN_ERROR_PART = -3,
|
||||
/* Everything was fine */
|
||||
JSMN_SUCCESS = 0
|
||||
} jsmnerr_t;
|
||||
|
||||
/**
|
||||
* JSON token description.
|
||||
* @param type type (object, array, string etc.)
|
||||
* @param start start position in JSON data string
|
||||
* @param end end position in JSON data string
|
||||
*/
|
||||
typedef struct {
|
||||
jsmntype_t type;
|
||||
int start;
|
||||
int end;
|
||||
int size;
|
||||
#ifdef JSMN_PARENT_LINKS
|
||||
int parent;
|
||||
#endif
|
||||
} jsmntok_t;
|
||||
|
||||
/**
|
||||
* JSON parser. Contains an array of token blocks available. Also stores
|
||||
* the string being parsed now and current position in that string
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned int pos; /* offset in the JSON string */
|
||||
int toknext; /* next token to allocate */
|
||||
int toksuper; /* superior token node, e.g parent object or array */
|
||||
} jsmn_parser;
|
||||
|
||||
/**
|
||||
* Create JSON parser over an array of tokens
|
||||
*/
|
||||
void jsmn_init(jsmn_parser *parser);
|
||||
|
||||
/**
|
||||
* Run JSON parser. It parses a JSON data string into and array of tokens, each describing
|
||||
* a single JSON object.
|
||||
*/
|
||||
jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js,
|
||||
jsmntok_t *tokens, unsigned int num_tokens);
|
||||
|
||||
#endif /* __JSMN_H_ */
|
Binary file not shown.
|
@ -0,0 +1,190 @@
|
|||
.Dd 2017-06-03
|
||||
.Dt SBOTC 1
|
||||
.Os SSBC
|
||||
.ds REPO ssb://%133ulDgs/oC1DXjoK04vDFy6DgVBB/Zok15YJmuhD5Q=.sha256
|
||||
.Sh NAME
|
||||
.Nm sbotc
|
||||
.Nd Call a scuttlebot/secret-stack RPC method
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl j
|
||||
.Op Fl l
|
||||
.Op Fl r
|
||||
.Op Fl T
|
||||
.Op Fl e
|
||||
.Op Fl a
|
||||
.
|
||||
.Oo
|
||||
.Fl n
|
||||
|
|
||||
.Op Fl c Ar cap
|
||||
.Op Fl k Ar key
|
||||
.Op Fl K Ar keypair
|
||||
.Oc
|
||||
.
|
||||
.Oo
|
||||
.Op Fl s Ar host
|
||||
.Op Fl p Ar port
|
||||
.Oo
|
||||
.Fl 4
|
||||
|
|
||||
.Fl 6
|
||||
.Oc
|
||||
|
|
||||
.Op Fl u Ar socket_path
|
||||
.Oc
|
||||
.
|
||||
.Oo
|
||||
.Fl a
|
||||
|
|
||||
.Op Fl t Ar type
|
||||
.Ar method
|
||||
.Op Ar argument ...
|
||||
.Oc
|
||||
.Sh DESCRIPTION
|
||||
Connect to a scuttlebot/secret-stack server, and call a method on it, with
|
||||
standard I/O.
|
||||
.Sh OPTIONS
|
||||
.Bl -tag
|
||||
.It Fl j
|
||||
Send stdin data as JSON.
|
||||
.It Fl l
|
||||
Don't output newlines after string or JSON packets.
|
||||
.It Fl r
|
||||
Raw mode. Disables stdin line buffering/editing and echoing. Implies
|
||||
.Fl l .
|
||||
.It Fl e
|
||||
Encode arguments as strings, rather than expecting them to be JSON-encoded.
|
||||
.It Fl T
|
||||
Test using shs1-testsuite protocol. Instead of connecting to a server and running
|
||||
a command, connect to stdio. On successful handshake, output concatenation of
|
||||
the encryption key, encryption nonce, decryption key and decryption nonce.
|
||||
.It Fl a
|
||||
Passthrough mode. Instead of making a muxrpc call, pass through the box-stream
|
||||
to stdio.
|
||||
.It Fl n
|
||||
Noauth mode. Skip secret-handshake authentication and box-stream encryption.
|
||||
This option makes the
|
||||
.Fl k ,
|
||||
.Fl K ,
|
||||
and
|
||||
.Fl c
|
||||
options have no effect and output a warning if used.
|
||||
.It Fl 4
|
||||
Connect to server over IPv4 only.
|
||||
.It Fl 6
|
||||
Connect to server over IPv6 only.
|
||||
.It Fl c Ar cap
|
||||
Capability key for secret-handshake. Default is SSB's capability key,
|
||||
.Li 1KHLiKZvAvjbY1ziZEHMXawbCEIM6qwjCDm3VYRan/s= .
|
||||
.It Fl s Ar host
|
||||
The hostname to connect to. Default is localhost. If set to localhost and connection to localhost fails,
|
||||
.Nm
|
||||
may attempt to connect to other local interface addresses.
|
||||
.It Fl p Ar port
|
||||
The port to connect to. Default is 8008.
|
||||
.It Fl u Ar socket_path
|
||||
Unix socket path to connect to, instead of TCP socket. Conflicts with
|
||||
.Fl p
|
||||
and
|
||||
.Fl s .
|
||||
.It Fl k Ar key
|
||||
The key to connect to. Default is your public key, as read from your
|
||||
private key file.
|
||||
.It Fl K Ar keypair
|
||||
Private key or private key seed to use for secret-handshake. Default is to use the private key
|
||||
from your
|
||||
.Pa ~/.ssb/secret
|
||||
file or other secret file according to the environmental variables described in
|
||||
.Sx ENVIRONMENT .
|
||||
.It Fl t Ar type
|
||||
The type of method:
|
||||
.Dq async ,
|
||||
.Dq source ,
|
||||
.Dq sink ,
|
||||
or
|
||||
.Dq duplex .
|
||||
Default is to look up the method in
|
||||
.Pa ~/.ssb/manifest.json .
|
||||
.It Ar method
|
||||
Method name.
|
||||
.It Op Ar argument ...
|
||||
Arguments to pass to the method call. Each argument must be JSON-encoded, unless the
|
||||
.Fl e
|
||||
option is used, in which the arguments are treated as strings.
|
||||
.El
|
||||
.Sh ENVIRONMENT
|
||||
.Bl -tag
|
||||
.It Ev ssb_appname
|
||||
Name of the app. Default is
|
||||
.Dq ssb .
|
||||
Used to construct the app's directory if
|
||||
.Ev ssb_path
|
||||
is not present.
|
||||
.It Ev ssb_path
|
||||
Path to the app's directory. Default is to use
|
||||
.Ev ssb_appname to construct the path as
|
||||
.Dq ~/.<ssb_appname>
|
||||
.El
|
||||
.Sh FILES
|
||||
.Bl -tag -width -indent
|
||||
.It Pa ~/.ssb/secret
|
||||
Your private key, used for authenticating to the server with the
|
||||
secret-handshake protocol.
|
||||
.It Pa ~/.ssb/manifest.json
|
||||
A map of method names to method types.
|
||||
.It Pa ~/.ssb/config
|
||||
JSON file containing key, host, port, and/or SHS cap key to use if the
|
||||
.Fl s ,
|
||||
.Fl p
|
||||
or
|
||||
.Fl c
|
||||
options are not given, respectively.
|
||||
.It Pa ~/.ssb/socket
|
||||
UNIX socket stream file for noauth connections.
|
||||
If none of the options
|
||||
.Fl s ,
|
||||
.Fl p ,
|
||||
.Fl u ,
|
||||
.Fl c ,
|
||||
.Fl k ,
|
||||
.Fl K ,
|
||||
.Fl c ,
|
||||
.Fl 4 ,
|
||||
.Fl 6 ,
|
||||
or
|
||||
.Fl T
|
||||
are specified,
|
||||
.Nm
|
||||
will attempt to connect in noauth mode to this socket file. If the socket file
|
||||
is not present or the connection fails,
|
||||
.Nm
|
||||
will fall back to connecting with TCP and secret-handshake according to the
|
||||
config file - unless the
|
||||
.Fl n
|
||||
option is specified, in which case the command will fail.
|
||||
.El
|
||||
.Pp
|
||||
The base path
|
||||
.Dq ~/.ssb/
|
||||
of these file names may be changed by setting
|
||||
.Ev ssb_appname
|
||||
or
|
||||
.Ev ssb_path .
|
||||
.Sh EXIT STATUS
|
||||
.Bl -tag -width Ds
|
||||
.It 0
|
||||
The command completed successfully.
|
||||
.It 1
|
||||
An error occurred.
|
||||
.It 2
|
||||
The command completed with an error.
|
||||
.El
|
||||
.Sh AUTHORS
|
||||
.Nm
|
||||
was written by
|
||||
.An cel Aq @f/6sQ6d2CMxRUhLpspgGIulDxDCwYD7DzFzPNr7u5AU=.ed25519 .
|
||||
.Sh BUGS
|
||||
.Pp
|
||||
Please report any bugs by making a post on SSB mentioning the repo,
|
||||
.Lk \*[REPO]
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,8 @@
|
|||
#!/bin/sh
|
||||
cap_hex=${1?shs cap key}
|
||||
pk_hex=${2?server public key}
|
||||
|
||||
cap_b64="$(echo -n "$cap_hex" | xxd -r -p | base64)"
|
||||
pk_b64="$(echo -n "$pk_hex" | xxd -r -p | base64)"
|
||||
|
||||
exec sbotc -T -c "$cap_b64" -k "$pk_b64"
|
Loading…
Reference in New Issue