mirror of
https://github.com/XRPLF/xrpl-dev-portal.git
synced 2025-11-21 20:25:51 +00:00
Add tutorial documentation
This commit is contained in:
@@ -1,12 +1,11 @@
|
||||
import {
|
||||
strToHex,
|
||||
decodeHex,
|
||||
datetimeToRippleTime,
|
||||
rippleTimeToDatetime,
|
||||
} from "./utils.js";
|
||||
|
||||
import { isValidClassicAddress } from "xrpl";
|
||||
isoTimeToRippleTime,
|
||||
rippleTimeToISOTime,
|
||||
isValidClassicAddress,
|
||||
} from "xrpl";
|
||||
import { stringToHex } from "@xrplf/isomorphic/dist/utils/index.js";
|
||||
|
||||
import { decodeHex } from "./decode_hex.js";
|
||||
import { ValueError } from "./errors.js";
|
||||
|
||||
// Regex constants
|
||||
@@ -15,7 +14,6 @@ const URI_REGEX = /^[A-Za-z0-9\-._~:/?#\[\]@!$&'()*+,;=%]{1,256}$/;
|
||||
|
||||
/**
|
||||
* Validate credential request.
|
||||
*
|
||||
* This function performs parameter validation. Validated fields:
|
||||
* - subject (required): the subject of the credential, as a classic address
|
||||
* - credential (required): the credential type, in human-readable (ASCII) chars
|
||||
@@ -35,19 +33,16 @@ export function validateCredentialRequest({ subject, credential, uri, expiration
|
||||
if (typeof credential !== "string") {
|
||||
throw new ValueError("Must provide a string 'credential' field");
|
||||
}
|
||||
|
||||
/*
|
||||
Checks if the specified credential type is one that this service issues.
|
||||
|
||||
XRPL credential types can be any binary data; this service issues
|
||||
any credential that can be encoded from the following ASCII chars:
|
||||
alphanumeric characters, underscore, period, and dash.
|
||||
(min length 1, max 64)
|
||||
|
||||
You might want to further limit the credential types, depending on your
|
||||
use case; for example, you might only issue one specific credential type.
|
||||
*/
|
||||
if (!CREDENTIAL_REGEX.test(credential)) {
|
||||
/**
|
||||
* Checks if the specified credential type is one that this service issues.
|
||||
* XRPL credential types can be any binary data; this service issues
|
||||
* any credential that can be encoded from the following ASCII chars:
|
||||
* alphanumeric characters, underscore, period, and dash. (min length 1, max 64)
|
||||
*
|
||||
* You might want to further limit the credential types, depending on your
|
||||
* use case; for example, you might only issue one specific credential type.
|
||||
*/
|
||||
throw new ValueError(`credential not allowed: '${credential}'.`);
|
||||
}
|
||||
|
||||
@@ -76,12 +71,10 @@ export function validateCredentialRequest({ subject, credential, uri, expiration
|
||||
// Validate and parse expiration
|
||||
let parsedExpiration;
|
||||
if (expiration !== undefined) {
|
||||
if (typeof expiration === "string") {
|
||||
parsedExpiration = new Date(expiration);
|
||||
} else {
|
||||
if (typeof expiration !== "string") {
|
||||
throw new ValueError(`Unsupported expiration format: ${typeof expiration}`);
|
||||
}
|
||||
|
||||
parsedExpiration = new Date(expiration);
|
||||
if (isNaN(parsedExpiration.getTime())) {
|
||||
throw new ValueError(`Invalid expiration date: ${expiration}`);
|
||||
}
|
||||
@@ -95,20 +88,41 @@ export function validateCredentialRequest({ subject, credential, uri, expiration
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* As a credential issuer, you typically need to verify some information
|
||||
* about someone before you issue them a credential. For this example,
|
||||
* the user passes relevant information in a documents field of the API request.
|
||||
* The documents are kept confidential, off-chain.
|
||||
*/
|
||||
export function verifyDocuments({documents}) {
|
||||
/*
|
||||
This is where you would check the user's documents to see if you
|
||||
should issue the requested Credential to them.
|
||||
Depending on the type of credentials your service needs, you might
|
||||
need to implement different types of checks here.
|
||||
// Convert an XRPL ledger entry into a usable credential object
|
||||
export function credentialFromXrpl(entry) {
|
||||
const { Subject, CredentialType, URI, Expiration, Flags } = entry;
|
||||
return {
|
||||
subject: Subject,
|
||||
credential: decodeHex(CredentialType),
|
||||
uri: URI ? decodeHex(URI) : undefined,
|
||||
expiration: Expiration ? rippleTimeToISOTime(Expiration) : undefined,
|
||||
accepted: Boolean(Flags & 0x00010000), // lsfAccepted
|
||||
};
|
||||
}
|
||||
|
||||
// Convert to an object in a format closer to the XRP Ledger representation
|
||||
export function credentialToXrpl(cred) {
|
||||
// Credential type and URI are hexadecimal;
|
||||
// Expiration, if present, is in seconds since the Ripple Epoch.
|
||||
return {
|
||||
subject: cred.subject,
|
||||
credential: stringToHex(cred.credential),
|
||||
uri: cred.uri ? stringToHex(cred.uri) : undefined,
|
||||
expiration: cred.expiration
|
||||
? isoTimeToRippleTime(cred.expiration)
|
||||
: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export function verifyDocuments({ documents }) {
|
||||
/**
|
||||
* This is where you would check the user's documents to see if you
|
||||
* should issue the requested Credential to them.
|
||||
* Depending on the type of credentials your service needs, you might
|
||||
* need to implement different types of checks here.
|
||||
*/
|
||||
if (typeof documents !== 'object' || Object.keys(documents).length === 0) {
|
||||
if (typeof documents !== "object" || Object.keys(documents).length === 0) {
|
||||
throw new ValueError("you must provide a non-empty 'documents' field");
|
||||
}
|
||||
|
||||
@@ -123,50 +137,3 @@ export function verifyDocuments({documents}) {
|
||||
throw new ValueError("reason must include 'please'");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert to a Credential object in a format closer to the XRP Ledger representation.
|
||||
* Credential type and URI are hexadecimal;
|
||||
* Expiration, if present, is in seconds since the Ripple Epoch.
|
||||
*/
|
||||
export function credentialToXrpl(cred) {
|
||||
return {
|
||||
subject: cred.subject,
|
||||
credential: strToHex(cred.credential),
|
||||
uri: cred.uri ? strToHex(cred.uri) : undefined,
|
||||
expiration: cred.expiration ? datetimeToRippleTime(cred.expiration) : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
// Convert an XRPL ledger entry into a usable credential object
|
||||
export function parseCredentialFromXrpl(entry) {
|
||||
const { Subject, CredentialType, URI, Expiration, Flags } = entry;
|
||||
|
||||
if (!Subject || !CredentialType) {
|
||||
throw new Error("Missing required fields from XRPL credential entry");
|
||||
}
|
||||
|
||||
return {
|
||||
subject: Subject,
|
||||
credential: decodeHex(CredentialType),
|
||||
uri: URI ? decodeHex(URI) : undefined,
|
||||
expiration: Expiration ? rippleTimeToDatetime(Expiration) : undefined,
|
||||
accepted: Boolean(Flags & 0x00010000), // lsfAccepted
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a credential object into API-friendly JSON
|
||||
*/
|
||||
export function serializeCredential(cred) {
|
||||
const result = {
|
||||
subject: cred.subject,
|
||||
credential: cred.credential,
|
||||
};
|
||||
|
||||
if (cred.uri) result.uri = cred.uri;
|
||||
if (cred.expiration) result.expiration = cred.expiration.toISOString();
|
||||
if (cred.accepted !== undefined) result.accepted = cred.accepted;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user