Plugin Directory

Changeset 2737154


Ignore:
Timestamp:
06/03/2022 08:58:14 PM (4 years ago)
Author:
psqr
Message:

v 0.1.2 trunk modifications

Location:
virtual-public-square/trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • virtual-public-square/trunk/psqr.php

    r2723045 r2737154  
    77Plugin URI: https://vpsqr.com/
    88Description: Virtual Public Squares operate on identity. Add self-hosted, cryptographically verifiable, decentralized identity to your site and authors.
    9 Version: 0.1.1
     9Version: 0.1.2
    1010Author: Virtual Public Square
    1111Author URI: https://vpsqr.com
     
    3232use Jose\Component\Signature\Serializer\JWSSerializerManager;
    3333
     34if ( ! function_exists('write_log')) {
     35    function write_log ( $log )  {
     36        $prefix = '|| Virtual Public Square || ';
     37        if ( is_array( $log ) || is_object( $log ) ) {
     38            error_log( $prefix . print_r( $log, true ) );
     39        } else {
     40            error_log( $prefix . $log );
     41        }
     42    }
     43}
     44
    3445if ( !class_exists( 'PSQR' ) ) {
    3546
     
    4152            'application/json',
    4253            'application/did+json'
     54        ];
     55
     56        // set required php extensions
     57        const REQUIRED_EXT = [
     58            'json',
     59            'mbstring',
     60            'openssl'
    4361        ];
    4462
     
    6583                    'status' => 400
    6684                ]
    67             ]
     85            ],
     86            'ext_missing' => [
     87                'code'    => 'ext_missing',
     88                'message' => 'The required php extensions are missing',
     89                'data'    => [
     90                    'status' => 500
     91                ]
     92            ],
    6893        ];
    6994
    70         private $available_dids = [];
     95        private $ext_missing = array();
     96        private $available_dids = array();
    7197        private JWSSerializerManager $serializer_manager;
    7298        private JWSVerifier $jws_verifier;
    7399
    74100        function __construct() {
     101            // check for missing php extensions
     102            $this->ext_missing = $this->check_extensions();
    75103
    76104            // create necessary directories
     
    84112                new CompactSerializer(),
    85113            ]);
     114
     115            // add notice on admin page
     116            add_action('after_plugin_row', array($this, 'add_ext_warning'));
    86117
    87118            // setup did and api response
     
    110141        }
    111142
     143        static function check_extensions(): array {
     144            $ext_missing = [];
     145            foreach (PSQR::REQUIRED_EXT as $ext) {
     146                if (extension_loaded($ext) === false) {
     147                    write_log('WARNING: missing php extension required for DID validation: ' . $ext);
     148                    array_push($ext_missing, $ext);
     149                }
     150            }
     151
     152            return $ext_missing;
     153        }
     154
    112155        static function setup_dirs() {
    113156            // determine dir path
     
    120163                $dir_resp = mkdir($author_dir, 0777, true);
    121164                if ($dir_resp === false) {
     165                    write_log('ERROR: unable to create psqr-identities directory');
    122166                    return false;
    123167                }
     
    134178
    135179            if ($identity === false) {
     180                write_log('ERROR: Unable to find DID from provided data');
     181                write_log($data);
    136182                wp_send_json(PSQR::RESPONSES['did_missing'], 404);
    137183            }
     
    147193
    148194            if (isset($body->id) === false || $body->id !== $request_did) {
     195                write_log('ERROR: DID mismatch for ' . $request_did);
    149196                wp_send_json([
    150197                    'code'    => 'did_mismatch',
     
    159206            $valid_resp = $this->validate_identity($body);
    160207            if ($valid_resp['valid'] === false) {
     208                write_log('ERROR: invalid DID ' . $valid_resp['message']);
    161209                wp_send_json([
    162210                    'code'    => 'did_invalid',
     
    170218            $response = $this->store_identity('/author/' . $name, $body);
    171219            if ($response === false) {
     220                write_log('ERROR: Unable to store identity for ' . $name);
    172221                wp_send_json(PSQR::RESPONSES['did_error'], 400);
    173222            }
     
    193242
    194243            // return empty object if no data found
    195             if ($identity_obj === null) {
     244            if ($identity_obj === NULL) {
    196245                return false;
    197246            }
     
    265314        function validate_update(string $path, string $token): bool
    266315        {
    267             $kid;
    268             $jws;
     316            $kid = NULL;
     317            $jws = '';
    269318            try {
    270319                $jws = $this->serializer_manager->unserialize($token);
    271320                $kid = $jws->getSignatures()[0]->getProtectedHeader()['kid'];
    272321            } catch (\Throwable $th) {
     322                write_log('ERROR: Unable to serialize JWS');
    273323                return false;
    274324            }
    275325
    276326            // get didDoc specified in header
    277             $matches;
     327            $matches = NULL;
    278328            preg_match('/did:psqr:[^\/]+([^#]+)/', $kid, $matches);
    279329            $kidPath = $matches[1];
     
    281331            // fail if path from signature doesn't match request path
    282332            if ($path !== $kidPath) {
     333                write_log('ERROR: JWS signature path does not match request path');
    283334                return false;
    284335            }
     
    287338
    288339            if ($didDoc === false) {
    289                 return false;
    290             }
    291 
     340                write_log('ERROR: Unable to retrieve DID doc for JWS');
     341                return false;
     342            }
    292343
    293344            // try to find valid public keys
     
    298349                $k = $keys[$j];
    299350                if ($k->kid === $kid) {
    300                     $pubKey = new JWK((array) $k, 0);
     351                    $pubKey = new JWK((array) $k);
    301352
    302353                    break;
     
    305356            // return false if no pubKey was found
    306357            if ($pubKey === false) {
     358                write_log('ERROR: No pubkey matching ' . $kid . ' found in current DID doc');
    307359                return false;
    308360            }
     
    322374            // return false if no grant was found or doesn't contain admin
    323375            if ($keyGrant === false || in_array('admin', $keyGrant) === false) {
     376                write_log('ERROR: No admin grant found for ' . $kid . ' in current DID doc');
    324377                return false;
    325378            }
     
    333386            $method = $_SERVER['REQUEST_METHOD'];
    334387
     388            error_log('----------------------------------------------------------------------------');
     389            write_log('INFO: Evaluating ' . $method . ' request to path ' . $path);
     390
    335391            // retrieve, sanitize, and validate JWS string if present
    336             $jws_matches;
     392            $jws_matches = array();
    337393            $raw_input = file_get_contents('php://input');
    338             preg_match('/[A-Za-z0-9_\-]+\.[A-Za-z0-9_\-]+\.[A-Za-z0-9_\-]+/', $raw_input, $jws_matches);
    339             $jws = empty($jws_matches) ? '' : $jws_matches[0];
     394
     395            $jws = '';
     396            $json_object = json_decode($raw_input, false);
     397
     398            if ($json_object !== NULL) {
     399                preg_match('/[A-Za-z0-9_\-]+\.[A-Za-z0-9_\-]+\.[A-Za-z0-9_\-]+/', $json_object->token, $jws_matches, PREG_UNMATCHED_AS_NULL);
     400                $jws = empty($jws_matches) ? '' : $json_object->token;
     401            }
     402
     403            write_log('INFO: Parsed JWS from response: ' . $jws);
    340404
    341405            $headers = array_change_key_case(array_map('strtolower', getallheaders()), CASE_LOWER);
    342406            $accept_header = $headers['accept'];
     407
     408            // ensure required php extensions exist for PUTs and DELETEs
     409            if ((strtoupper($method) === 'PUT' || strtoupper($method) === 'DELETE') && count($this->ext_missing) !== 0) {
     410                write_log('ERROR: there are some required php extensions missing from the current installation: ' . implode(", ", $this->ext_missing));
     411                $error_response = PSQR::RESPONSES['ext_missing'];
     412                $error_response['message'] = $error_response['message'] . ': ' . implode(", ", $this->ext_missing);
     413                wp_send_json($error_response, 500);
     414            }
    343415
    344416            if ($path === '.well-known/psqr') {
     
    388460        function update_did(string $path, string $body)
    389461        {
     462            write_log('INFO: updating DID with path ' . $path);
    390463            $signature_valid = $this->validate_update($path, $body);
    391464
    392465            if ($signature_valid === false) {
     466                write_log('ERROR: Signature is not valid');
    393467                wp_send_json(PSQR::RESPONSES['invalid_jws'], 401);
    394468            }
     
    400474            $valid_resp = $this->validate_identity($newDid);
    401475            if ($valid_resp['valid'] === false) {
     476                write_log('ERROR: DID from JWS is not valid');
    402477                wp_send_json([
    403478                    'code'    => 'did_invalid',
     
    411486            $response = $this->store_identity($path, $newDid);
    412487            if ($response === false) {
     488                write_log('ERROR: there was an issue storing the DID for ' . $path);
    413489                wp_send_json(PSQR::RESPONSES['did_error'], 400);
    414490            }
    415491
     492            write_log('INFO: update successful');
    416493            wp_send_json($newDid, 200);
    417494        }
     
    419496        public function delete_did(string $path, string $body)
    420497        {
     498            write_log('INFO: deleting DID with path ' . $path);
    421499            $signature_valid = $this->validate_update($path, $body);
    422500
    423501            if ($signature_valid === false) {
     502                write_log('ERROR: Signature is not valid');
    424503                wp_send_json(PSQR::RESPONSES['invalid_jws'], 401);
    425504            }
     
    427506            $response = $this->delete_identity($path);
    428507            if ($response === false) {
     508                write_log('ERROR: there was an error deleting the DID for ' . $path);
    429509                wp_send_json(PSQR::RESPONSES['did_error'], 400);
    430510            }
    431511
     512            write_log('INFO: delete successful');
    432513            wp_send_json([
    433514                'code'    => 'did_deleted',
     
    441522
    442523            return $did;
     524        }
     525
     526        function add_ext_warning(string $plugin_file) {
     527            // add notice if necessary
     528            if ($plugin_file === 'psqr/psqr.php' && count($this->ext_missing) !== 0) {
     529                echo '<div class="notice notice-warning">
     530                        <p><strong>Virtual Public Square</strong></p>
     531                        <p>You are missing some required php extensions to manage DIDs. Please install the following: ' . implode(", ", $this->ext_missing) . '</p>
     532                    </div>';
     533            }
    443534        }
    444535
  • virtual-public-square/trunk/readme.txt

    r2737145 r2737154  
    44Requires at least: 5.4
    55Tested up to: 5.9
    6 Requires PHP: 7.0
    7 Stable tag: 0.1.1
     6Requires PHP: 7.4
     7Stable tag: 0.1.2
    88License: GPLv2
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
     
    2121
    2222The primary use of Virtual Public Square technology is to acquire content from specified publishers without third party interference. This will often appear in the format of a news feed. The first commercial use of Virtual Public Square data is to populate widgets on websites containing curated content from a set of publishers that seek to cross-promote each other to keep readers engaged and maximize audience attention.
     23
     24== Required PHP Extensions ==
     25
     26The following PHP extensions are required to update and delete DIDs with an API call:
     27
     28* json
     29* mbstring
     30* openssl
    2331
    2432== Frequently Asked Questions ==
     
    7482== Changelog ==
    7583
     84= 0.1.2 =
     85* Update token format to {token: JWSstring}
     86* Add checks for required php extensions
     87* Add debug logs
     88
    7689= 0.1.1 =
    77 * Update, delete DID with http PUT; revised DID document in request body
     90* Add ability to update DIDs with PUT request and delete DIDs with DELETE
    7891
    7992= 0.1.0 =
    8093* Initial release
    81 
Note: See TracChangeset for help on using the changeset viewer.