crypto = $crypto; } /** * All connections, oldest first. * * @return Connection[] */ public function all() { $rows = get_option( self::OPTION, array() ); $out = array(); foreach ( is_array( $rows ) ? $rows : array() as $row ) { if ( is_array( $row ) && ! empty( $row['id'] ) ) { $out[ $row['id'] ] = Connection::from_array( $row ); } } return $out; } /** * Finds a connection by ID. * * @param string $id Connection ID. * @return Connection|null */ public function find( $id ) { $all = $this->all(); return isset( $all[ $id ] ) ? $all[ $id ] : null; } /** * Inserts or updates a connection. Assigns an ID to new connections. * * @param Connection $connection Connection to save. * @return Connection */ public function save( Connection $connection ) { OptionUpdate::change( self::OPTION, function ( array $rows ) use ( $connection ) { if ( '' === $connection->id ) { $connection->id = $this->new_id( $rows ); $connection->created = time(); } $rows[ $connection->id ] = $connection->to_array(); return $rows; } ); return $connection; } /** * Deletes a connection and its secrets. * * @param string $id Connection ID. * @return void */ public function delete( $id ) { OptionUpdate::change( self::OPTION, static function ( array $rows ) use ( $id ) { unset( $rows[ $id ] ); return $rows; } ); OptionUpdate::change( self::SECRETS_OPTION, static function ( array $secrets ) use ( $id ) { unset( $secrets[ $id ] ); return $secrets; } ); } /** * Reads and decrypts a secret. * * @param string $id Connection ID. * @param string $name Secret name, one of the SECRET_* constants. * @return string Empty string when not set or unreadable. */ public function secret( $id, $name ) { $secrets = $this->secrets(); return isset( $secrets[ $id ][ $name ] ) ? $this->crypto->decrypt( $secrets[ $id ][ $name ] ) : ''; } /** * Encrypts and stores a secret. Pass null to remove it. * * @param string $id Connection ID. * @param string $name Secret name. * @param string|null $value Secret value. * @return void */ public function set_secret( $id, $name, $value ) { $encrypted = null === $value || '' === $value ? null : $this->crypto->encrypt( $value ); OptionUpdate::change( self::SECRETS_OPTION, static function ( array $secrets ) use ( $id, $name, $encrypted ) { if ( null === $encrypted ) { unset( $secrets[ $id ][ $name ] ); } else { $secrets[ $id ][ $name ] = $encrypted; } return $secrets; } ); } /** * Raw secrets option. * * @return array */ private function secrets() { $secrets = get_option( self::SECRETS_OPTION, array() ); return is_array( $secrets ) ? $secrets : array(); } /** * Generates a unique, URL-safe ID. * * @param array $existing Existing rows keyed by ID. * @return string */ private function new_id( array $existing ) { do { $id = 'c' . strtolower( wp_generate_password( 9, false ) ); } while ( isset( $existing[ $id ] ) ); return $id; } }