@herberthtk/yo-payments-api 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/LICENSE +21 -0
- package/README.md +236 -0
- package/certs/Yo_Uganda_Public_Certificate.crt +28 -0
- package/certs/Yo_Uganda_Public_Sandbox_Certificate.crt +35 -0
- package/dist/index.cjs +857 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +391 -0
- package/dist/index.d.ts +391 -0
- package/dist/index.js +828 -0
- package/dist/index.js.map +1 -0
- package/package.json +80 -0
package/CHANGELOG.md
ADDED
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 herberthtk
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
# @herberthtk/yo-payments-api
|
|
2
|
+
|
|
3
|
+
TypeScript client for the [Yo! Payments API PHP library](https://github.com/YO-Uganda) (`YoAPI.php`) for mobile money, airtime and account operations on the Yo! Payments gateway. Runs on [Bun](https://bun.com) and Node.js 18+ (uses `fetch` + `node:crypto`), including Next.js App Router handlers, Server Actions and Server Components (**server-side only** — never import it into a Client Component).
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @herberthtk/yo-payments-api
|
|
9
|
+
# or: bun add @herberthtk/yo-payments-api
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import { YoAPI } from "@herberthtk/yo-payments-api";
|
|
16
|
+
|
|
17
|
+
// production by default; pass "sandbox" as the third argument for sandbox mode
|
|
18
|
+
const yoAPI = new YoAPI("API_USERNAME", "API_PASSWORD");
|
|
19
|
+
|
|
20
|
+
// Request a mobile money user to deposit funds into your account
|
|
21
|
+
const response = await yoAPI.acDepositFunds("256770000000", 10000, "Reason for transfer of funds");
|
|
22
|
+
if (response.Status === "OK") {
|
|
23
|
+
console.log("Transaction Reference =", response.TransactionReference);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Check the balance of your account
|
|
27
|
+
const balance = await yoAPI.acAcctBalance();
|
|
28
|
+
console.log(balance.balance); // [{ code: "UGX", balance: "50000" }, ...]
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
All network methods are `async` and return typed response objects. Method names use idiomatic camelCase (e.g. `acDepositFunds`, `setExternalReference`, `getTransactionLimitAccountIdentifier`) — the one intentional divergence from the PHP library's `snake_case` names; the XML wire format is unchanged.
|
|
32
|
+
|
|
33
|
+
### Available operations
|
|
34
|
+
|
|
35
|
+
- `acDepositFunds(msisdn, amount, narrative)`
|
|
36
|
+
- `acTransactionCheckStatus(transactionReference, privateTransactionReference?)`
|
|
37
|
+
- `acInternalTransfer(currencyCode, amount, beneficiaryAccount, beneficiaryEmail, narrative)`
|
|
38
|
+
- `acAcctBalance()`
|
|
39
|
+
- `acGetMinistatement(startDate?, endDate?, transactionStatus?, currencyCode?, resultSetLimit?, transactionEntryDesignation?, externalReference?)`
|
|
40
|
+
- `acSendAirtimeMobile(msisdn, amount, narrative)`
|
|
41
|
+
- `acSendAirtimeInternal(currencyCode, amount, beneficiaryAccount, beneficiaryEmail, narrative)`
|
|
42
|
+
- `acWithdrawFunds(msisdn, amount, narrative)`
|
|
43
|
+
- `acUserPurchaseAirtimestock(airtimeCurrencyCode, amount)`
|
|
44
|
+
- `acGetMsisdnKycInfo(msisdn)`
|
|
45
|
+
- `generatePublicKeyAuthenticationSignature(msisdn, amount, narrative)`
|
|
46
|
+
|
|
47
|
+
### Receiving payment notifications (IPN)
|
|
48
|
+
|
|
49
|
+
PHP reads `$_POST` / `php://input` globals, which is impossible in TypeScript, so you pass the parsed form body yourself. Point `setUrl`-style config is not affected; use `setPublicKeyFileUrl` if you need a different certificate (sandbox vs production is picked automatically by the constructor `mode`).
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
// Bun HTTP server example
|
|
53
|
+
Bun.serve({
|
|
54
|
+
port: 3000,
|
|
55
|
+
async fetch(req) {
|
|
56
|
+
const form = await req.formData();
|
|
57
|
+
const body = Object.fromEntries(form.entries()) as any;
|
|
58
|
+
|
|
59
|
+
const yoAPI = new YoAPI("API_USERNAME", "API_PASSWORD", "sandbox");
|
|
60
|
+
const payment = yoAPI.receivePaymentNotification(body);
|
|
61
|
+
if (payment.is_verified) {
|
|
62
|
+
console.log(`Payment from ${payment.msisdn} of ${payment.amount} (ref ${payment.external_ref})`);
|
|
63
|
+
// update your transaction status where external_ref = payment.external_ref
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Failure notifications:
|
|
67
|
+
// const failure = yoAPI.receivePaymentFailureNotification(body);
|
|
68
|
+
return new Response("OK");
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Public key authentication (payouts)
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
const yoAPI = new YoAPI("API_USERNAME", "API_PASSWORD");
|
|
77
|
+
yoAPI.setExternalReference("INV-123");
|
|
78
|
+
yoAPI.setPublicKeyAuthenticationNonce(crypto.randomUUID());
|
|
79
|
+
yoAPI.setPrivateKeyFileLocation("/path/to/your-private-key.pem");
|
|
80
|
+
yoAPI.generatePublicKeyAuthenticationSignature("256770000000", 5000, "Salary payout");
|
|
81
|
+
const res = await yoAPI.acWithdrawFunds("256770000000", 5000, "Salary payout");
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Usage in Next.js (App Router)
|
|
85
|
+
|
|
86
|
+
The library is **server-only**: it uses `node:crypto`/`node:fs` and handles API secrets. Add `import "server-only"` (`npm i server-only`) at the top of every file that touches it, keep credentials in server-side env vars (never `NEXT_PUBLIC_*`), and pin `export const runtime = "nodejs"` on route handlers. Ready-to-copy handlers live in `examples/nextjs/`:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
npm install @herberthtk/yo-payments-api server-only
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
// lib/yo.ts
|
|
94
|
+
import "server-only";
|
|
95
|
+
import { YoAPI } from "@herberthtk/yo-payments-api";
|
|
96
|
+
|
|
97
|
+
export function getYoClient() {
|
|
98
|
+
return new YoAPI(process.env.YO_API_USERNAME!, process.env.YO_API_PASSWORD!, "sandbox");
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
// app/api/yo/ipn/route.ts — register this URL as your InstantNotificationUrl
|
|
104
|
+
import "server-only";
|
|
105
|
+
import { getYoClient } from "@/lib/yo";
|
|
106
|
+
|
|
107
|
+
export const runtime = "nodejs";
|
|
108
|
+
export const dynamic = "force-dynamic";
|
|
109
|
+
|
|
110
|
+
export async function POST(req: Request) {
|
|
111
|
+
const form = await req.formData();
|
|
112
|
+
const body: Record<string, string> = {};
|
|
113
|
+
for (const [k, v] of form.entries()) if (typeof v === "string") body[k] = v;
|
|
114
|
+
|
|
115
|
+
const payment = getYoClient().receivePaymentNotification({
|
|
116
|
+
date_time: body.date_time ?? "",
|
|
117
|
+
amount: body.amount ?? "",
|
|
118
|
+
narrative: body.narrative ?? "",
|
|
119
|
+
network_ref: body.network_ref ?? "",
|
|
120
|
+
external_ref: body.external_ref ?? "",
|
|
121
|
+
msisdn: body.msisdn ?? "",
|
|
122
|
+
signature: body.signature ?? "",
|
|
123
|
+
});
|
|
124
|
+
if (!payment.is_verified) return new Response("NOT VERIFIED", { status: 400 });
|
|
125
|
+
|
|
126
|
+
// TODO: persist + mark processed idempotently on payment.external_ref
|
|
127
|
+
return new Response("OK");
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
// app/actions.ts — deposits from a Client Component form action
|
|
133
|
+
"use server";
|
|
134
|
+
import { getYoClient } from "@/lib/yo";
|
|
135
|
+
|
|
136
|
+
export async function requestDeposit(msisdn: string, amount: number, narrative: string) {
|
|
137
|
+
const api = getYoClient();
|
|
138
|
+
api.setExternalReference(`${Date.now()}`);
|
|
139
|
+
const res = await api.acDepositFunds(msisdn, amount, narrative);
|
|
140
|
+
if (res.Status === "OK") return { ok: true, reference: res.TransactionReference };
|
|
141
|
+
return { ok: false, message: res.StatusMessage };
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
```tsx
|
|
146
|
+
// app/statement/page.tsx — Server Component (all reads return JSON-safe data)
|
|
147
|
+
import { getYoClient } from "@/lib/yo";
|
|
148
|
+
|
|
149
|
+
export default async function StatementPage() {
|
|
150
|
+
const res = await getYoClient().acGetMinistatement(null, null, "SUCCEEDED", "UGX-MTNMM", 0);
|
|
151
|
+
return <pre>{JSON.stringify(res.Transactions, null, 2)}</pre>;
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Feature map: deposits/status checks → Server Actions (`examples/nextjs/lib/actions.ts`); balances/ministatements/KYC → Server Components or actions (`examples/nextjs/lib/queries.ts`); IPN + failure notices → Route Handlers (`examples/nextjs/app/api/yo/...`); payouts → Server Actions with `setPrivateKeyContent(process.env.YO_PRIVATE_KEY!.replace(/\\n/g, "\n"))` since serverless hosts have no key files. See `examples/nextjs/` for every operation, covered by `tests/nextjs.test.ts`.
|
|
156
|
+
|
|
157
|
+
### Error handling
|
|
158
|
+
|
|
159
|
+
Transport-level and protocol-level failures throw `YoAPIError` (an `Error` subclass):
|
|
160
|
+
|
|
161
|
+
```ts
|
|
162
|
+
import { YoAPI, YoAPIError } from "@herberthtk/yo-payments-api";
|
|
163
|
+
|
|
164
|
+
try {
|
|
165
|
+
await yoAPI.acAcctBalance();
|
|
166
|
+
} catch (e) {
|
|
167
|
+
if (e instanceof YoAPIError) {
|
|
168
|
+
console.error(e.message, "status:", e.status, "cause:", e.cause);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
`YoAPIError` is thrown for connection errors, timeouts, non-2xx HTTP statuses, oversized bodies, malformed XML and responses missing the `<Response>` node. Gateway-level business failures (e.g. `Status: "FAILED"`) are still returned as normal response objects, exactly like the PHP library.
|
|
174
|
+
|
|
175
|
+
### Examples
|
|
176
|
+
|
|
177
|
+
The `examples/` directory ports all six PHP examples; each exports testable functions and is runnable with `bun run`:
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
YO_API_USERNAME=... YO_API_PASSWORD=... YO_API_MODE=sandbox bun run examples/deposit_funds.ts
|
|
181
|
+
YO_API_USERNAME=... YO_API_PASSWORD=... YO_API_MODE=sandbox bun run examples/deposit_funds_nonblocking.ts
|
|
182
|
+
YO_API_USERNAME=... YO_API_PASSWORD=... YO_API_MODE=sandbox bun run examples/get_ministatement.ts
|
|
183
|
+
YO_API_USERNAME=... YO_API_PASSWORD=... YO_API_MODE=sandbox \
|
|
184
|
+
YO_PRIVATE_KEY_FILE=/path/to/private-key.pem \
|
|
185
|
+
bun run examples/withdraw_funds_public_key_authentication.ts
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
`examples/receive_payment_notification.ts` and `examples/receive_payment_failure_notification.ts` export `handlePaymentNotification` / `handlePaymentFailureNotification` for wiring into your HTTP server. All examples are covered by `tests/examples.test.ts`.
|
|
189
|
+
|
|
190
|
+
## Notes on parity with the PHP library
|
|
191
|
+
|
|
192
|
+
- Request XML element order and optional-element inclusion rules match the PHP library exactly (values are inserted verbatim — escape special XML characters yourself, as with the PHP version). Empty-string and `"0"` response fields follow PHP's `empty()` semantics.
|
|
193
|
+
- `acUserPurchaseAirtimestock` sends `external_reference` inside a `<TransactionReference>` tag, exactly like the PHP code.
|
|
194
|
+
- The PHP library's private `deposit_transaction_type` (used by `acTransactionCheckStatus`) has no setter in PHP and is stuck on `"PULL"`; this port adds `setDepositTransactionType` / `getDepositTransactionType` so `"PUSH"` is usable.
|
|
195
|
+
- A `ResultSetLimit` of `0` is sent to the gateway (returns all, per gateway docs). The PHP example passes `0` but its `!= NULL` check silently drops it; this port sends it.
|
|
196
|
+
- Timeouts default to 120 s (`setTimeout` / `getTimeout` can change it); a timeout `<= 0` disables the timeout, mirroring PHP curl semantics.
|
|
197
|
+
- **TLS verification differs from PHP on purpose:** the PHP library disables peer verification, but this port verifies the gateway certificate by default. Opt out only for testing via `setTlsVerificationEnabled(false)` (on Node.js this additionally requires `NODE_TLS_REJECT_UNAUTHORIZED=0`).
|
|
198
|
+
- Response bodies are capped (`setMaxResponseBytes` / `getMaxResponseBytes`, default 1 MiB) and malformed/non-XML responses throw `YoAPIError` instead of degrading to empty results.
|
|
199
|
+
- Pass money amounts as strings when exact formatting matters; numbers use JavaScript float-to-string conversion.
|
|
200
|
+
- One `YoAPI` instance holds per-request state (`externalReference`, ...), so don't share an instance across concurrent requests — create one per request.
|
|
201
|
+
- The Yo! Uganda public certificates (`certs/*.crt`, copied from the PHP package) verify IPN signatures, with embedded copies as fallback when the files can't be resolved (bundled servers, CJS builds). Override with `setPublicKeyFileUrl`. Verification is fail-closed (`is_verified: false`) when the certificate is missing or invalid — monitor this, and handle IPNs idempotently on `external_ref` since notifications carry no replay protection.
|
|
202
|
+
- `setPrivateKeyContent` accepts the signing key as PEM text (takes precedence over the file location) for hosts without a stable filesystem; on serverless, load it from an env var and unescape newlines.
|
|
203
|
+
|
|
204
|
+
## Develop
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
bun install
|
|
208
|
+
bun test # mock gateway server + generated RSA keys; no real API calls
|
|
209
|
+
bun run typecheck # tsc --noEmit
|
|
210
|
+
bun run build # tsup → dist/ (ESM + CJS + .d.ts); regenerates src/embeddedCerts.ts first
|
|
211
|
+
bunx attw --pack # validate the packed types
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
The suite (`tests/YoAPI.test.ts`, `tests/examples.test.ts`, `tests/keys.test.ts`, `tests/nextjs.test.ts`) asserts byte-exact request XML for every operation, response parsing, signature round-trips, key/cert handling and all examples. `tsc --noEmit` must also pass.
|
|
215
|
+
|
|
216
|
+
### Releasing (maintainers)
|
|
217
|
+
|
|
218
|
+
Versions follow [Conventional Commits](https://www.conventionalcommits.org/) (`feat:` → minor, `fix:` → patch, `feat!:`/`BREAKING CHANGE:` → major). To cut a release, run **Actions → Release → Run workflow** — release-it bumps the version, updates `CHANGELOG.md`, tags, creates the GitHub release and publishes to npm via trusted publishing (no npm token needed). First-time setup only: `npm login` + one manual `npm publish --access public`, then register the repo as a trusted publisher in the npm package settings.
|
|
219
|
+
|
|
220
|
+
## Project structure
|
|
221
|
+
|
|
222
|
+
- `src/YoAPI.ts` — the `YoAPI` client class (public API: config, operations, notifications, signing)
|
|
223
|
+
- `src/types.ts` — public response/body TypeScript interfaces
|
|
224
|
+
- `src/errors.ts` — `YoAPIError`
|
|
225
|
+
- `src/xml.ts` — request building, response parsing and PHP-parity mapping helpers
|
|
226
|
+
- `src/http.ts` — gateway POST transport (timeout, TLS, size cap, error mapping)
|
|
227
|
+
- `src/keys.ts` — cached verification-key loading (file-first, embedded fallback)
|
|
228
|
+
- `src/constants.ts` — gateway URLs, certificate names, defaults
|
|
229
|
+
- `src/embeddedCerts.ts` — auto-generated from `certs/` (`bun run embed-certs`)
|
|
230
|
+
- `examples/` — runnable ports of the six PHP examples
|
|
231
|
+
- `examples/nextjs/` — Next.js App Router handlers, Server Actions and queries
|
|
232
|
+
- `certs/` — Yo! Uganda public certificates for IPN verification
|
|
233
|
+
- `.github/workflows/` — `ci.yml` (test/typecheck/build/pack-check) and `release.yml` (release-it via trusted publishing)
|
|
234
|
+
- `scripts/embed-certs.ts` — regenerates `src/embeddedCerts.ts`
|
|
235
|
+
|
|
236
|
+
This project was created using `bun init` in bun v1.4.0. [Bun](https://bun.com) is a fast all-in-one JavaScript runtime.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
|
2
|
+
MIIEvTCCA6WgAwIBAgIJAN3e7VqDg5zQMA0GCSqGSIb3DQEBBQUAMIGaMQswCQYD
|
|
3
|
+
VQQGEwJVRzEQMA4GA1UECBMHS2FtcGFsYTEQMA4GA1UEBxMHS2FtcGFsYTEbMBkG
|
|
4
|
+
A1UECgwSWW8hIFVnYW5kYSBMaW1pdGVkMRUwEwYDVQQLDAxZbyEgUGF5bWVudHMx
|
|
5
|
+
FTATBgNVBAMTDHd3dy55by5jby51ZzEcMBoGCSqGSIb3DQEJARYNaW5mb0B5by5j
|
|
6
|
+
by51ZzAeFw0xMzA4MDkwNTQyMTRaFw0yMzA4MDcwNTQyMTRaMIGaMQswCQYDVQQG
|
|
7
|
+
EwJVRzEQMA4GA1UECBMHS2FtcGFsYTEQMA4GA1UEBxMHS2FtcGFsYTEbMBkGA1UE
|
|
8
|
+
CgwSWW8hIFVnYW5kYSBMaW1pdGVkMRUwEwYDVQQLDAxZbyEgUGF5bWVudHMxFTAT
|
|
9
|
+
BgNVBAMTDHd3dy55by5jby51ZzEcMBoGCSqGSIb3DQEJARYNaW5mb0B5by5jby51
|
|
10
|
+
ZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPPo+N67Z56ebScXJ9tX
|
|
11
|
+
tFpSNBNNyDlqU/X8bqouZjWuvxpWOI4xZkPKXi0t205ooVbQL/+962NASjJRrouQ
|
|
12
|
+
IUhJq7xhwb+KKcWyFpA25742mNgaxeZJa9iofiHeKotBvHz6pswuqa2gXAyTTmYf
|
|
13
|
+
j6BOIFhDeUffOjfJYbzACy7WLtbK6VIRSTHypQY+zMQluw1euyY8524GYzf8E+c5
|
|
14
|
+
9qjIa5YY5PPianvvR25VDNRCm0Z6GPolhIGvYPUWHFZx+HtU8xoZumi5Kddvipew
|
|
15
|
+
uujxNVBRyQ8bVRoYxKKuDMFHiXA6V01oPzSOtfPK7JI+rd2JFU7dQgbFxTXI9+Qx
|
|
16
|
+
2yUCAwEAAaOCAQIwgf8wHQYDVR0OBBYEFPj0nwwE8lJByx243yV6cfXbTKbhMIHP
|
|
17
|
+
BgNVHSMEgccwgcSAFPj0nwwE8lJByx243yV6cfXbTKbhoYGgpIGdMIGaMQswCQYD
|
|
18
|
+
VQQGEwJVRzEQMA4GA1UECBMHS2FtcGFsYTEQMA4GA1UEBxMHS2FtcGFsYTEbMBkG
|
|
19
|
+
A1UECgwSWW8hIFVnYW5kYSBMaW1pdGVkMRUwEwYDVQQLDAxZbyEgUGF5bWVudHMx
|
|
20
|
+
FTATBgNVBAMTDHd3dy55by5jby51ZzEcMBoGCSqGSIb3DQEJARYNaW5mb0B5by5j
|
|
21
|
+
by51Z4IJAN3e7VqDg5zQMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEB
|
|
22
|
+
AGCaUMHBxGVtVsA8xMDWknjH6hV9yuca3s0qRrOoMfM7nyOjeYtUNgZlsLxuX2n3
|
|
23
|
+
FhoeK9DUBvIKVSlVfO5SXgsXyWKG54YFEkZ8D50Krsyl5NCfaAJezkQ0MNdtpG98
|
|
24
|
+
wlD/cYa6C6DC/s1eilUbI5QqaxLo+EFy5VuHQ8tAuxJbNTVPMW9GvTjxofeMUnug
|
|
25
|
+
SxUMDqHmEkzbQV7yCBVqf3yi4XOM4/6B7Tr6gaandpuR+v2XaKl4SOf8G5svn96g
|
|
26
|
+
Kn+Bk8p6rlBWAl+5hWxHWi4dkjiLsk8q+aeKh6ibwYtRjEt/sbWTgJAZjI1mTT8d
|
|
27
|
+
wsLYlL7k1O3wCjUeMQzi274=
|
|
28
|
+
-----END CERTIFICATE-----
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
|
2
|
+
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
|
|
35
|
+
-----END CERTIFICATE-----
|