Pull current spec and clean it up

Also setup CI and CD to GH pages through GH actions.
This commit is contained in:
Andrew Mayorov 2021-11-30 18:19:41 +03:00
parent 3eedc0e4c8
commit 4300979ed5
No known key found for this signature in database
GPG Key ID: 2837C62ACFBFED5D
41 changed files with 16775 additions and 1 deletions

23
.github/workflows/build.yaml vendored Normal file
View File

@ -0,0 +1,23 @@
name: build
on:
- pull_request
env:
NODEJS_VERSION: '16'
jobs:
bundle:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: ${{ env.NODEJS_VERSION }}
cache: npm
- run: npm install
- name: Bundle specification
run: npm run build
- name: Validate specification
run: npm run test

View File

@ -1 +1 @@
# Empayre Wallets · Webhook Events API Specification
# Vality Wallets · Webhook Events API Specification

58
gulpfile.js Normal file
View File

@ -0,0 +1,58 @@
var gulp = require('gulp');
var util = require('gulp-util')
var gulpConnect = require('gulp-connect');
var connect = require('connect');
var cors = require('cors');
var path = require('path');
var exec = require('child_process').exec;
var portfinder = require('portfinder');
var swaggerRepo = require('swagger-repo');
var DIST_DIR = 'dist';
gulp.task('edit', gulp.series(
function (cb) {
exec('npm run bundle-swagger-ui', function (err, stdout, stderr) {
console.log(stderr);
cb(err);
});
},
function () {
portfinder.getPort({ port: 5000 }, function (err, port) {
var app = connect();
app.use(swaggerRepo.swaggerEditorMiddleware());
app.listen(port);
util.log(util.colors.green('swagger-editor started http://localhost:' + port));
});
}
));
gulp.task('build', function (cb) {
exec('npm run build', function (err, stdout, stderr) {
console.log(stderr);
cb(err);
});
});
gulp.task('reload', gulp.parallel('build', function () {
gulp.src(DIST_DIR).pipe(gulpConnect.reload())
}));
gulp.task('watch', function () {
gulp.watch(['spec/**/*', 'web/**/*'], gulp.series(['reload']));
});
gulp.task('serve', gulp.parallel('build', 'watch', 'edit', function () {
portfinder.getPort({ port: 3000 }, function (err, port) {
gulpConnect.server({
root: [DIST_DIR],
livereload: true,
port: port,
middleware: function (gulpConnect, opt) {
return [
cors()
]
}
});
});
}));

15889
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

28
package.json Normal file
View File

@ -0,0 +1,28 @@
{
"name": "swag-wallets-webhook-openapi-spec",
"version": "0.0.1",
"dependencies": {
"bower": "^1.7.7",
"connect": "^3.4.1",
"cors": "^2.7.1",
"gulp-connect": "^4.2.0",
"gulp-util": "^3.0.8",
"json-merge-patch": "^0.2.3",
"npm": "^8.1.3",
"portfinder": "^1.0.3",
"shelljs": "^0.7.0",
"swagger-repo": "^1.5.1",
"swagger-ui": "^2.1.4"
},
"private": true,
"scripts": {
"build": "node ./scripts/build.js",
"bundle-swagger-ui": "node ./scripts/bundle-swagger-ui.js",
"swagger": "swagger-repo",
"test": "swagger-repo validate",
"start": "gulp serve"
},
"devDependencies": {
"gulp": "github:gulpjs/gulp"
}
}

165
pom.xml Normal file
View File

@ -0,0 +1,165 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>dev.vality</groupId>
<artifactId>parent</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>swag-wallets-webhook-events</artifactId>
<version>SNAPSHOT</version>
<packaging>jar</packaging>
<name>swag-wallets-webhook-events</name>
<description>Generates jar artifact containing compiled swagger classes based on generated swagger yaml files
</description>
<properties>
<default.package>dev.vality.swag.wallets.webhook.events</default.package>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<swagger-annotations-version>1.5.21</swagger-annotations-version>
<jodatime-version>2.7</jodatime-version>
<maven-plugin-version>1.0.0</maven-plugin-version>
<java.version>1.8</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<jetty-version>9.2.15.v20160210</jetty-version>
<slf4j-version>1.7.21</slf4j-version>
<junit-version>4.12</junit-version>
<servlet-api-version>2.5</servlet-api-version>
<springfox-version>3.0.0</springfox-version>
<jackson-version>2.11.3</jackson-version>
<jackson-threetenbp-version>2.6.4</jackson-threetenbp-version>
<spring-version>5.3.1</spring-version>
</properties>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j-version}</version>
<scope>provided</scope>
</dependency>
<!--Spring dependencies -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring-version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring-version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring-version}</version>
<scope>provided</scope>
</dependency>
<!--SpringFox dependencies-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${springfox-version}</version>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</exclusion>
<exclusion>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${springfox-version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>${jackson-version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit-version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>${servlet-api-version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<!-- Bean Validation API support -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>io.swagger</groupId>
<artifactId>swagger-codegen-maven-plugin</artifactId>
<version>2.3.1</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>web_deploy/swagger.yaml</inputSpec>
<configOptions>
<dateLibrary>java8</dateLibrary>
</configOptions>
<language>spring</language>
<library>spring-mvc</library>
<apiPackage>${default.package}.api</apiPackage>
<modelPackage>${default.package}.model</modelPackage>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

17
scripts/build.js Executable file
View File

@ -0,0 +1,17 @@
#!/usr/bin/env node
'use strict';
var TARGET_DIR = 'dist'
if (process.argv[2]) {
TARGET_DIR = process.argv[2]
}
require('shelljs/global');
set('-e');
mkdir('-p', TARGET_DIR);
cp('-R', 'web/*', TARGET_DIR + '/');
exec('npm run swagger bundle -- -o ' + TARGET_DIR + '/swagger.json');
exec('npm run swagger bundle -- --yaml -o ' + TARGET_DIR + '/swagger.yaml');

18
scripts/bundle-swagger-ui.js Executable file
View File

@ -0,0 +1,18 @@
#!/usr/bin/env node
'use strict';
var Path = require('path');
var TARGET_DIR = 'dist'
if (process.argv[2]) {
TARGET_DIR = process.argv[2]
}
require('shelljs/global');
set('-e');
mkdir('-p', TARGET_DIR);
var SWAGGER_UI_DIST = Path.dirname(require.resolve('swagger-ui'));
rm('-rf', TARGET_DIR + '/swagger-ui/')
cp('-R', SWAGGER_UI_DIST, TARGET_DIR + '/swagger-ui/')
sed('-i', 'http://petstore.swagger.io/v2/swagger.json', '../swagger.json', TARGET_DIR + '/swagger-ui/index.html')

View File

@ -0,0 +1,31 @@
var jpointer = require('json-pointer');
var mergePatch = require('json-merge-patch');
module.exports = {
pathExpression: '$..["x-merge-properties"]',
init: function(swagger) {
console.log('* x-merge-properties plugin');
},
process: function(parent, name, jsonpath, swagger) {
var value = parent[name];
if (!Array.isArray(value)) {
throw Error('x-merge-properties argument should be array at ' + jsonpath);
}
let required = [];
let properties = {};
value.forEach(function(obj) {
if (obj.$ref && (typeof obj.$ref === 'string')) {
obj = jpointer.get(swagger, obj.$ref.substring(1));
}
if (typeof obj !== 'object') throw Error('Can\'t merge non-object values at ' + jsonpath);
required = required.concat(obj.required || []);
properties = mergePatch.apply(properties, obj.properties || {});
});
delete parent[name];
parent.required = required;
parent.properties = properties;
},
finish: function(swagger) {
// TODO: cleanup unused $refs
},
}

View File

@ -0,0 +1,28 @@
var jpointer = require('json-pointer');
var mergePatch = require('json-merge-patch');
module.exports = {
pathExpression: '$..["x-rebillyMerge"]',
init: function(swagger) {
console.log('* x-rebillyMerge plugin');
},
process: function(parent, name, jsonpath, swagger) {
var value = parent[name];
if (!Array.isArray(value)) {
throw Error('x-rebillyMerge argument should be array at ' + jsonpath);
}
let res = null;
value.forEach(function(obj) {
if (typeof obj !== 'object') throw Error('Can\'t merge non-object values at ' + jsonpath);
if (obj.$ref && (typeof obj.$ref === 'string')) {
obj = jpointer.get(swagger, obj.$ref.substring(1));
}
res = mergePatch.apply(res, obj);
});
delete parent[name];
Object.assign(parent, res);
},
finish: function(swagger) {
// TODO: cleanup unused $refs
},
}

24
spec/README.md Normal file
View File

@ -0,0 +1,24 @@
## Global headers
In order to minimize duplications you can use `headers` global object (similar to `definitions`, `responses`).
During build process all references to global `headers` will be inlined and `headers` will be removed form resulting spec so spec will be valid (global `headers` is not allowed by Swagger spec):
Example:
```yaml
...
headers:
Rate-Limit-Limit:
description: The number of allowed requests in the current period
type: integer
...
paths:
/api-keys:
get:
summary: Retrieve a list of api keys
responses:
200:
description: A list of api keys was retrieved successfully
headers:
Rate-Limit-Limit:
$ref: "#/headers/Rate-Limit-Limit"
```

View File

@ -0,0 +1,24 @@
description: Данные счета
type: object
required:
- currency
- identity
properties:
id:
x-rebillyMerge:
- $ref: '#/definitions/AccountID'
createdAt:
description: Дата и время создания счета
type: string
format: date-time
currency:
x-rebillyMerge:
- $ref: '#/definitions/CurrencyID'
identity:
x-rebillyMerge:
- $ref: '#/definitions/IdentityID'
accountNumber:
x-rebillyMerge:
- $ref: '#/definitions/AccountNumber'

View File

@ -0,0 +1,3 @@
description: Идентификатор счета
type: string
example: tZ0jUmlsV0

View File

@ -0,0 +1,4 @@
description: Номер счета
type: integer
format: int64
example: 1430000

View File

@ -0,0 +1,16 @@
description: |
Объём денежных средств
type: object
required:
- amount
- currency
properties:
amount:
description: |
Сумма денежных средств в минорных единицах, например, в копейках
type: integer
format: int64
example: 1430000
currency:
x-rebillyMerge:
- $ref: '#/definitions/CurrencyID'

View File

@ -0,0 +1,26 @@
description: Данные банковской карты
allOf:
- $ref: '#/definitions/DestinationResource'
- type: object
required:
- cardNumberMask
- paymentSystem
properties:
cardNumberMask:
description: Маскированый номер карты
type: string
pattern: '^\d{6,8}\*+\d{2,4}$'
bin:
description: BIN банка-эмитента карты
type: string
pattern: '^\d{6,8}$'
lastDigits:
description: Последние цифры номера карты
type: string
pattern: '^\d{2,4}$'
paymentSystem:
x-rebillyMerge:
- $ref: '#/definitions/BankCardPaymentSystem'
tokenProvider:
x-rebillyMerge:
- $ref: '#/definitions/BankCardTokenProvider'

View File

@ -0,0 +1,12 @@
description: Платежная система
type: string
# enum:
# - visa
# - mastercard
# - dankort
# - amex
# - dinersclub
# - discover
# - unionpay
# - jcb
# - nspkmir

View File

@ -0,0 +1,6 @@
description: Провайдер платежных токенов
type: string
enum:
- applepay
- googlepay
- samsungpay

View File

@ -0,0 +1,9 @@
description: Криптовалюта
type: string
enum:
- Bitcoin
- Litecoin
- BitcoinCash
- Ripple
- Ethereum
- Zcash

View File

@ -0,0 +1,17 @@
description: Данные криптовалютного кошелька
allOf:
- $ref: '#/definitions/DestinationResource'
- type: object
required:
- cryptoWalletId
- currency
properties:
cryptoWalletId:
description: Идентификатор (он же адрес) криптовалютного кошелька
type: string
minLength: 16
maxLength: 256
example: zu3TcwGI71Bpaaw2XkLWZXlhMdn4zpVzMQ
currency:
x-rebillyMerge:
- $ref: '#/definitions/CryptoCurrency'

View File

@ -0,0 +1,6 @@
description: |
Валюта, символьный код согласно [ISO
4217](http://www.iso.org/iso/home/standards/currency_codes.htm).
type: string
pattern: '^[A-Z]{3}$'
example: RUB

View File

@ -0,0 +1,35 @@
description: Данные приемника денежных средств
type: object
required:
- name
- identity
- currency
- resource
properties:
id:
x-rebillyMerge:
- $ref: '#/definitions/DestinationID'
- readOnly: true
name:
description: |
Человекочитаемое название приёмника средств, по которому его легко узнать
type: string
example: Squarey plastic thingy
identity:
x-rebillyMerge:
- $ref: '#/definitions/IdentityID'
currency:
x-rebillyMerge:
- $ref: '#/definitions/CurrencyID'
resource:
$ref: '#/definitions/DestinationResource'
metadata:
description: |
Произвольный, специфичный для клиента API и непрозрачный для системы набор данных, ассоциированных с
данным приёмником
type: object
example:
color_hint: olive-green
externalID:
x-rebillyMerge:
- $ref: '#/definitions/ExternalID'

View File

@ -0,0 +1,13 @@
description: Смена статуса приемника на авторизованный
allOf:
- $ref: '#/definitions/Event'
- type: object
required:
- destinationID
properties:
destinationID:
x-rebillyMerge:
- $ref: '#/definitions/DestinationID'
externalID:
x-rebillyMerge:
- $ref: '#/definitions/ExternalID'

View File

@ -0,0 +1,9 @@
description: Событие создания приемника денежных средств
allOf:
- $ref: '#/definitions/Event'
- type: object
required:
- destination
properties:
destination:
$ref: '#/definitions/Destination'

View File

@ -0,0 +1,3 @@
description: Идентификатор места назначения денежных средств
type: string
example: "10ASF74D98"

View File

@ -0,0 +1,3 @@
description: Человекочитаемое название места назначения, по которому его легко узнать
type: string
example: "Worldwide PHP Awareness Initiative"

View File

@ -0,0 +1,14 @@
description: Ресурс приёмника денежных средств, используемый для осуществления выводов
type: object
discriminator: type
required:
- type
properties:
type:
description: |
Тип ресурса приёмника средств.
type: string
enum:
- BankCard
- CryptoWallet
- DigitalWallet

View File

@ -0,0 +1,13 @@
description: Смена статуса приемника на не авторизованный
allOf:
- $ref: '#/definitions/Event'
- type: object
required:
- destinationID
properties:
destinationID:
x-rebillyMerge:
- $ref: '#/definitions/DestinationID'
externalID:
x-rebillyMerge:
- $ref: '#/definitions/ExternalID'

View File

@ -0,0 +1,21 @@
description: Данные криптовалютного кошелька
allOf:
- $ref: '#/definitions/DestinationResource'
- type: object
required:
- digitalWalletId
- digitalWalletProvider
properties:
digitalWalletId:
description: Идентификатор
type: string
minLength: 16
maxLength: 256
example: zu3TcwGI71Bpaaw2XkLWZXlhMdn4zpVzMQ
digitalWalletProvider:
description: |
Идентификатор провайдера
type: string
enum:
- webmoney

View File

@ -0,0 +1,31 @@
description: Данные события
type: object
discriminator: eventType
required:
- occuredAt
- topic
- eventType
properties:
eventID:
description: Идентификатор события в системе
type: string
occuredAt:
description: Дата и время возникновения события
type: string
format: date-time
topic:
description: Предмет оповещения
type: string
enum:
- WithdrawalTopic
- DestinationTopic
eventType:
type: string
description: Тип произошедшего с предметом оповещения события
enum:
- WithdrawalStarted
- WithdrawalSucceeded
- WithdrawalFailed
- DestinationCreated
- DestinationAuthorized
- DestinationUnauthorized

View File

@ -0,0 +1,6 @@
description: |
Уникальный идентификатор сущности на вашей стороне.
При указании будет использован для того, чтобы гарантировать идемпотентную обработку операции.
type: string
example: "10036274"

View File

@ -0,0 +1,3 @@
description: Идентификатор личности владельца кошелька
type: string
example: tZ0jUmlsV0

View File

@ -0,0 +1,3 @@
description: Идентификатор кошелька
type: string
example: "10068321"

View File

@ -0,0 +1,31 @@
description: Данные вывода денежных средств
type: object
required:
- wallet
- destination
- body
properties:
id:
x-rebillyMerge:
- $ref: '#/definitions/WithdrawalID'
createdAt:
description: Дата и время запуска вывода
type: string
format: date-time
destination:
x-rebillyMerge:
- $ref: '#/definitions/DestinationID'
body:
x-rebillyMerge:
- description: Объём средств, которые необходимо вывести
- $ref: '#/definitions/Asset'
metadata:
description: |
Произвольный, специфичный для клиента API и непрозрачный для системы набор данных, ассоциированных с
данным выводом
wallet:
x-rebillyMerge:
- $ref: '#/definitions/WalletID'
externalID:
x-rebillyMerge:
- $ref: '#/definitions/ExternalID'

View File

@ -0,0 +1,13 @@
description: Событие о неуспешном осуществлении вывода средств
allOf:
- $ref: '#/definitions/Event'
- type: object
required:
- withdrawalID
properties:
withdrawalID:
x-rebillyMerge:
- $ref: '#/definitions/WithdrawalID'
externalID:
x-rebillyMerge:
- $ref: '#/definitions/ExternalID'

View File

@ -0,0 +1,3 @@
description: Идентификатор вывода денежных средств
type: string
example: tZ0jUmlsV0

View File

@ -0,0 +1,9 @@
description: Событие о начале осуществления вывода средств
allOf:
- $ref: '#/definitions/Event'
- type: object
required:
- withdrawal
properties:
withdrawal:
$ref: '#/definitions/Withdrawal'

View File

@ -0,0 +1,13 @@
description: Событие об успешном осуществлении вывода средств
allOf:
- $ref: '#/definitions/Event'
- type: object
required:
- withdrawalID
properties:
withdrawalID:
x-rebillyMerge:
- $ref: '#/definitions/WithdrawalID'
externalID:
x-rebillyMerge:
- $ref: '#/definitions/ExternalID'

View File

@ -0,0 +1,16 @@
post:
tags:
- Event Notifications
summary: Оповестить о событии
operationId: notifyWebhookEvent
parameters:
- $ref: '#/parameters/signature'
- in: body
name: event
description: Данные произошедшего в системе события
required: true
schema:
$ref: '#/definitions/Event'
responses:
'200':
description: Оповещение обработано

96
spec/swagger.yaml Normal file
View File

@ -0,0 +1,96 @@
swagger: '2.0'
info:
version: '0.1.0'
title: Vality Wallets · Webhook Events API
termsOfService: 'https://vality.dev/'
description: |
## Wallet Webhook Events API
Данная спецификация определяет протокол доставки оповещений о возникновении
новых событий по кошелькам в рамках вашей организации, которые система доставляет в
виде HTTP-запросов на URL-адреса созданных вами webhook'ов. Обработчики для
подобного рода запросов необходимо реализовать на стороне вашего серверного
кода согласно данной спецификации.
Webhook — это подписка на определенный тип события либо их группу,
касающихся различных объектов в рамках вашей организации. Для управления
webhook'ами используются методы API, описанные в спецификации
[Vality Webhook Management API](https://github.com/valitydev/swag-wallets).
Когда наступает одно из событий в рамках определенного кошелька (например,
изменение статуса кошелька), система выбирает
webhook, подходящий под этот тип события, и отправляет HTTP-запрос,
содержащий сообщение в формате JSON на указанный в этом webhook'е URL. Если
вы создали несколько webhook'ов, подходящих под этот тип события, то событие
доставляется одновременно на все заданные в них URL в неопределённом
порядке.
## Стратегия доставки
Система гарантирует порядок доставки событий в рамках определенного предмета оповещения
(кошелек, пополнение, выплата и т.п.). Система поддерживает очередь сообщений для каждого
предмета оповещения, чтобы соблюсти очередность и гарантированную доставку.
Запрос на доставку считается успешным только при получении ответа со
статусом `200`. Система будет ожидать успешного ответа на отправленный
запрос в течение 10 секунд. В случае ответа любым другим статусом или по
истечении указанного времени, отведённого на обработку оповещения, система
будет пытаться повторно доставить оповещения до получения успешного ответа,
либо до принятия решения о невозможности доставить информацию. Попытки
доставки будут производиться со следующими временными интервалами между
запросами:
- 30 секунд,
- 5 минут,
- 15 минут,
- 1 час.
- каждый час в течение суток (24 часа)
Если последняя попытка доставить оповещение оканчивается неудачей, все события, которые
накопились в очереди этого кошелька, отбрасываются.
## Авторизация полученных сообщений
Система подтверждает подлинность оповещений, подписывая сообщения
приватным ключом, уникальным для каждого webhook'а, парный публичный ключ к
которому содержится в данных этого webhook'а. Подпись передается в
HTTP-заголовке `Content-Signature`. В заголовке в виде различных атрибутов
содержится информация об использованном при формировании подписи алгоритме и
значение подписи в формате
[URL-safe base-64](https://tools.ietf.org/html/rfc4648).
```
Content-Signature: alg=RS256; digest=zFuf7bRH4RHwyktaqHQwmX5rn3LfSb4dKo...
```
На данный момент возможно использование единственного алоритма формирования
подписи.
### [RS256](https://tools.ietf.org/html/rfc7518#section-3.3)
Подпись формируется согласно алгоритму
[RSASSA-PKCS1-v1_5](https://tools.ietf.org/html/rfc3447#section-8.2), на
вход которому подаётся результат вычисления хэша сообщения по алгоритму
[SHA-256](https://tools.ietf.org/html/rfc6234).
Набор атрибутов заголовка и список возможных алгоритмов формирования подписи
в дальнейшем могут быть расширены.
schemes:
- https
consumes:
- application/json; charset=utf-8
produces:
- application/json; charset=utf-8
parameters:
signature:
name: Content-Signature
in: header
description: >
Подпись сообщения, сформированная согласно указанным выше правилам
required: true
type: string
tags:
- name: Event Notifications
x-displayName: Оповещения
description: Доставка оповещений о событиях системы.

35
web/index.html Normal file
View File

@ -0,0 +1,35 @@
<!DOCTYPE html>
<html>
<head>
<title>Vality Wallets · Webhook Events API</title>
<!-- Needed for adaptive design -->
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://cdn.jsdelivr.net/npm/redoc@next/bundles/redoc.standalone.js">
</script>
<!-- ReDoc doesn't change outer page styles -->
<style>
body {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<div id='redoc'></div>
<script type="text/javascript">
Redoc.init(
"./swagger.json",
{
theme: {
breakpoints: {
// 3-panel view fix
medium: '75rem'
}
}
},
document.getElementById('redoc')
);
</script>
</body>
</html>