PHP Classes

File: bin/create-client.php

Recommend this page to a friend!
  Classes of Scott Arciszewski   Chronicle   bin/create-client.php   Download  
File: bin/create-client.php
Role: Example script
Content type: text/plain
Description: Example script
Class: Chronicle
Append arbitrary data to a storage container
Author: By
Last change: Boyscouting
Fix double quote errors
Fix escaping issue for SQLite in create-client script
Concurrent Chronicles

Add support for multiple instances via the ?instance=name parameter.

To implement, add something like this to your local/settings.json in the
instances key:

"public_prefix" => "table_name_prefix"

Then run bin/make-tables.php as normal.

Every instance is totally independent of each other. They have their own

* Clients
* Chain data
* Cross-Signing Targets and Policies
* Replications

If merged, I will document these features and roll it into v1.1.0
Add newline
Consistent error styles
Add -j / --json flag to bin/create-client.php to get JSON output
Future Genesis blocks will have a NULL prevhash, thereby allowing UNIQUE
FOREIGN KEY constraints to be created on prevhash pointing to a previous
row's currahsh.
Docblock consistency, fix composer internal server
Type safety
Upgrade composer dependencies
Minor bugfixes.
Date: 1 year ago
Size: 4,373 bytes
 

Contents

Class file image Download
<?php
declare(strict_types=1);

use
GetOpt\{
   
GetOpt,
   
Option
};
use
ParagonIE\EasyDB\{
   
EasyDB,
   
Factory
};
use
ParagonIE\Chronicle\Chronicle;
use
ParagonIE\Chronicle\Exception\InstanceNotFoundException;
use
ParagonIE\ConstantTime\Base64UrlSafe;
use
ParagonIE\Sapient\CryptographyKeys\SigningPublicKey;

$root = \dirname(__DIR__);
/** @psalm-suppress UnresolvableInclude */
require_once $root . '/cli-autoload.php';

if (!\
is_readable($root . '/local/settings.json')) {
    echo
'Settings are not loaded.', PHP_EOL;
    exit(
1);
}

/** @var array $settings */
$settings = \json_decode(
    (string) \
file_get_contents($root . '/local/settings.json'),
   
true
);
/** @var EasyDB $db */
$db = Factory::create(
   
$settings['database']['dsn'],
   
$settings['database']['username'] ?? '',
   
$settings['database']['password'] ?? '',
   
$settings['database']['options'] ?? []
);

// Pass database instance to Chronicle
Chronicle::setDatabase($db);

/**
 * @var Getopt $getopt
 *
 * This defines the Command Line options.
 *
 * These two are equivalent:
 * php create-client.php -p foo
 * php create-client.php --publickey=foo
 */
$getopt = new Getopt([
    new
Option('p', 'publickey', Getopt::REQUIRED_ARGUMENT),
    new
Option('c', 'comment', Getopt::OPTIONAL_ARGUMENT),
    new
Option('j', 'json', Getopt::OPTIONAL_ARGUMENT),
    new
Option(null, 'administrator', Getopt::OPTIONAL_ARGUMENT),
    new
Option('i', 'instance', Getopt::OPTIONAL_ARGUMENT),
]);
$getopt->process();

/** @var string $publicKey */
$publicKey = $getopt->getOption('publickey');
/** @var string $comment */
$comment = $getopt->getOption('comment') ?? '';
/** @var bool $admin */
$admin = $getopt->getOption('administrator') ?? false;
/** @var bool $json */
$json = $getopt->getOption('json') ?? false;
/** @var string $instance */
$instance = $getopt->getOption('instance') ?? '';

try {
    if (!empty(
$instance)) {
        if (!\
array_key_exists($instance, $settings['instances'])) {
            throw new
InstanceNotFoundException(
               
'Instance ' . $instance . ' not found'
           
);
        }
       
Chronicle::setTablePrefix($settings['instances'][$instance]);
    }
} catch (
InstanceNotFoundException $ex) {
    echo
$ex->getMessage(), PHP_EOL;
    exit(
1);
}

if (empty(
$publicKey)) {
    echo
'Usage:', PHP_EOL, "\t",
       
'php create-client.php -p publickeygoeshere [-c comment] [--administrator]', PHP_EOL, PHP_EOL;
    exit(
1);
}

/** @var SigningPublicKey $publicKeyObj */
// Make sure it's a valid public key:
try {
   
$publicKeyObj = new SigningPublicKey(
       
Base64UrlSafe::decode($publicKey)
    );
} catch (\
Throwable $ex) {
    if (
$json) {
        echo
json_encode([
           
'status' => false,
           
'message' => $ex->getMessage(),
           
'data' => [
               
'trace' => $ex->getTrace()
            ]
        ]),
PHP_EOL;
    } else {
        echo
$ex->getMessage(), PHP_EOL;
    }
    exit(
1);
}

// Generate a unique ID for the user:
/** @var string $newPublicId */
$newPublicId = Base64UrlSafe::encode(\random_bytes(24));

// Disable escaping for SQLite
/** @var boolean $isSQLite */
$isSQLite = strpos($settings['database']['dsn'] ?? '', 'sqlite:') !== false;

$db->beginTransaction();
$db->insert(
   
Chronicle::getTableNameUnquoted('clients', $isSQLite),
    [
       
'isAdmin' => !empty($admin),
       
'publicid' => $newPublicId,
       
'publickey' => $publicKey
   
]
);
if (
$db->commit()) {
    if (
$json) {
        echo
json_encode([
           
'status' => true,
           
'message' => 'Client successfully created!',
           
'data' => [
               
'publicId' => $newPublicId,
               
'administrator' => !empty($admin)
            ]
        ]);
        exit(
0);
    }
   
// Success.
   
if (!empty($admin)) {
        echo
"\t" . 'Client (' . $newPublicId . ') created successfully with administrative privileges!', PHP_EOL;
    } else {
        echo
"\t" . 'Client (' . $newPublicId . ') created successfully!', PHP_EOL;
    }
} else {
   
$db->rollBack();
   
/** @var array<int, string> $errorInfo */
   
$errorInfo = $db->errorInfo();

    if (
$json) {
        echo
json_encode([
           
'status' => false,
           
'message' => $errorInfo[0],
           
'data' => []
        ]),
PHP_EOL;
    } else {
        echo
$errorInfo[0], PHP_EOL;
    }
    exit(
1);
}