1
1
import {
2
- strToHex ,
3
- decodeHex ,
4
- datetimeToRippleTime ,
5
- rippleTimeToDatetime ,
6
- } from "./utils.js" ;
7
-
8
- import { isValidClassicAddress } from "xrpl" ;
2
+ isoTimeToRippleTime ,
3
+ rippleTimeToISOTime ,
4
+ isValidClassicAddress ,
5
+ } from "xrpl" ;
6
+ import { stringToHex } from "@xrplf/isomorphic/dist/utils/index.js" ;
9
7
8
+ import { decodeHex } from "./decode_hex.js" ;
10
9
import { ValueError } from "./errors.js" ;
11
10
12
11
// Regex constants
@@ -15,7 +14,6 @@ const URI_REGEX = /^[A-Za-z0-9\-._~:/?#\[\]@!$&'()*+,;=%]{1,256}$/;
15
14
16
15
/**
17
16
* Validate credential request.
18
- *
19
17
* This function performs parameter validation. Validated fields:
20
18
* - subject (required): the subject of the credential, as a classic address
21
19
* - credential (required): the credential type, in human-readable (ASCII) chars
@@ -35,19 +33,16 @@ export function validateCredentialRequest({ subject, credential, uri, expiration
35
33
if ( typeof credential !== "string" ) {
36
34
throw new ValueError ( "Must provide a string 'credential' field" ) ;
37
35
}
38
-
39
- /*
40
- Checks if the specified credential type is one that this service issues.
41
-
42
- XRPL credential types can be any binary data; this service issues
43
- any credential that can be encoded from the following ASCII chars:
44
- alphanumeric characters, underscore, period, and dash.
45
- (min length 1, max 64)
46
-
47
- You might want to further limit the credential types, depending on your
48
- use case; for example, you might only issue one specific credential type.
49
- */
50
36
if ( ! CREDENTIAL_REGEX . test ( credential ) ) {
37
+ /**
38
+ * Checks if the specified credential type is one that this service issues.
39
+ * XRPL credential types can be any binary data; this service issues
40
+ * any credential that can be encoded from the following ASCII chars:
41
+ * alphanumeric characters, underscore, period, and dash. (min length 1, max 64)
42
+ *
43
+ * You might want to further limit the credential types, depending on your
44
+ * use case; for example, you might only issue one specific credential type.
45
+ */
51
46
throw new ValueError ( `credential not allowed: '${ credential } '.` ) ;
52
47
}
53
48
@@ -76,12 +71,10 @@ export function validateCredentialRequest({ subject, credential, uri, expiration
76
71
// Validate and parse expiration
77
72
let parsedExpiration ;
78
73
if ( expiration !== undefined ) {
79
- if ( typeof expiration === "string" ) {
80
- parsedExpiration = new Date ( expiration ) ;
81
- } else {
74
+ if ( typeof expiration !== "string" ) {
82
75
throw new ValueError ( `Unsupported expiration format: ${ typeof expiration } ` ) ;
83
76
}
84
-
77
+ parsedExpiration = new Date ( expiration ) ;
85
78
if ( isNaN ( parsedExpiration . getTime ( ) ) ) {
86
79
throw new ValueError ( `Invalid expiration date: ${ expiration } ` ) ;
87
80
}
@@ -95,20 +88,41 @@ export function validateCredentialRequest({ subject, credential, uri, expiration
95
88
} ;
96
89
}
97
90
98
- /**
99
- * As a credential issuer, you typically need to verify some information
100
- * about someone before you issue them a credential. For this example,
101
- * the user passes relevant information in a documents field of the API request.
102
- * The documents are kept confidential, off-chain.
103
- */
104
- export function verifyDocuments ( { documents} ) {
105
- /*
106
- This is where you would check the user's documents to see if you
107
- should issue the requested Credential to them.
108
- Depending on the type of credentials your service needs, you might
109
- need to implement different types of checks here.
91
+ // Convert an XRPL ledger entry into a usable credential object
92
+ export function credentialFromXrpl ( entry ) {
93
+ const { Subject, CredentialType, URI , Expiration, Flags } = entry ;
94
+ return {
95
+ subject : Subject ,
96
+ credential : decodeHex ( CredentialType ) ,
97
+ uri : URI ? decodeHex ( URI ) : undefined ,
98
+ expiration : Expiration ? rippleTimeToISOTime ( Expiration ) : undefined ,
99
+ accepted : Boolean ( Flags & 0x00010000 ) , // lsfAccepted
100
+ } ;
101
+ }
102
+
103
+ // Convert to an object in a format closer to the XRP Ledger representation
104
+ export function credentialToXrpl ( cred ) {
105
+ // Credential type and URI are hexadecimal;
106
+ // Expiration, if present, is in seconds since the Ripple Epoch.
107
+ return {
108
+ subject : cred . subject ,
109
+ credential : stringToHex ( cred . credential ) ,
110
+ uri : cred . uri ? stringToHex ( cred . uri ) : undefined ,
111
+ expiration : cred . expiration
112
+ ? isoTimeToRippleTime ( cred . expiration )
113
+ : undefined ,
114
+ } ;
115
+ }
116
+
117
+
118
+ export function verifyDocuments ( { documents } ) {
119
+ /**
120
+ * This is where you would check the user's documents to see if you
121
+ * should issue the requested Credential to them.
122
+ * Depending on the type of credentials your service needs, you might
123
+ * need to implement different types of checks here.
110
124
*/
111
- if ( typeof documents !== ' object' || Object . keys ( documents ) . length === 0 ) {
125
+ if ( typeof documents !== " object" || Object . keys ( documents ) . length === 0 ) {
112
126
throw new ValueError ( "you must provide a non-empty 'documents' field" ) ;
113
127
}
114
128
@@ -123,50 +137,3 @@ export function verifyDocuments({documents}) {
123
137
throw new ValueError ( "reason must include 'please'" ) ;
124
138
}
125
139
}
126
-
127
- /**
128
- * Convert to a Credential object in a format closer to the XRP Ledger representation.
129
- * Credential type and URI are hexadecimal;
130
- * Expiration, if present, is in seconds since the Ripple Epoch.
131
- */
132
- export function credentialToXrpl ( cred ) {
133
- return {
134
- subject : cred . subject ,
135
- credential : strToHex ( cred . credential ) ,
136
- uri : cred . uri ? strToHex ( cred . uri ) : undefined ,
137
- expiration : cred . expiration ? datetimeToRippleTime ( cred . expiration ) : undefined ,
138
- } ;
139
- }
140
-
141
- // Convert an XRPL ledger entry into a usable credential object
142
- export function parseCredentialFromXrpl ( entry ) {
143
- const { Subject, CredentialType, URI , Expiration, Flags } = entry ;
144
-
145
- if ( ! Subject || ! CredentialType ) {
146
- throw new Error ( "Missing required fields from XRPL credential entry" ) ;
147
- }
148
-
149
- return {
150
- subject : Subject ,
151
- credential : decodeHex ( CredentialType ) ,
152
- uri : URI ? decodeHex ( URI ) : undefined ,
153
- expiration : Expiration ? rippleTimeToDatetime ( Expiration ) : undefined ,
154
- accepted : Boolean ( Flags & 0x00010000 ) , // lsfAccepted
155
- } ;
156
- }
157
-
158
- /**
159
- * Convert a credential object into API-friendly JSON
160
- */
161
- export function serializeCredential ( cred ) {
162
- const result = {
163
- subject : cred . subject ,
164
- credential : cred . credential ,
165
- } ;
166
-
167
- if ( cred . uri ) result . uri = cred . uri ;
168
- if ( cred . expiration ) result . expiration = cred . expiration . toISOString ( ) ;
169
- if ( cred . accepted !== undefined ) result . accepted = cred . accepted ;
170
-
171
- return result ;
172
- }
0 commit comments