Merge branch 'master' into age-withdraw
This commit is contained in:
commit
80a1b8f524
@ -70,7 +70,8 @@ EXTRA_DIST = \
|
|||||||
$(rdata_DATA) \
|
$(rdata_DATA) \
|
||||||
coverage.sh \
|
coverage.sh \
|
||||||
gnunet.tag \
|
gnunet.tag \
|
||||||
microhttpd.tag
|
microhttpd.tag \
|
||||||
|
packages
|
||||||
|
|
||||||
# Change the set of supported languages here. You should
|
# Change the set of supported languages here. You should
|
||||||
# also update tos'XX'data and EXTRA_DIST accordingly.
|
# also update tos'XX'data and EXTRA_DIST accordingly.
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 85736484cb0da26aded705ebb1e944e8bb1b8504
|
Subproject commit f9ea79a6aae074928f44960f69bc3c2d0c9c7e1d
|
@ -0,0 +1 @@
|
|||||||
|
# This configuration will be changed by tooling. Do not touch it manually.
|
@ -0,0 +1,49 @@
|
|||||||
|
# Main entry point for the GNU Taler configuration.
|
||||||
|
#
|
||||||
|
# Structure:
|
||||||
|
# - taler.conf is the main configuration entry point
|
||||||
|
# used by all Taler components (the file you are currently
|
||||||
|
# looking at.
|
||||||
|
# - overrides.conf contains configuration overrides that are
|
||||||
|
# set by some tools that help with the configuration,
|
||||||
|
# and should not be edited by humans. Comments in this file
|
||||||
|
# are not preserved.
|
||||||
|
# - conf.d/ contains configuration files for
|
||||||
|
# Taler components, which can be read by all
|
||||||
|
# users of the system and are included by the main
|
||||||
|
# configuration.
|
||||||
|
# - secrets/ contains configuration snippets
|
||||||
|
# with secrets for particular services.
|
||||||
|
# These files should have restrictive permissions
|
||||||
|
# so that only users of the relevant services
|
||||||
|
# can read it. All files in it should end with
|
||||||
|
# ".secret.conf".
|
||||||
|
|
||||||
|
[taler]
|
||||||
|
|
||||||
|
# Currency of the Taler deployment. This setting applies to all Taler
|
||||||
|
# components that only support a single currency.
|
||||||
|
#currency = KUDOS
|
||||||
|
|
||||||
|
# Smallest currency unit handled by the underlying bank system. Taler payments
|
||||||
|
# can make payments smaller than this units, but interactions with external
|
||||||
|
# systems is always rounded to this unit.
|
||||||
|
#currency_round_unit = KUDOS:0.01
|
||||||
|
|
||||||
|
# Monthly amount that mandatorily triggers an AML check
|
||||||
|
#AML_THRESHOLD = KUDOS:10000000
|
||||||
|
|
||||||
|
[paths]
|
||||||
|
|
||||||
|
TALER_HOME = /var/lib/taler
|
||||||
|
TALER_RUNTIME_DIR = /run/taler
|
||||||
|
TALER_CACHE_HOME = /var/cache/taler
|
||||||
|
TALER_CONFIG_HOME = /etc/taler
|
||||||
|
TALER_DATA_HOME = /var/lib/taler
|
||||||
|
|
||||||
|
|
||||||
|
# Inline configurations from all Taler components.
|
||||||
|
@inline-matching@ conf.d/*.conf
|
||||||
|
|
||||||
|
# Overrides from tools that help with configuration.
|
||||||
|
@inline@ overrides.conf
|
@ -0,0 +1,4 @@
|
|||||||
|
<Location "/taler-auditor/">
|
||||||
|
ProxyPass "unix:/var/lib/taler-auditor/auditor.sock|http://example.com/"
|
||||||
|
RequestHeader add "X-Forwarded-Proto" "https"
|
||||||
|
</Location>
|
@ -0,0 +1,18 @@
|
|||||||
|
server {
|
||||||
|
|
||||||
|
listen 80;
|
||||||
|
listen [::]:80;
|
||||||
|
|
||||||
|
server_name localhost;
|
||||||
|
|
||||||
|
access_log /var/log/nginx/auditor.log;
|
||||||
|
error_log /var/log/nginx/auditor.err;
|
||||||
|
|
||||||
|
location /taler-auditor/ {
|
||||||
|
proxy_pass http://unix:/var/lib/taler-auditor/auditor.sock;
|
||||||
|
proxy_redirect off;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Forwarded-Host "localhost";
|
||||||
|
#proxy_set_header X-Forwarded-Proto "https";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
# Read secret sections into configuration, but only
|
||||||
|
# if we have permission to do so.
|
||||||
|
@inline-secret@ auditordb-postgres ../secrets/auditor-db.secret.conf
|
||||||
|
|
||||||
|
[auditor]
|
||||||
|
# Debian package is configured to use a reverse proxy with a UNIX
|
||||||
|
# domain socket. See nginx/apache configuration files.
|
||||||
|
SERVE = UNIX
|
||||||
|
UNIXPATH = /var/lib/taler-auditor/auditor.sock
|
||||||
|
|
||||||
|
# Only supported database is Postgres right now.
|
||||||
|
DATABASE = postgres
|
@ -0,0 +1,10 @@
|
|||||||
|
# Database configuration for the Taler auditor.
|
||||||
|
|
||||||
|
[auditordb-postgres]
|
||||||
|
|
||||||
|
# Typically, there should only be a single line here, of the form:
|
||||||
|
|
||||||
|
CONFIG=postgres:///DATABASE
|
||||||
|
|
||||||
|
# The details of the URI depend on where the database lives and how
|
||||||
|
# access control was configured.
|
@ -0,0 +1,4 @@
|
|||||||
|
<Location "/taler-exchange/">
|
||||||
|
ProxyPass "unix:/run/taler/exchange-httpd/exchange-http.sock|http://example.com/"
|
||||||
|
RequestHeader add "X-Forwarded-Proto" "https"
|
||||||
|
</Location>
|
@ -0,0 +1,17 @@
|
|||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
listen [::]:80;
|
||||||
|
|
||||||
|
server_name localhost;
|
||||||
|
|
||||||
|
access_log /var/log/nginx/exchange.log;
|
||||||
|
error_log /var/log/nginx/exchange.err;
|
||||||
|
|
||||||
|
location /taler-exchange/ {
|
||||||
|
proxy_pass http://unix:/run/taler/exchange-httpd/exchange-http.sock:/;
|
||||||
|
proxy_redirect off;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Forwarded-Host "localhost";
|
||||||
|
#proxy_set_header X-Forwarded-Proto "https";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
# Configuration for business-level aspects of the exchange.
|
||||||
|
|
||||||
|
[exchange]
|
||||||
|
|
||||||
|
# Here you MUST add the master public key of the offline system
|
||||||
|
# which you can get using `taler-exchange-offline setup`.
|
||||||
|
# This is just an example, your key will be different!
|
||||||
|
# MASTER_PUBLIC_KEY = YE6Q6TR1EDB7FD0S68TGDZGF1P0GHJD2S0XVV8R2S62MYJ6HJ4ZG
|
||||||
|
# MASTER_PUBLIC_KEY =
|
||||||
|
|
||||||
|
# Publicly visible base URL of the exchange.
|
||||||
|
# BASE_URL = https://example.com/
|
||||||
|
# BASE_URL =
|
||||||
|
|
||||||
|
# Here you MUST configure the amount above which transactions are
|
||||||
|
# always subject to manual AML review.
|
||||||
|
# AML_THRESHOLD =
|
||||||
|
|
||||||
|
# Attribute encryption key for storing attributes encrypted
|
||||||
|
# in the database. Should be a high-entropy nonce.
|
||||||
|
ATTRIBUTE_ENCRYPTION_KEY = SET_ME_PLEASE
|
||||||
|
|
||||||
|
# For your terms of service and privacy policy, you should specify
|
||||||
|
# an Etag that must be updated whenever there are significant
|
||||||
|
# changes to either document. The format is up to you, what matters
|
||||||
|
# is that the value is updated and never re-used. See the HTTP
|
||||||
|
# specification on Etags.
|
||||||
|
# TERMS_ETAG =
|
||||||
|
# PRIVACY_ETAG =
|
||||||
|
|
||||||
|
SERVE = unix
|
||||||
|
UNIXPATH_MODE = 666
|
||||||
|
|
||||||
|
# Bank accounts used by the exchange should be specified here:
|
||||||
|
[exchange-account-1]
|
||||||
|
|
||||||
|
ENABLE_CREDIT = NO
|
||||||
|
ENABLE_DEBIT = NO
|
||||||
|
|
||||||
|
# Account identifier in the form of an RFC-8905 payto:// URI.
|
||||||
|
# For SEPA, looks like payto://sepa/$IBAN?receiver-name=$NAME
|
||||||
|
# Make sure to URL-encode spaces in $NAME!
|
||||||
|
PAYTO_URI =
|
||||||
|
|
||||||
|
# Credentials to access the account are in a separate
|
||||||
|
# config file with restricted permissions.
|
||||||
|
@inline-secret@ exchange-accountcredentials-1 ../secrets/exchange-accountcredentials-1.secret.conf
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,33 @@
|
|||||||
|
#
|
||||||
|
# This configuration file specifies the various denominations offered by your
|
||||||
|
# exchange.
|
||||||
|
#
|
||||||
|
# Each denomination must be specified in a sections starting with
|
||||||
|
# "coin_".
|
||||||
|
#
|
||||||
|
# What follows is an example.
|
||||||
|
#
|
||||||
|
|
||||||
|
# [coin_FOO]
|
||||||
|
## Actual value of the coin
|
||||||
|
#VALUE = KUDOS:1
|
||||||
|
|
||||||
|
## How long will one key be used for withdrawals?
|
||||||
|
#DURATION_WITHDRAW = 7 days
|
||||||
|
|
||||||
|
## How long do users have to spend their coins?
|
||||||
|
#DURATION_SPEND = 2 years
|
||||||
|
|
||||||
|
## How long does the exchange keep the proofs around for legal disputes?
|
||||||
|
#DURATION_LEGAL = 6 years
|
||||||
|
|
||||||
|
## Fees charged. Note that for the lowest denomination, the
|
||||||
|
## fee must precisely be the lowest denomination, or zero.
|
||||||
|
#FEE_WITHDRAW = KUDOS:0
|
||||||
|
#FEE_DEPOSIT = KUDOS:0
|
||||||
|
#FEE_REFRESH = KUDOS:0
|
||||||
|
#FEE_REFUND = KUDOS:0
|
||||||
|
|
||||||
|
## How long should the RSA keys be. Do not change unless you really know
|
||||||
|
## what you are doing (consult your local cryptographer first!).
|
||||||
|
#RSA_KEYSIZE = 2048
|
@ -0,0 +1,13 @@
|
|||||||
|
# Configuration settings for system parameters of the exchange.
|
||||||
|
|
||||||
|
# Read secret sections into configuration, but only
|
||||||
|
# if we have permission to do so.
|
||||||
|
@inline-secret@ exchangedb-postgres ../secrets/exchange-db.secret.conf
|
||||||
|
|
||||||
|
[exchange]
|
||||||
|
|
||||||
|
# Only supported database is Postgres right now.
|
||||||
|
DATABASE = postgres
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,17 @@
|
|||||||
|
# This file contains the secret credentials
|
||||||
|
# to access the Taler Wire Gateway API (usually
|
||||||
|
# provided by LibEuFin) for the exchange accounts.
|
||||||
|
#
|
||||||
|
# Each exchange-account-* section should have a matching
|
||||||
|
# exchange-accountcredentials-* section here.
|
||||||
|
#
|
||||||
|
# Each of those sections must be imported via @inline-secret@,
|
||||||
|
# usually in conf.d/exchange-business.conf.
|
||||||
|
|
||||||
|
[exchange-accountcredentials-1]
|
||||||
|
|
||||||
|
wire_gateway_auth_method = basic
|
||||||
|
password =
|
||||||
|
username =
|
||||||
|
wire_gateway_url =
|
||||||
|
|
@ -0,0 +1,10 @@
|
|||||||
|
# Database configuration for the Taler exchange.
|
||||||
|
|
||||||
|
[exchangedb-postgres]
|
||||||
|
|
||||||
|
# Typically, there should only be a single line here, of the form:
|
||||||
|
|
||||||
|
# CONFIG=postgres:///DATABASE
|
||||||
|
|
||||||
|
# The details of the URI depend on where the database lives and how
|
||||||
|
# access control was configured.
|
@ -0,0 +1,12 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=GNU Taler payment system auditor REST API
|
||||||
|
After=postgres.service network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=taler-auditor-httpd
|
||||||
|
Type=simple
|
||||||
|
Restart=on-failure
|
||||||
|
ExecStart=/usr/bin/taler-auditor-httpd -c /etc/taler/taler.conf
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
@ -0,0 +1,18 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=GNU Taler payment system exchange aggregator service
|
||||||
|
PartOf=taler-exchange.target
|
||||||
|
After=postgres.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=taler-exchange-aggregator
|
||||||
|
Type=simple
|
||||||
|
Restart=always
|
||||||
|
RestartSec=1s
|
||||||
|
ExecStart=/usr/bin/taler-exchange-aggregator -c /etc/taler/taler.conf
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
PrivateTmp=yes
|
||||||
|
PrivateDevices=yes
|
||||||
|
ProtectSystem=full
|
||||||
|
Slice=taler-exchange.slice
|
||||||
|
RuntimeMaxSec=3600s
|
@ -0,0 +1,17 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=GNU Taler payment system exchange aggregator service
|
||||||
|
PartOf=taler-exchange.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=taler-exchange-aggregator
|
||||||
|
Type=simple
|
||||||
|
Restart=always
|
||||||
|
RestartSec=1s
|
||||||
|
ExecStart=/usr/bin/taler-exchange-aggregator -c /etc/taler/taler.conf
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
PrivateTmp=yes
|
||||||
|
PrivateDevices=yes
|
||||||
|
ProtectSystem=full
|
||||||
|
Slice=taler-exchange.slice
|
||||||
|
RuntimeMaxSec=3600s
|
@ -0,0 +1,18 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=GNU Taler payment system exchange closer service
|
||||||
|
PartOf=taler-exchange.target
|
||||||
|
After=network.target postgres.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=taler-exchange-closer
|
||||||
|
Type=simple
|
||||||
|
Restart=always
|
||||||
|
RestartSec=1s
|
||||||
|
ExecStart=/usr/bin/taler-exchange-closer -c /etc/taler/taler.conf
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
PrivateTmp=yes
|
||||||
|
PrivateDevices=yes
|
||||||
|
ProtectSystem=full
|
||||||
|
Slice=taler-exchange.slice
|
||||||
|
RuntimeMaxSec=3600s
|
@ -0,0 +1,18 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=GNU Taler payment system exchange expire service
|
||||||
|
PartOf=taler-exchange.target
|
||||||
|
After=postgres.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=taler-exchange-expire
|
||||||
|
Type=simple
|
||||||
|
Restart=always
|
||||||
|
RestartSec=1s
|
||||||
|
ExecStart=/usr/bin/taler-exchange-expire -c /etc/taler/taler.conf
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
PrivateTmp=yes
|
||||||
|
PrivateDevices=yes
|
||||||
|
ProtectSystem=full
|
||||||
|
Slice=taler-exchange.slice
|
||||||
|
RuntimeMaxSec=3600s
|
@ -0,0 +1,33 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=GNU Taler payment system exchange REST API
|
||||||
|
AssertPathExists=/run/taler/exchange-httpd
|
||||||
|
Requires=taler-exchange-httpd.socket taler-exchange-secmod-cs.service taler-exchange-secmod-rsa.service taler-exchange-secmod-eddsa.service
|
||||||
|
After=postgres.service network.target taler-exchange-secmod-cs.service taler-exchange-secmod-rsa.service taler-exchange-secmod-eddsa.service
|
||||||
|
PartOf=taler-exchange.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=taler-exchange-httpd
|
||||||
|
Type=simple
|
||||||
|
|
||||||
|
# Depending on the configuration, the service process kills itself and then
|
||||||
|
# needs to be restarted. Thus no significant delay on restarts.
|
||||||
|
Restart=always
|
||||||
|
RestartSec=1ms
|
||||||
|
|
||||||
|
# Disable the service if more than 5 restarts are encountered within 5s.
|
||||||
|
# These are usually the systemd defaults, but can be overwritten, thus we set
|
||||||
|
# them here explicitly, as the exchange code assumes StartLimitInterval
|
||||||
|
# to be >=5s.
|
||||||
|
StartLimitBurst=5
|
||||||
|
StartLimitInterval=5s
|
||||||
|
|
||||||
|
ExecStart=/usr/bin/taler-exchange-httpd -c /etc/taler/taler.conf
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
PrivateTmp=no
|
||||||
|
PrivateDevices=yes
|
||||||
|
ProtectSystem=full
|
||||||
|
Slice=taler-exchange.slice
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
@ -0,0 +1,27 @@
|
|||||||
|
% This is a systemd service template.
|
||||||
|
[Unit]
|
||||||
|
Description=GNU Taler payment system exchange REST API at %I
|
||||||
|
AssertPathExists=/run/taler/exchange-httpd
|
||||||
|
Requires=taler-exchange-httpd@%i.socket taler-exchange-secmod-rsa.service taler-exchange-secmod-eddsa.service
|
||||||
|
After=postgres.service network.target taler-exchange-secmod-rsa.service taler-exchange-secmod-eddsa.service
|
||||||
|
PartOf=taler-exchange.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=taler-exchange-httpd
|
||||||
|
Type=simple
|
||||||
|
# Depending on the configuration, the service suicides and then
|
||||||
|
# needs to be restarted.
|
||||||
|
Restart=always
|
||||||
|
# Do not dally on restarts.
|
||||||
|
RestartSec=1ms
|
||||||
|
EnvironmentFile=/etc/environment
|
||||||
|
ExecStart=/usr/bin/taler-exchange-httpd -c /etc/taler/taler.conf
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
PrivateTmp=no
|
||||||
|
PrivateDevices=yes
|
||||||
|
ProtectSystem=full
|
||||||
|
Slice=taler-exchange.slice
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
@ -0,0 +1,18 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=GNU Taler payment system exchange CS security module
|
||||||
|
AssertPathExists=/run/taler/exchange-secmod-cs
|
||||||
|
PartOf=taler-exchange.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=taler-exchange-secmod-cs
|
||||||
|
Type=simple
|
||||||
|
Restart=always
|
||||||
|
RestartSec=100ms
|
||||||
|
ExecStart=/usr/bin/taler-exchange-secmod-cs -c /etc/taler/taler.conf
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
PrivateTmp=no
|
||||||
|
PrivateDevices=yes
|
||||||
|
ProtectSystem=full
|
||||||
|
IPAddressDeny=any
|
||||||
|
Slice=taler-exchange.slice
|
@ -0,0 +1,19 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=GNU Taler payment system exchange EdDSA security module
|
||||||
|
AssertPathExists=/run/taler/exchange-secmod-eddsa
|
||||||
|
PartOf=taler-exchange.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=taler-exchange-secmod-eddsa
|
||||||
|
Type=simple
|
||||||
|
Restart=always
|
||||||
|
RestartSec=100ms
|
||||||
|
ExecStart=/usr/bin/taler-exchange-secmod-eddsa -c /etc/taler/taler.conf
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
PrivateTmp=no
|
||||||
|
PrivateDevices=yes
|
||||||
|
ProtectSystem=full
|
||||||
|
IPAddressDeny=any
|
||||||
|
Slice=taler-exchange.slice
|
||||||
|
|
@ -0,0 +1,18 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=GNU Taler payment system exchange RSA security module
|
||||||
|
AssertPathExists=/run/taler/exchange-secmod-rsa
|
||||||
|
PartOf=taler-exchange.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=taler-exchange-secmod-rsa
|
||||||
|
Type=simple
|
||||||
|
Restart=always
|
||||||
|
RestartSec=100ms
|
||||||
|
ExecStart=/usr/bin/taler-exchange-secmod-rsa -c /etc/taler/taler.conf
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
PrivateTmp=no
|
||||||
|
PrivateDevices=yes
|
||||||
|
ProtectSystem=full
|
||||||
|
IPAddressDeny=any
|
||||||
|
Slice=taler-exchange.slice
|
@ -0,0 +1,18 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Taler Exchange Transfer Service
|
||||||
|
After=network.target postgres.service
|
||||||
|
PartOf=taler-exchange.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=taler-exchange-wire
|
||||||
|
Type=simple
|
||||||
|
Restart=always
|
||||||
|
RestartSec=1s
|
||||||
|
ExecStart=/usr/bin/taler-exchange-transfer -c /etc/taler/taler.conf
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
PrivateTmp=yes
|
||||||
|
PrivateDevices=yes
|
||||||
|
ProtectSystem=full
|
||||||
|
Slice=taler-exchange.slice
|
||||||
|
RuntimeMaxSec=3600s
|
@ -0,0 +1,18 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=GNU Taler payment system exchange wirewatch service
|
||||||
|
After=network.target postgres.service
|
||||||
|
PartOf=taler-exchange.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=taler-exchange-wire
|
||||||
|
Type=simple
|
||||||
|
Restart=always
|
||||||
|
RestartSec=1s
|
||||||
|
RuntimeMaxSec=3600s
|
||||||
|
ExecStart=/usr/bin/taler-exchange-wirewatch -c /etc/taler/taler.conf
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
PrivateTmp=yes
|
||||||
|
PrivateDevices=yes
|
||||||
|
ProtectSystem=full
|
||||||
|
Slice=taler-exchange.slice
|
@ -0,0 +1,18 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=GNU Taler payment system exchange wirewatch service
|
||||||
|
After=network.target
|
||||||
|
PartOf=taler-exchange.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=taler-exchange-wire
|
||||||
|
Type=simple
|
||||||
|
Restart=always
|
||||||
|
RestartSec=1s
|
||||||
|
ExecStart=/usr/bin/taler-exchange-wirewatch -c /etc/taler/taler.conf
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
PrivateTmp=yes
|
||||||
|
PrivateDevices=yes
|
||||||
|
ProtectSystem=full
|
||||||
|
Slice=taler-exchange.slice
|
||||||
|
RuntimeMaxSec=3600s
|
@ -4,7 +4,7 @@
|
|||||||
exec 1>&2
|
exec 1>&2
|
||||||
|
|
||||||
RET=0
|
RET=0
|
||||||
changed=$(git diff --cached --name-only | grep -v mustach)
|
changed=$(git diff --cached --name-only | grep -v mustach | grep -v templating/test./)
|
||||||
crustified=""
|
crustified=""
|
||||||
|
|
||||||
for f in $changed;
|
for f in $changed;
|
||||||
@ -28,7 +28,7 @@ done
|
|||||||
if [ $RET = 1 ];
|
if [ $RET = 1 ];
|
||||||
then
|
then
|
||||||
echo "Run"
|
echo "Run"
|
||||||
echo "uncrustify --no-backup -c uncrustify.cfg ${crustified}"
|
echo "uncrustify --replace -c uncrustify.cfg ${crustified}"
|
||||||
echo "before committing."
|
echo "before committing."
|
||||||
fi
|
fi
|
||||||
exit $RET
|
exit $RET
|
||||||
|
@ -12,6 +12,14 @@
|
|||||||
# BASE_URL = https://example.com/
|
# BASE_URL = https://example.com/
|
||||||
# BASE_URL =
|
# BASE_URL =
|
||||||
|
|
||||||
|
# Here you MUST configure the amount above which transactions are
|
||||||
|
# always subject to manual AML review.
|
||||||
|
# AML_THRESHOLD =
|
||||||
|
|
||||||
|
# Attribute encryption key for storing attributes encrypted
|
||||||
|
# in the database. Should be a high-entropy nonce.
|
||||||
|
ATTRIBUTE_ENCRYPTION_KEY = SET_ME_PLEASE
|
||||||
|
|
||||||
# For your terms of service and privacy policy, you should specify
|
# For your terms of service and privacy policy, you should specify
|
||||||
# an Etag that must be updated whenever there are significant
|
# an Etag that must be updated whenever there are significant
|
||||||
# changes to either document. The format is up to you, what matters
|
# changes to either document. The format is up to you, what matters
|
||||||
@ -26,14 +34,17 @@ UNIXPATH_MODE = 666
|
|||||||
# Bank accounts used by the exchange should be specified here:
|
# Bank accounts used by the exchange should be specified here:
|
||||||
[exchange-account-1]
|
[exchange-account-1]
|
||||||
|
|
||||||
enable_credit = no
|
ENABLE_CREDIT = NO
|
||||||
enable_debit = no
|
ENABLE_DEBIT = NO
|
||||||
|
|
||||||
# Account identifier in the form of an RFC-8905 payto:// URI.
|
# Account identifier in the form of an RFC-8905 payto:// URI.
|
||||||
# For SEPA, looks like payto://sepa/$IBAN?receiver-name=$NAME
|
# For SEPA, looks like payto://sepa/$IBAN?receiver-name=$NAME
|
||||||
# Make sure to URL-encode spaces in $NAME!
|
# Make sure to URL-encode spaces in $NAME!
|
||||||
payto_uri =
|
PAYTO_URI =
|
||||||
|
|
||||||
# Credentials to access the account are in a separate
|
# Credentials to access the account are in a separate
|
||||||
# config file with restricted permissions.
|
# config file with restricted permissions.
|
||||||
@inline-secret@ exchange-accountcredentials-1 ../secrets/exchange-accountcredentials-1.secret.conf
|
@inline-secret@ exchange-accountcredentials-1 ../secrets/exchange-accountcredentials-1.secret.conf
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,3 +8,6 @@
|
|||||||
|
|
||||||
# Only supported database is Postgres right now.
|
# Only supported database is Postgres right now.
|
||||||
DATABASE = postgres
|
DATABASE = postgres
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ man_MANS = \
|
|||||||
prebuilt/man/taler-exchange-drain.1 \
|
prebuilt/man/taler-exchange-drain.1 \
|
||||||
prebuilt/man/taler-exchange-expire.1 \
|
prebuilt/man/taler-exchange-expire.1 \
|
||||||
prebuilt/man/taler-exchange-httpd.1 \
|
prebuilt/man/taler-exchange-httpd.1 \
|
||||||
|
prebuilt/man/taler-exchange-kyc-aml-pep-trigger.1 \
|
||||||
prebuilt/man/taler-exchange-kyc-tester.1 \
|
prebuilt/man/taler-exchange-kyc-tester.1 \
|
||||||
prebuilt/man/taler-exchange-offline.1 \
|
prebuilt/man/taler-exchange-offline.1 \
|
||||||
prebuilt/man/taler-exchange-router.1\
|
prebuilt/man/taler-exchange-router.1\
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 8452f991dd967328207fab52a99beb19e2cb4dff
|
Subproject commit 66e99d09d4351bb6e6c5fd442f14ec7cf1363a81
|
@ -213,7 +213,7 @@ main (int argc,
|
|||||||
? "Could not remove exchange from database: entry already absent\n"
|
? "Could not remove exchange from database: entry already absent\n"
|
||||||
: "Could not add exchange to database: entry already exists\n");
|
: "Could not add exchange to database: entry already exists\n");
|
||||||
TALER_AUDITORDB_plugin_unload (adb);
|
TALER_AUDITORDB_plugin_unload (adb);
|
||||||
return EXIT_FAILURE;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TALER_AUDITORDB_plugin_unload (adb);
|
TALER_AUDITORDB_plugin_unload (adb);
|
||||||
|
@ -12,6 +12,7 @@ CURRENCY_ROUND_UNIT = EUR:0.01
|
|||||||
|
|
||||||
[exchange]
|
[exchange]
|
||||||
|
|
||||||
|
AML_THRESHOLD = EUR:99999999
|
||||||
SIGNKEY_LEGAL_DURATION = 2 years
|
SIGNKEY_LEGAL_DURATION = 2 years
|
||||||
|
|
||||||
# HTTP port the exchange listens to
|
# HTTP port the exchange listens to
|
||||||
@ -50,6 +51,7 @@ HTTP_PORT = 8082
|
|||||||
SERVE = http
|
SERVE = http
|
||||||
MAX_DEBT = EUR:100000000000.0
|
MAX_DEBT = EUR:100000000000.0
|
||||||
MAX_DEBT_BANK = EUR:1000000000000000.0
|
MAX_DEBT_BANK = EUR:1000000000000000.0
|
||||||
|
DATABASE = bank-db.sqlite3
|
||||||
|
|
||||||
[benchmark]
|
[benchmark]
|
||||||
USER_PAYTO_URI = payto://x-taler-bank/localhost:8082/42
|
USER_PAYTO_URI = payto://x-taler-bank/localhost:8082/42
|
||||||
|
@ -12,6 +12,7 @@ CURRENCY_ROUND_UNIT = EUR:0.01
|
|||||||
|
|
||||||
[exchange]
|
[exchange]
|
||||||
|
|
||||||
|
AML_THRESHOLD = EUR:99999999
|
||||||
SIGNKEY_LEGAL_DURATION = 2 years
|
SIGNKEY_LEGAL_DURATION = 2 years
|
||||||
|
|
||||||
# HTTP port the exchange listens to
|
# HTTP port the exchange listens to
|
||||||
@ -50,6 +51,7 @@ HTTP_PORT = 8082
|
|||||||
SERVE = http
|
SERVE = http
|
||||||
MAX_DEBT = EUR:100000000000.0
|
MAX_DEBT = EUR:100000000000.0
|
||||||
MAX_DEBT_BANK = EUR:1000000000000000.0
|
MAX_DEBT_BANK = EUR:1000000000000000.0
|
||||||
|
DATABASE = bank-db.sqlite3
|
||||||
|
|
||||||
[benchmark]
|
[benchmark]
|
||||||
USER_PAYTO_URI = payto://x-taler-bank/localhost:8082/42
|
USER_PAYTO_URI = payto://x-taler-bank/localhost:8082/42
|
||||||
|
@ -521,7 +521,7 @@ launch_fakebank (void *cls)
|
|||||||
* @param config_file configuration file to use
|
* @param config_file configuration file to use
|
||||||
* @return #GNUNET_OK on success
|
* @return #GNUNET_OK on success
|
||||||
*/
|
*/
|
||||||
static int
|
static enum GNUNET_GenericReturnValue
|
||||||
parallel_benchmark (TALER_TESTING_Main main_cb,
|
parallel_benchmark (TALER_TESTING_Main main_cb,
|
||||||
void *main_cb_cls,
|
void *main_cb_cls,
|
||||||
const char *config_file)
|
const char *config_file)
|
||||||
@ -565,7 +565,7 @@ parallel_benchmark (TALER_TESTING_Main main_cb,
|
|||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
TALER_TESTING_prepare_bank (cfg_filename,
|
TALER_TESTING_prepare_bank (cfg_filename,
|
||||||
GNUNET_NO,
|
GNUNET_NO,
|
||||||
"exchange-account-2",
|
"exchange-account-test",
|
||||||
&bc))
|
&bc))
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
@ -1061,32 +1061,20 @@ main (int argc,
|
|||||||
}
|
}
|
||||||
if ( (MODE_EXCHANGE == mode) || (MODE_BOTH == mode) )
|
if ( (MODE_EXCHANGE == mode) || (MODE_BOTH == mode) )
|
||||||
{
|
{
|
||||||
struct GNUNET_OS_Process *compute_wire_response;
|
|
||||||
|
|
||||||
compute_wire_response
|
|
||||||
= GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL,
|
|
||||||
NULL, NULL, NULL,
|
|
||||||
"taler-exchange-wire",
|
|
||||||
"taler-exchange-wire",
|
|
||||||
"-c", cfg_filename,
|
|
||||||
NULL);
|
|
||||||
if (NULL == compute_wire_response)
|
|
||||||
{
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
|
||||||
"Failed to run `taler-exchange-wire`, is your PATH correct?\n");
|
|
||||||
GNUNET_free (cfg_filename);
|
|
||||||
return BAD_CONFIG_FILE;
|
|
||||||
}
|
|
||||||
GNUNET_OS_process_wait (compute_wire_response);
|
|
||||||
GNUNET_OS_process_destroy (compute_wire_response);
|
|
||||||
/* If we use the fakebank, we MUST reset the database as the fakebank
|
/* If we use the fakebank, we MUST reset the database as the fakebank
|
||||||
will have forgotten everything... */
|
will have forgotten everything... */
|
||||||
GNUNET_assert (GNUNET_OK ==
|
if (GNUNET_OK !=
|
||||||
TALER_TESTING_prepare_exchange (cfg_filename,
|
TALER_TESTING_prepare_exchange (cfg_filename,
|
||||||
(GNUNET_YES == use_fakebank)
|
(GNUNET_YES == use_fakebank)
|
||||||
? GNUNET_YES
|
? GNUNET_YES
|
||||||
: GNUNET_NO,
|
: GNUNET_NO,
|
||||||
&ec));
|
&ec))
|
||||||
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
|
"Failed to prepare the exchange for launch\n");
|
||||||
|
GNUNET_free (cfg_filename);
|
||||||
|
return BAD_CONFIG_FILE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -3397,14 +3397,28 @@ do_set_global_fee (char *const *args)
|
|||||||
(NULL == args[3]) ||
|
(NULL == args[3]) ||
|
||||||
(NULL == args[4]) ||
|
(NULL == args[4]) ||
|
||||||
(NULL == args[5]) ||
|
(NULL == args[5]) ||
|
||||||
(NULL == args[6]) ||
|
(NULL == args[6]) )
|
||||||
( (1 != sscanf (args[0],
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
|
"You must use YEAR, HISTORY-FEE, ACCOUNT-FEE, PURSE-FEE, PURSE-TIMEOUT, HISTORY-EXPIRATION and PURSE-ACCOUNT-LIMIT as arguments for this subcommand\n");
|
||||||
|
test_shutdown ();
|
||||||
|
global_ret = EXIT_INVALIDARGUMENT;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ( (1 != sscanf (args[0],
|
||||||
"%u%c",
|
"%u%c",
|
||||||
&year,
|
&year,
|
||||||
&dummy)) &&
|
&dummy)) &&
|
||||||
(0 != strcasecmp ("now",
|
(0 != strcasecmp ("now",
|
||||||
args[0])) ) ||
|
args[0])) )
|
||||||
(GNUNET_OK !=
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
|
"Invalid YEAR given for 'global-fee' subcommand\n");
|
||||||
|
test_shutdown ();
|
||||||
|
global_ret = EXIT_INVALIDARGUMENT;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ( (GNUNET_OK !=
|
||||||
TALER_string_to_amount (args[1],
|
TALER_string_to_amount (args[1],
|
||||||
&fees.history)) ||
|
&fees.history)) ||
|
||||||
(GNUNET_OK !=
|
(GNUNET_OK !=
|
||||||
@ -3412,20 +3426,34 @@ do_set_global_fee (char *const *args)
|
|||||||
&fees.account)) ||
|
&fees.account)) ||
|
||||||
(GNUNET_OK !=
|
(GNUNET_OK !=
|
||||||
TALER_string_to_amount (args[3],
|
TALER_string_to_amount (args[3],
|
||||||
&fees.purse)) ||
|
&fees.purse)) )
|
||||||
(GNUNET_OK !=
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
|
"Invalid amount given for 'global-fee' subcommand\n");
|
||||||
|
test_shutdown ();
|
||||||
|
global_ret = EXIT_INVALIDARGUMENT;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ( (GNUNET_OK !=
|
||||||
GNUNET_STRINGS_fancy_time_to_relative (args[4],
|
GNUNET_STRINGS_fancy_time_to_relative (args[4],
|
||||||
&purse_timeout)) ||
|
&purse_timeout)) ||
|
||||||
(GNUNET_OK !=
|
(GNUNET_OK !=
|
||||||
GNUNET_STRINGS_fancy_time_to_relative (args[5],
|
GNUNET_STRINGS_fancy_time_to_relative (args[5],
|
||||||
&history_expiration)) ||
|
&history_expiration)) )
|
||||||
(1 != sscanf (args[6],
|
|
||||||
"%u%c",
|
|
||||||
&purse_account_limit,
|
|
||||||
&dummy)) )
|
|
||||||
{
|
{
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
"You must use YEAR, HISTORY-FEE, ACCOUNT-FEE, PURSE-FEE, PURSE-TIMEOUT, HISTORY-EXPIRATION and PURSE-ACCOUNT-LIMIT as arguments for this subcommand\n");
|
"Invalid delay given for 'global-fee' subcommand\n");
|
||||||
|
test_shutdown ();
|
||||||
|
global_ret = EXIT_INVALIDARGUMENT;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (1 != sscanf (args[6],
|
||||||
|
"%u%c",
|
||||||
|
&purse_account_limit,
|
||||||
|
&dummy))
|
||||||
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
|
"Invalid purse account limit given for 'global-fee' subcommand\n");
|
||||||
test_shutdown ();
|
test_shutdown ();
|
||||||
global_ret = EXIT_INVALIDARGUMENT;
|
global_ret = EXIT_INVALIDARGUMENT;
|
||||||
return;
|
return;
|
||||||
|
@ -15,6 +15,8 @@ pkgcfg_DATA = \
|
|||||||
exchange.conf
|
exchange.conf
|
||||||
|
|
||||||
# Programs
|
# Programs
|
||||||
|
bin_SCRIPTS = \
|
||||||
|
taler-exchange-kyc-aml-pep-trigger.sh
|
||||||
|
|
||||||
bin_PROGRAMS = \
|
bin_PROGRAMS = \
|
||||||
taler-exchange-aggregator \
|
taler-exchange-aggregator \
|
||||||
@ -131,6 +133,7 @@ taler_exchange_httpd_SOURCES = \
|
|||||||
taler-exchange-httpd_age-withdraw.c taler-exchange-httpd_age-withdraw.h \
|
taler-exchange-httpd_age-withdraw.c taler-exchange-httpd_age-withdraw.h \
|
||||||
taler-exchange-httpd_age-withdraw_reveal.c taler-exchange-httpd_age-withdraw_reveal.h \
|
taler-exchange-httpd_age-withdraw_reveal.c taler-exchange-httpd_age-withdraw_reveal.h \
|
||||||
taler-exchange-httpd_common_deposit.c taler-exchange-httpd_common_deposit.h \
|
taler-exchange-httpd_common_deposit.c taler-exchange-httpd_common_deposit.h \
|
||||||
|
taler-exchange-httpd_common_kyc.c taler-exchange-httpd_common_kyc.h \
|
||||||
taler-exchange-httpd_config.c taler-exchange-httpd_config.h \
|
taler-exchange-httpd_config.c taler-exchange-httpd_config.h \
|
||||||
taler-exchange-httpd_contract.c taler-exchange-httpd_contract.h \
|
taler-exchange-httpd_contract.c taler-exchange-httpd_contract.h \
|
||||||
taler-exchange-httpd_csr.c taler-exchange-httpd_csr.h \
|
taler-exchange-httpd_csr.c taler-exchange-httpd_csr.h \
|
||||||
@ -227,4 +230,5 @@ EXTRA_DIST = \
|
|||||||
test_taler_exchange_httpd.get \
|
test_taler_exchange_httpd.get \
|
||||||
test_taler_exchange_httpd.post \
|
test_taler_exchange_httpd.post \
|
||||||
exchange.conf \
|
exchange.conf \
|
||||||
|
$(bin_SCRIPTS) \
|
||||||
$(check_SCRIPTS)
|
$(check_SCRIPTS)
|
||||||
|
@ -6,10 +6,23 @@
|
|||||||
# This must be adjusted to your actual installation.
|
# This must be adjusted to your actual installation.
|
||||||
# MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG
|
# MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG
|
||||||
|
|
||||||
|
# Must be set to the threshold above which transactions
|
||||||
|
# are flagged for AML review.
|
||||||
|
# AML_THRESHOLD =
|
||||||
|
|
||||||
|
# Specifies a program (binary) to run on KYC attribute data to decide
|
||||||
|
# whether we should immediately flag an account for AML review.
|
||||||
|
# The KYC attribute data will be passed on standard-input.
|
||||||
|
# Return non-zero to trigger AML review of the new user.
|
||||||
|
KYC_AML_TRIGGER = true
|
||||||
|
|
||||||
# Attribute encryption key for storing attributes encrypted
|
# Attribute encryption key for storing attributes encrypted
|
||||||
# in the database. Should be a high-entropy nonce.
|
# in the database. Should be a high-entropy nonce.
|
||||||
ATTRIBUTE_ENCRYPTION_KEY = SET_ME_PLEASE
|
ATTRIBUTE_ENCRYPTION_KEY = SET_ME_PLEASE
|
||||||
|
|
||||||
|
# Set to NO to disable tipping.
|
||||||
|
ENABLE_TIPPING = YES
|
||||||
|
|
||||||
# How long do we allow /keys to be cached at most? The actual
|
# How long do we allow /keys to be cached at most? The actual
|
||||||
# limit is the minimum of this value and the first expected
|
# limit is the minimum of this value and the first expected
|
||||||
# significant change in /keys based on the expiration times.
|
# significant change in /keys based on the expiration times.
|
||||||
|
@ -303,17 +303,17 @@ parse_aggregator_config (void)
|
|||||||
(TALER_amount_is_zero (¤cy_round_unit)) )
|
(TALER_amount_is_zero (¤cy_round_unit)) )
|
||||||
{
|
{
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
"Need non-zero amount in section `TALER' under `CURRENCY_ROUND_UNIT'\n");
|
"Need non-zero amount in section `taler' under `CURRENCY_ROUND_UNIT'\n");
|
||||||
return GNUNET_SYSERR;
|
return GNUNET_SYSERR;
|
||||||
}
|
}
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
TALER_config_get_amount (cfg,
|
TALER_config_get_amount (cfg,
|
||||||
"taler",
|
"exchange",
|
||||||
"AML_THRESHOLD",
|
"AML_THRESHOLD",
|
||||||
&aml_threshold))
|
&aml_threshold))
|
||||||
{
|
{
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
"Need amount in section `TALER' under `AML_THRESHOLD'\n");
|
"Need amount in section `exchange' under `AML_THRESHOLD'\n");
|
||||||
return GNUNET_SYSERR;
|
return GNUNET_SYSERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,6 +153,16 @@ struct TALER_EXCHANGEDB_Plugin *TEH_plugin;
|
|||||||
*/
|
*/
|
||||||
char *TEH_currency;
|
char *TEH_currency;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the KYC-AML-trigger evaluation binary.
|
||||||
|
*/
|
||||||
|
char *TEH_kyc_aml_trigger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Option set to #GNUNET_YES if tipping is enabled.
|
||||||
|
*/
|
||||||
|
int TEH_enable_tipping;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* What is the largest amount we allow a peer to
|
* What is the largest amount we allow a peer to
|
||||||
* merge into a reserve before always triggering
|
* merge into a reserve before always triggering
|
||||||
@ -1844,6 +1854,17 @@ exchange_serve_process_config (void)
|
|||||||
"valid relative time expected");
|
"valid relative time expected");
|
||||||
return GNUNET_SYSERR;
|
return GNUNET_SYSERR;
|
||||||
}
|
}
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
GNUNET_CONFIGURATION_get_value_string (TEH_cfg,
|
||||||
|
"exchange",
|
||||||
|
"KYC_AML_TRIGGER",
|
||||||
|
&TEH_kyc_aml_trigger))
|
||||||
|
{
|
||||||
|
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
|
||||||
|
"exchange",
|
||||||
|
"KYC_AML_TRIGGER");
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
TALER_config_get_currency (TEH_cfg,
|
TALER_config_get_currency (TEH_cfg,
|
||||||
&TEH_currency))
|
&TEH_currency))
|
||||||
@ -1855,19 +1876,30 @@ exchange_serve_process_config (void)
|
|||||||
}
|
}
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
TALER_config_get_amount (TEH_cfg,
|
TALER_config_get_amount (TEH_cfg,
|
||||||
"taler",
|
"exchange",
|
||||||
"AML_THRESHOLD",
|
"AML_THRESHOLD",
|
||||||
&TEH_aml_threshold))
|
&TEH_aml_threshold))
|
||||||
{
|
{
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
"Need amount in section `TALER' under `AML_THRESHOLD'\n");
|
"Need amount in section `exchange' under `AML_THRESHOLD'\n");
|
||||||
return GNUNET_SYSERR;
|
return GNUNET_SYSERR;
|
||||||
}
|
}
|
||||||
if (0 != strcmp (TEH_currency,
|
if (0 != strcmp (TEH_currency,
|
||||||
TEH_aml_threshold.currency))
|
TEH_aml_threshold.currency))
|
||||||
{
|
{
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
"Amount in section `TALER' under `AML_THRESHOLD' uses the wrong currency!\n");
|
"Amount in section `exchange' under `AML_THRESHOLD' uses the wrong currency!\n");
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
TEH_enable_tipping
|
||||||
|
= GNUNET_CONFIGURATION_get_value_yesno (
|
||||||
|
TEH_cfg,
|
||||||
|
"exchange",
|
||||||
|
"ENABLE_TIPPING");
|
||||||
|
if (GNUNET_SYSERR == TEH_enable_tipping)
|
||||||
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
|
"Need YES or NO in section `exchange' under `ENABLE_TIPPING'\n");
|
||||||
return GNUNET_SYSERR;
|
return GNUNET_SYSERR;
|
||||||
}
|
}
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
|
@ -64,6 +64,11 @@ extern int TEH_check_invariants_flag;
|
|||||||
*/
|
*/
|
||||||
extern int TEH_allow_keys_timetravel;
|
extern int TEH_allow_keys_timetravel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Option set to #GNUNET_YES if tipping is enabled.
|
||||||
|
*/
|
||||||
|
extern int TEH_enable_tipping;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main directory with revocation data.
|
* Main directory with revocation data.
|
||||||
*/
|
*/
|
||||||
@ -97,6 +102,11 @@ extern struct TALER_EXCHANGEDB_Plugin *TEH_plugin;
|
|||||||
*/
|
*/
|
||||||
extern char *TEH_currency;
|
extern char *TEH_currency;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the KYC-AML-trigger evaluation binary.
|
||||||
|
*/
|
||||||
|
extern char *TEH_kyc_aml_trigger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* What is the largest amount we allow a peer to
|
* What is the largest amount we allow a peer to
|
||||||
* merge into a reserve before always triggering
|
* merge into a reserve before always triggering
|
||||||
|
@ -43,8 +43,6 @@
|
|||||||
* @param[in,out] cls closure with a `json_t *` array to update
|
* @param[in,out] cls closure with a `json_t *` array to update
|
||||||
* @param h_payto account for which the attribute data is stored
|
* @param h_payto account for which the attribute data is stored
|
||||||
* @param provider_section provider that must be checked
|
* @param provider_section provider that must be checked
|
||||||
* @param birthdate birthdate of user, in format YYYY-MM-DD; can be NULL;
|
|
||||||
* digits can be 0 if exact day, month or year are unknown
|
|
||||||
* @param collection_time when was the data collected
|
* @param collection_time when was the data collected
|
||||||
* @param expiration_time when does the data expire
|
* @param expiration_time when does the data expire
|
||||||
* @param enc_attributes_size number of bytes in @a enc_attributes
|
* @param enc_attributes_size number of bytes in @a enc_attributes
|
||||||
@ -55,7 +53,6 @@ kyc_attribute_cb (
|
|||||||
void *cls,
|
void *cls,
|
||||||
const struct TALER_PaytoHashP *h_payto,
|
const struct TALER_PaytoHashP *h_payto,
|
||||||
const char *provider_section,
|
const char *provider_section,
|
||||||
const char *birthdate,
|
|
||||||
struct GNUNET_TIME_Timestamp collection_time,
|
struct GNUNET_TIME_Timestamp collection_time,
|
||||||
struct GNUNET_TIME_Timestamp expiration_time,
|
struct GNUNET_TIME_Timestamp expiration_time,
|
||||||
size_t enc_attributes_size,
|
size_t enc_attributes_size,
|
||||||
|
239
src/exchange/taler-exchange-httpd_common_kyc.c
Normal file
239
src/exchange/taler-exchange-httpd_common_kyc.c
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
/*
|
||||||
|
This file is part of TALER
|
||||||
|
Copyright (C) 2023 Taler Systems SA
|
||||||
|
|
||||||
|
TALER is free software; you can redistribute it and/or modify it under the
|
||||||
|
terms of the GNU Affero General Public License as published by the Free Software
|
||||||
|
Foundation; either version 3, or (at your option) any later version.
|
||||||
|
|
||||||
|
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License along with
|
||||||
|
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @file taler-exchange-httpd_common_kyc.c
|
||||||
|
* @brief shared logic for finishing a KYC process
|
||||||
|
* @author Christian Grothoff
|
||||||
|
*/
|
||||||
|
#include "platform.h"
|
||||||
|
#include "taler-exchange-httpd_common_kyc.h"
|
||||||
|
#include "taler_attributes.h"
|
||||||
|
#include "taler_exchangedb_plugin.h"
|
||||||
|
|
||||||
|
struct TEH_KycAmlTrigger
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Our logging scope.
|
||||||
|
*/
|
||||||
|
struct GNUNET_AsyncScopeId scope;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* account the operation is about
|
||||||
|
*/
|
||||||
|
struct TALER_PaytoHashP account_id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* until when is the KYC data valid
|
||||||
|
*/
|
||||||
|
struct GNUNET_TIME_Absolute expiration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* legitimization process the KYC data is about
|
||||||
|
*/
|
||||||
|
uint64_t process_row;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* name of the configuration section of the logic that was run
|
||||||
|
*/
|
||||||
|
char *provider_section;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set to user ID at the provider, or NULL if not supported or unknown
|
||||||
|
*/
|
||||||
|
char *provider_user_id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* provider_legitimization_id set to legitimization process ID at the provider, or NULL if not supported or unknown
|
||||||
|
*/
|
||||||
|
char *provider_legitimization_id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* function to call with the result
|
||||||
|
*/
|
||||||
|
TEH_KycAmlTriggerCallback cb;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* closure for @e cb
|
||||||
|
*/
|
||||||
|
void *cb_cls;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* user attributes returned by the provider
|
||||||
|
*/
|
||||||
|
json_t *attributes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* response to return to the HTTP client
|
||||||
|
*/
|
||||||
|
struct MHD_Response *response;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle to an external process that evaluates the
|
||||||
|
* need to run AML on the account.
|
||||||
|
*/
|
||||||
|
struct TALER_JSON_ExternalConversion *kyc_aml;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP status code of @e response
|
||||||
|
*/
|
||||||
|
unsigned int http_status;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type of a callback that receives a JSON @a result.
|
||||||
|
*
|
||||||
|
* @param cls closure of type `struct TEH_KycAmlTrigger *`
|
||||||
|
* @param status_type how did the process die
|
||||||
|
* @param code termination status code from the process
|
||||||
|
* @param result some JSON result, NULL if we failed to get an JSON output
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
kyc_aml_finished (void *cls,
|
||||||
|
enum GNUNET_OS_ProcessStatusType status_type,
|
||||||
|
unsigned long code,
|
||||||
|
const json_t *result)
|
||||||
|
{
|
||||||
|
struct TEH_KycAmlTrigger *kat = cls;
|
||||||
|
enum GNUNET_DB_QueryStatus qs;
|
||||||
|
size_t eas;
|
||||||
|
void *ea;
|
||||||
|
const char *birthdate;
|
||||||
|
unsigned int birthday;
|
||||||
|
struct GNUNET_ShortHashCode kyc_prox;
|
||||||
|
struct GNUNET_AsyncScopeSave old_scope;
|
||||||
|
|
||||||
|
kat->kyc_aml = NULL;
|
||||||
|
GNUNET_async_scope_enter (&kat->scope,
|
||||||
|
&old_scope);
|
||||||
|
TALER_CRYPTO_attributes_to_kyc_prox (kat->attributes,
|
||||||
|
&kyc_prox);
|
||||||
|
birthdate = json_string_value (json_object_get (kat->attributes,
|
||||||
|
TALER_ATTRIBUTE_BIRTHDATE));
|
||||||
|
birthday = 0; (void) birthdate; // FIXME-Oec: calculate birthday here...
|
||||||
|
// Convert 'birthdate' to time after 1970, then compute days.
|
||||||
|
// Then compare against max age-restriction, and if before, set to 0.
|
||||||
|
TALER_CRYPTO_kyc_attributes_encrypt (&TEH_attribute_key,
|
||||||
|
kat->attributes,
|
||||||
|
&ea,
|
||||||
|
&eas);
|
||||||
|
qs = TEH_plugin->insert_kyc_attributes (
|
||||||
|
TEH_plugin->cls,
|
||||||
|
kat->process_row,
|
||||||
|
&kat->account_id,
|
||||||
|
&kyc_prox,
|
||||||
|
kat->provider_section,
|
||||||
|
birthday,
|
||||||
|
GNUNET_TIME_timestamp_get (),
|
||||||
|
kat->provider_user_id,
|
||||||
|
kat->provider_legitimization_id,
|
||||||
|
kat->expiration,
|
||||||
|
eas,
|
||||||
|
ea,
|
||||||
|
0 != code);
|
||||||
|
GNUNET_free (ea);
|
||||||
|
if (GNUNET_DB_STATUS_HARD_ERROR == qs)
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
if (NULL != kat->response)
|
||||||
|
MHD_destroy_response (kat->response);
|
||||||
|
kat->http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
|
||||||
|
kat->response = TALER_MHD_make_error (TALER_EC_GENERIC_DB_STORE_FAILED,
|
||||||
|
"do_insert_kyc_attributes");
|
||||||
|
}
|
||||||
|
/* Finally, return result to main handler */
|
||||||
|
kat->cb (kat->cb_cls,
|
||||||
|
kat->http_status,
|
||||||
|
kat->response);
|
||||||
|
kat->response = NULL;
|
||||||
|
TEH_kyc_finished_cancel (kat);
|
||||||
|
GNUNET_async_scope_restore (&old_scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct TEH_KycAmlTrigger *
|
||||||
|
TEH_kyc_finished (const struct GNUNET_AsyncScopeId *scope,
|
||||||
|
uint64_t process_row,
|
||||||
|
const struct TALER_PaytoHashP *account_id,
|
||||||
|
const char *provider_section,
|
||||||
|
const char *provider_user_id,
|
||||||
|
const char *provider_legitimization_id,
|
||||||
|
struct GNUNET_TIME_Absolute expiration,
|
||||||
|
const json_t *attributes,
|
||||||
|
unsigned int http_status,
|
||||||
|
struct MHD_Response *response,
|
||||||
|
TEH_KycAmlTriggerCallback cb,
|
||||||
|
void *cb_cls)
|
||||||
|
{
|
||||||
|
struct TEH_KycAmlTrigger *kat;
|
||||||
|
|
||||||
|
kat = GNUNET_new (struct TEH_KycAmlTrigger);
|
||||||
|
kat->scope = *scope;
|
||||||
|
kat->process_row = process_row;
|
||||||
|
kat->account_id = *account_id;
|
||||||
|
kat->provider_section
|
||||||
|
= GNUNET_strdup (provider_section);
|
||||||
|
if (NULL != provider_user_id)
|
||||||
|
kat->provider_user_id
|
||||||
|
= GNUNET_strdup (provider_user_id);
|
||||||
|
if (NULL != provider_legitimization_id)
|
||||||
|
kat->provider_legitimization_id
|
||||||
|
= GNUNET_strdup (provider_legitimization_id);
|
||||||
|
kat->expiration = expiration;
|
||||||
|
kat->attributes = json_incref ((json_t*) attributes);
|
||||||
|
kat->http_status = http_status;
|
||||||
|
kat->response = response;
|
||||||
|
kat->cb = cb;
|
||||||
|
kat->cb_cls = cb_cls;
|
||||||
|
kat->kyc_aml
|
||||||
|
= TALER_JSON_external_conversion_start (
|
||||||
|
attributes,
|
||||||
|
&kyc_aml_finished,
|
||||||
|
kat,
|
||||||
|
TEH_kyc_aml_trigger,
|
||||||
|
TEH_kyc_aml_trigger,
|
||||||
|
NULL);
|
||||||
|
if (NULL == kat->kyc_aml)
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
TEH_kyc_finished_cancel (kat);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return kat;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TEH_kyc_finished_cancel (struct TEH_KycAmlTrigger *kat)
|
||||||
|
{
|
||||||
|
if (NULL != kat->kyc_aml)
|
||||||
|
{
|
||||||
|
TALER_JSON_external_conversion_stop (kat->kyc_aml);
|
||||||
|
kat->kyc_aml = NULL;
|
||||||
|
}
|
||||||
|
GNUNET_free (kat->provider_section);
|
||||||
|
GNUNET_free (kat->provider_user_id);
|
||||||
|
GNUNET_free (kat->provider_legitimization_id);
|
||||||
|
json_decref (kat->attributes);
|
||||||
|
if (NULL != kat->response)
|
||||||
|
{
|
||||||
|
MHD_destroy_response (kat->response);
|
||||||
|
kat->response = NULL;
|
||||||
|
}
|
||||||
|
GNUNET_free (kat);
|
||||||
|
}
|
99
src/exchange/taler-exchange-httpd_common_kyc.h
Normal file
99
src/exchange/taler-exchange-httpd_common_kyc.h
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
This file is part of TALER
|
||||||
|
Copyright (C) 2023 Taler Systems SA
|
||||||
|
|
||||||
|
TALER is free software; you can redistribute it and/or modify it under the
|
||||||
|
terms of the GNU Affero General Public License as published by the Free Software
|
||||||
|
Foundation; either version 3, or (at your option) any later version.
|
||||||
|
|
||||||
|
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License along with
|
||||||
|
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @file taler-exchange-httpd_common_kyc.h
|
||||||
|
* @brief shared logic for finishing a KYC process
|
||||||
|
* @author Christian Grothoff
|
||||||
|
*/
|
||||||
|
#ifndef TALER_EXCHANGE_HTTPD_COMMON_KYC_H
|
||||||
|
#define TALER_EXCHANGE_HTTPD_COMMON_KYC_H
|
||||||
|
|
||||||
|
#include <gnunet/gnunet_util_lib.h>
|
||||||
|
#include <gnunet/gnunet_json_lib.h>
|
||||||
|
#include <jansson.h>
|
||||||
|
#include <microhttpd.h>
|
||||||
|
#include "taler_json_lib.h"
|
||||||
|
#include "taler_mhd_lib.h"
|
||||||
|
#include "taler-exchange-httpd.h"
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function called after the KYC-AML trigger is done.
|
||||||
|
*
|
||||||
|
* @param cls closure
|
||||||
|
* @param http_status final HTTP status to return
|
||||||
|
* @param[in] response final HTTP ro return
|
||||||
|
*/
|
||||||
|
typedef void
|
||||||
|
(*TEH_KycAmlTriggerCallback) (
|
||||||
|
void *cls,
|
||||||
|
unsigned int http_status,
|
||||||
|
struct MHD_Response *response);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle for an asynchronous operation to finish
|
||||||
|
* a KYC process after running the AML trigger.
|
||||||
|
*/
|
||||||
|
struct TEH_KycAmlTrigger;
|
||||||
|
|
||||||
|
// FIXME: also pass async log context and set it!
|
||||||
|
/**
|
||||||
|
* We have finished a KYC process and obtained new
|
||||||
|
* @a attributes for a given @a account_id.
|
||||||
|
* Check with the KYC-AML trigger to see if we need
|
||||||
|
* to initiate an AML process, and store the attributes
|
||||||
|
* in the database. Then call @a cb.
|
||||||
|
*
|
||||||
|
* @param scope the HTTP request logging scope
|
||||||
|
* @param process_row legitimization process the webhook was about
|
||||||
|
* @param account_id account the webhook was about
|
||||||
|
* @param provider_section name of the configuration section of the logic that was run
|
||||||
|
* @param provider_user_id set to user ID at the provider, or NULL if not supported or unknown
|
||||||
|
* @param provider_legitimization_id set to legitimization process ID at the provider, or NULL if not supported or unknown
|
||||||
|
* @param expiration until when is the KYC check valid
|
||||||
|
* @param attributes user attributes returned by the provider
|
||||||
|
* @param http_status HTTP status code of @a response
|
||||||
|
* @param[in] response to return to the HTTP client
|
||||||
|
* @param cb function to call with the result
|
||||||
|
* @param cb_cls closure for @a cb
|
||||||
|
* @return handle to cancel the operation
|
||||||
|
*/
|
||||||
|
struct TEH_KycAmlTrigger *
|
||||||
|
TEH_kyc_finished (const struct GNUNET_AsyncScopeId *scope,
|
||||||
|
uint64_t process_row,
|
||||||
|
const struct TALER_PaytoHashP *account_id,
|
||||||
|
const char *provider_section,
|
||||||
|
const char *provider_user_id,
|
||||||
|
const char *provider_legitimization_id,
|
||||||
|
struct GNUNET_TIME_Absolute expiration,
|
||||||
|
const json_t *attributes,
|
||||||
|
unsigned int http_status,
|
||||||
|
struct MHD_Response *response,
|
||||||
|
TEH_KycAmlTriggerCallback cb,
|
||||||
|
void *cb_cls);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancel KYC finish operation.
|
||||||
|
*
|
||||||
|
* @param[in] kat operation to abort
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
TEH_kyc_finished_cancel (struct TEH_KycAmlTrigger *kat);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
@ -1857,6 +1857,8 @@ create_krd (struct TEH_KeyStateHandle *ksh,
|
|||||||
TEH_currency),
|
TEH_currency),
|
||||||
GNUNET_JSON_pack_string ("asset_type",
|
GNUNET_JSON_pack_string ("asset_type",
|
||||||
asset_type),
|
asset_type),
|
||||||
|
GNUNET_JSON_pack_bool ("tipping_allowed",
|
||||||
|
GNUNET_YES == TEH_enable_tipping),
|
||||||
GNUNET_JSON_pack_data_auto ("master_public_key",
|
GNUNET_JSON_pack_data_auto ("master_public_key",
|
||||||
&TEH_master_public_key),
|
&TEH_master_public_key),
|
||||||
GNUNET_JSON_pack_time_rel ("reserve_closing_delay",
|
GNUNET_JSON_pack_time_rel ("reserve_closing_delay",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
This file is part of TALER
|
This file is part of TALER
|
||||||
Copyright (C) 2021-2022 Taler Systems SA
|
Copyright (C) 2021-2023 Taler Systems SA
|
||||||
|
|
||||||
TALER is free software; you can redistribute it and/or modify it under the
|
TALER is free software; you can redistribute it and/or modify it under the
|
||||||
terms of the GNU Affero General Public License as published by the Free Software
|
terms of the GNU Affero General Public License as published by the Free Software
|
||||||
@ -23,11 +23,11 @@
|
|||||||
#include <gnunet/gnunet_json_lib.h>
|
#include <gnunet/gnunet_json_lib.h>
|
||||||
#include <jansson.h>
|
#include <jansson.h>
|
||||||
#include <microhttpd.h>
|
#include <microhttpd.h>
|
||||||
#include <pthread.h>
|
|
||||||
#include "taler_attributes.h"
|
#include "taler_attributes.h"
|
||||||
#include "taler_json_lib.h"
|
#include "taler_json_lib.h"
|
||||||
#include "taler_kyclogic_lib.h"
|
#include "taler_kyclogic_lib.h"
|
||||||
#include "taler_mhd_lib.h"
|
#include "taler_mhd_lib.h"
|
||||||
|
#include "taler-exchange-httpd_common_kyc.h"
|
||||||
#include "taler-exchange-httpd_kyc-proof.h"
|
#include "taler-exchange-httpd_kyc-proof.h"
|
||||||
#include "taler-exchange-httpd_responses.h"
|
#include "taler-exchange-httpd_responses.h"
|
||||||
|
|
||||||
@ -68,6 +68,11 @@ struct KycProofContext
|
|||||||
*/
|
*/
|
||||||
struct TALER_KYCLOGIC_ProofHandle *ph;
|
struct TALER_KYCLOGIC_ProofHandle *ph;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* KYC AML trigger operation.
|
||||||
|
*/
|
||||||
|
struct TEH_KycAmlTrigger *kat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process information about the user for the plugin from the database, can
|
* Process information about the user for the plugin from the database, can
|
||||||
* be NULL.
|
* be NULL.
|
||||||
@ -159,6 +164,28 @@ TEH_kyc_proof_cleanup (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function called after the KYC-AML trigger is done.
|
||||||
|
*
|
||||||
|
* @param cls closure
|
||||||
|
* @param http_status final HTTP status to return
|
||||||
|
* @param[in] response final HTTP ro return
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
proof_finish (
|
||||||
|
void *cls,
|
||||||
|
unsigned int http_status,
|
||||||
|
struct MHD_Response *response)
|
||||||
|
{
|
||||||
|
struct KycProofContext *kpc = cls;
|
||||||
|
|
||||||
|
kpc->kat = NULL;
|
||||||
|
kpc->response_code = http_status;
|
||||||
|
kpc->response = response;
|
||||||
|
kpc_resume (kpc);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function called with the result of a proof check operation.
|
* Function called with the result of a proof check operation.
|
||||||
*
|
*
|
||||||
@ -192,74 +219,40 @@ proof_cb (
|
|||||||
kpc->ph = NULL;
|
kpc->ph = NULL;
|
||||||
GNUNET_async_scope_enter (&rc->async_scope_id,
|
GNUNET_async_scope_enter (&rc->async_scope_id,
|
||||||
&old_scope);
|
&old_scope);
|
||||||
|
|
||||||
if (TALER_KYCLOGIC_STATUS_SUCCESS == status)
|
if (TALER_KYCLOGIC_STATUS_SUCCESS == status)
|
||||||
{
|
{
|
||||||
enum GNUNET_DB_QueryStatus qs;
|
kpc->kat = TEH_kyc_finished (&rc->async_scope_id,
|
||||||
size_t eas;
|
|
||||||
void *ea;
|
|
||||||
const char *birthdate;
|
|
||||||
struct GNUNET_ShortHashCode kyc_prox;
|
|
||||||
|
|
||||||
TALER_CRYPTO_attributes_to_kyc_prox (attributes,
|
|
||||||
&kyc_prox);
|
|
||||||
birthdate = json_string_value (json_object_get (attributes,
|
|
||||||
TALER_ATTRIBUTE_BIRTHDATE));
|
|
||||||
TALER_CRYPTO_kyc_attributes_encrypt (&TEH_attribute_key,
|
|
||||||
attributes,
|
|
||||||
&ea,
|
|
||||||
&eas);
|
|
||||||
qs = TEH_plugin->insert_kyc_attributes (
|
|
||||||
TEH_plugin->cls,
|
|
||||||
&kpc->h_payto,
|
|
||||||
&kyc_prox,
|
|
||||||
kpc->provider_section,
|
|
||||||
birthdate,
|
|
||||||
GNUNET_TIME_timestamp_get (),
|
|
||||||
GNUNET_TIME_absolute_to_timestamp (expiration),
|
|
||||||
eas,
|
|
||||||
ea);
|
|
||||||
GNUNET_free (ea);
|
|
||||||
if (GNUNET_DB_STATUS_HARD_ERROR == qs)
|
|
||||||
{
|
|
||||||
GNUNET_break (0);
|
|
||||||
if (NULL != response)
|
|
||||||
MHD_destroy_response (response);
|
|
||||||
kpc->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
|
|
||||||
kpc->response = TALER_MHD_make_error (TALER_EC_GENERIC_DB_STORE_FAILED,
|
|
||||||
"insert_kyc_attributes");
|
|
||||||
GNUNET_async_scope_restore (&old_scope);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
qs = TEH_plugin->update_kyc_process_by_row (TEH_plugin->cls,
|
|
||||||
kpc->process_row,
|
kpc->process_row,
|
||||||
kpc->provider_section,
|
|
||||||
&kpc->h_payto,
|
&kpc->h_payto,
|
||||||
|
kpc->provider_section,
|
||||||
provider_user_id,
|
provider_user_id,
|
||||||
provider_legitimization_id,
|
provider_legitimization_id,
|
||||||
expiration);
|
expiration,
|
||||||
if (GNUNET_DB_STATUS_HARD_ERROR == qs)
|
attributes,
|
||||||
|
http_status,
|
||||||
|
response,
|
||||||
|
&proof_finish,
|
||||||
|
kpc);
|
||||||
|
if (NULL == kpc->kat)
|
||||||
{
|
{
|
||||||
GNUNET_break (0);
|
http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
|
||||||
if (NULL != response)
|
if (NULL != response)
|
||||||
MHD_destroy_response (response);
|
MHD_destroy_response (response);
|
||||||
kpc->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
|
response = TALER_MHD_make_error (
|
||||||
kpc->response = TALER_MHD_make_error (TALER_EC_GENERIC_DB_STORE_FAILED,
|
TALER_EC_EXCHANGE_GENERIC_BAD_CONFIGURATION,
|
||||||
"set_kyc_ok");
|
"[exchange] AML_KYC_TRIGGER");
|
||||||
GNUNET_async_scope_restore (&old_scope);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
if (NULL == kpc->kat)
|
||||||
{
|
{
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||||
"KYC process #%llu failed with status %d\n",
|
"KYC process #%llu failed with status %d\n",
|
||||||
(unsigned long long) kpc->process_row,
|
(unsigned long long) kpc->process_row,
|
||||||
status);
|
status);
|
||||||
|
proof_finish (kpc,
|
||||||
|
http_status,
|
||||||
|
response);
|
||||||
}
|
}
|
||||||
kpc->response_code = http_status;
|
|
||||||
kpc->response = response;
|
|
||||||
kpc_resume (kpc);
|
|
||||||
GNUNET_async_scope_restore (&old_scope);
|
GNUNET_async_scope_restore (&old_scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -279,6 +272,11 @@ clean_kpc (struct TEH_RequestContext *rc)
|
|||||||
kpc->logic->proof_cancel (kpc->ph);
|
kpc->logic->proof_cancel (kpc->ph);
|
||||||
kpc->ph = NULL;
|
kpc->ph = NULL;
|
||||||
}
|
}
|
||||||
|
if (NULL != kpc->kat)
|
||||||
|
{
|
||||||
|
TEH_kyc_finished_cancel (kpc->kat);
|
||||||
|
kpc->kat = NULL;
|
||||||
|
}
|
||||||
if (NULL != kpc->response)
|
if (NULL != kpc->response)
|
||||||
{
|
{
|
||||||
MHD_destroy_response (kpc->response);
|
MHD_destroy_response (kpc->response);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
This file is part of TALER
|
This file is part of TALER
|
||||||
Copyright (C) 2022 Taler Systems SA
|
Copyright (C) 2022-2023 Taler Systems SA
|
||||||
|
|
||||||
TALER is free software; you can redistribute it and/or modify it under the
|
TALER is free software; you can redistribute it and/or modify it under the
|
||||||
terms of the GNU Affero General Public License as published by the Free Software
|
terms of the GNU Affero General Public License as published by the Free Software
|
||||||
@ -28,6 +28,7 @@
|
|||||||
#include "taler_json_lib.h"
|
#include "taler_json_lib.h"
|
||||||
#include "taler_mhd_lib.h"
|
#include "taler_mhd_lib.h"
|
||||||
#include "taler_kyclogic_lib.h"
|
#include "taler_kyclogic_lib.h"
|
||||||
|
#include "taler-exchange-httpd_common_kyc.h"
|
||||||
#include "taler-exchange-httpd_kyc-webhook.h"
|
#include "taler-exchange-httpd_kyc-webhook.h"
|
||||||
#include "taler-exchange-httpd_responses.h"
|
#include "taler-exchange-httpd_responses.h"
|
||||||
|
|
||||||
@ -53,6 +54,11 @@ struct KycWebhookContext
|
|||||||
*/
|
*/
|
||||||
struct TEH_RequestContext *rc;
|
struct TEH_RequestContext *rc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle for the KYC-AML trigger interaction.
|
||||||
|
*/
|
||||||
|
struct TEH_KycAmlTrigger *kat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Plugin responsible for the webhook.
|
* Plugin responsible for the webhook.
|
||||||
*/
|
*/
|
||||||
@ -140,6 +146,28 @@ TEH_kyc_webhook_cleanup (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function called after the KYC-AML trigger is done.
|
||||||
|
*
|
||||||
|
* @param cls closure with a `struct KycWebhookContext *`
|
||||||
|
* @param http_status final HTTP status to return
|
||||||
|
* @param[in] response final HTTP ro return
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
kyc_aml_webhook_finished (
|
||||||
|
void *cls,
|
||||||
|
unsigned int http_status,
|
||||||
|
struct MHD_Response *response)
|
||||||
|
{
|
||||||
|
struct KycWebhookContext *kwh = cls;
|
||||||
|
|
||||||
|
kwh->kat = NULL;
|
||||||
|
kwh->response = response;
|
||||||
|
kwh->response_code = http_status;
|
||||||
|
kwh_resume (kwh);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function called with the result of a KYC webhook operation.
|
* Function called with the result of a KYC webhook operation.
|
||||||
*
|
*
|
||||||
@ -178,58 +206,27 @@ webhook_finished_cb (
|
|||||||
switch (status)
|
switch (status)
|
||||||
{
|
{
|
||||||
case TALER_KYCLOGIC_STATUS_SUCCESS:
|
case TALER_KYCLOGIC_STATUS_SUCCESS:
|
||||||
/* _successfully_ resumed case */
|
kwh->kat = TEH_kyc_finished (
|
||||||
{
|
&kwh->rc->async_scope_id,
|
||||||
enum GNUNET_DB_QueryStatus qs;
|
|
||||||
size_t eas;
|
|
||||||
void *ea;
|
|
||||||
const char *birthdate;
|
|
||||||
struct GNUNET_ShortHashCode kyc_prox;
|
|
||||||
|
|
||||||
TALER_CRYPTO_attributes_to_kyc_prox (attributes,
|
|
||||||
&kyc_prox);
|
|
||||||
birthdate = json_string_value (json_object_get (attributes,
|
|
||||||
TALER_ATTRIBUTE_BIRTHDATE));
|
|
||||||
TALER_CRYPTO_kyc_attributes_encrypt (&TEH_attribute_key,
|
|
||||||
attributes,
|
|
||||||
&ea,
|
|
||||||
&eas);
|
|
||||||
qs = TEH_plugin->insert_kyc_attributes (
|
|
||||||
TEH_plugin->cls,
|
|
||||||
account_id,
|
|
||||||
&kyc_prox,
|
|
||||||
provider_section,
|
|
||||||
birthdate,
|
|
||||||
GNUNET_TIME_timestamp_get (),
|
|
||||||
GNUNET_TIME_absolute_to_timestamp (expiration),
|
|
||||||
eas,
|
|
||||||
ea);
|
|
||||||
GNUNET_free (ea);
|
|
||||||
if (qs < 0)
|
|
||||||
{
|
|
||||||
GNUNET_break (0);
|
|
||||||
kwh->response = TALER_MHD_make_error (TALER_EC_GENERIC_DB_STORE_FAILED,
|
|
||||||
"insert_kyc_attributes");
|
|
||||||
kwh->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
|
|
||||||
kwh_resume (kwh);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
qs = TEH_plugin->update_kyc_process_by_row (TEH_plugin->cls,
|
|
||||||
process_row,
|
process_row,
|
||||||
provider_section,
|
|
||||||
account_id,
|
account_id,
|
||||||
|
provider_section,
|
||||||
provider_user_id,
|
provider_user_id,
|
||||||
provider_legitimization_id,
|
provider_legitimization_id,
|
||||||
expiration);
|
expiration,
|
||||||
if (qs < 0)
|
attributes,
|
||||||
|
http_status,
|
||||||
|
response,
|
||||||
|
&kyc_aml_webhook_finished,
|
||||||
|
kwh);
|
||||||
|
if (NULL == kwh->kat)
|
||||||
{
|
{
|
||||||
GNUNET_break (0);
|
http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
|
||||||
kwh->response = TALER_MHD_make_error (TALER_EC_GENERIC_DB_STORE_FAILED,
|
if (NULL != response)
|
||||||
"set_kyc_ok");
|
MHD_destroy_response (response);
|
||||||
kwh->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
|
response = TALER_MHD_make_error (
|
||||||
kwh_resume (kwh);
|
TALER_EC_EXCHANGE_GENERIC_BAD_CONFIGURATION,
|
||||||
return;
|
"[exchange] AML_KYC_TRIGGER");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -241,9 +238,10 @@ webhook_finished_cb (
|
|||||||
status);
|
status);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
kwh->response = response;
|
if (NULL == kwh->kat)
|
||||||
kwh->response_code = http_status;
|
kyc_aml_webhook_finished (kwh,
|
||||||
kwh_resume (kwh);
|
http_status,
|
||||||
|
response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -262,6 +260,11 @@ clean_kwh (struct TEH_RequestContext *rc)
|
|||||||
kwh->plugin->webhook_cancel (kwh->wh);
|
kwh->plugin->webhook_cancel (kwh->wh);
|
||||||
kwh->wh = NULL;
|
kwh->wh = NULL;
|
||||||
}
|
}
|
||||||
|
if (NULL != kwh->kat)
|
||||||
|
{
|
||||||
|
TEH_kyc_finished_cancel (kwh->kat);
|
||||||
|
kwh->kat = NULL;
|
||||||
|
}
|
||||||
if (NULL != kwh->response)
|
if (NULL != kwh->response)
|
||||||
{
|
{
|
||||||
MHD_destroy_response (kwh->response);
|
MHD_destroy_response (kwh->response);
|
||||||
|
@ -158,8 +158,6 @@ reply_reserve_attest_success (struct MHD_Connection *connection,
|
|||||||
* @param cls our `struct ReserveAttestContext *`
|
* @param cls our `struct ReserveAttestContext *`
|
||||||
* @param h_payto account for which the attribute data is stored
|
* @param h_payto account for which the attribute data is stored
|
||||||
* @param provider_section provider that must be checked
|
* @param provider_section provider that must be checked
|
||||||
* @param birthdate birthdate of user, in format YYYY-MM-DD; can be NULL;
|
|
||||||
* digits can be 0 if exact day, month or year are unknown
|
|
||||||
* @param collection_time when was the data collected
|
* @param collection_time when was the data collected
|
||||||
* @param expiration_time when does the data expire
|
* @param expiration_time when does the data expire
|
||||||
* @param enc_attributes_size number of bytes in @a enc_attributes
|
* @param enc_attributes_size number of bytes in @a enc_attributes
|
||||||
@ -169,7 +167,6 @@ static void
|
|||||||
kyc_process_cb (void *cls,
|
kyc_process_cb (void *cls,
|
||||||
const struct TALER_PaytoHashP *h_payto,
|
const struct TALER_PaytoHashP *h_payto,
|
||||||
const char *provider_section,
|
const char *provider_section,
|
||||||
const char *birthdate,
|
|
||||||
struct GNUNET_TIME_Timestamp collection_time,
|
struct GNUNET_TIME_Timestamp collection_time,
|
||||||
struct GNUNET_TIME_Timestamp expiration_time,
|
struct GNUNET_TIME_Timestamp expiration_time,
|
||||||
size_t enc_attributes_size,
|
size_t enc_attributes_size,
|
||||||
|
@ -64,8 +64,6 @@ struct ReserveAttestContext
|
|||||||
* @param cls our `struct ReserveAttestContext *`
|
* @param cls our `struct ReserveAttestContext *`
|
||||||
* @param h_payto account for which the attribute data is stored
|
* @param h_payto account for which the attribute data is stored
|
||||||
* @param provider_section provider that must be checked
|
* @param provider_section provider that must be checked
|
||||||
* @param birthdate birthdate of user, in format YYYY-MM-DD; can be NULL;
|
|
||||||
* digits can be 0 if exact day, month or year are unknown
|
|
||||||
* @param collection_time when was the data collected
|
* @param collection_time when was the data collected
|
||||||
* @param expiration_time when does the data expire
|
* @param expiration_time when does the data expire
|
||||||
* @param enc_attributes_size number of bytes in @a enc_attributes
|
* @param enc_attributes_size number of bytes in @a enc_attributes
|
||||||
@ -75,7 +73,6 @@ static void
|
|||||||
kyc_process_cb (void *cls,
|
kyc_process_cb (void *cls,
|
||||||
const struct TALER_PaytoHashP *h_payto,
|
const struct TALER_PaytoHashP *h_payto,
|
||||||
const char *provider_section,
|
const char *provider_section,
|
||||||
const char *birthdate,
|
|
||||||
struct GNUNET_TIME_Timestamp collection_time,
|
struct GNUNET_TIME_Timestamp collection_time,
|
||||||
struct GNUNET_TIME_Timestamp expiration_time,
|
struct GNUNET_TIME_Timestamp expiration_time,
|
||||||
size_t enc_attributes_size,
|
size_t enc_attributes_size,
|
||||||
|
7
src/exchange/taler-exchange-kyc-aml-pep-trigger.sh
Executable file
7
src/exchange/taler-exchange-kyc-aml-pep-trigger.sh
Executable file
@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# This file is in the public domain.
|
||||||
|
# This is an example of how to trigger AML if the
|
||||||
|
# KYC attributes include '{"pep":true}'
|
||||||
|
#
|
||||||
|
# To be used as a script for the KYC_AML_TRIGGER.
|
||||||
|
test "false" = $(jq .pep -)
|
@ -7,13 +7,14 @@ TALER_RUNTIME_DIR = ${TMPDIR:-${TMP:-/tmp}}/${USER:-}/taler-system-runtime/
|
|||||||
# Currency supported by the exchange (can only be one)
|
# Currency supported by the exchange (can only be one)
|
||||||
CURRENCY = EUR
|
CURRENCY = EUR
|
||||||
CURRENCY_ROUND_UNIT = EUR:0.01
|
CURRENCY_ROUND_UNIT = EUR:0.01
|
||||||
AML_THRESHOLD = EUR:1000000
|
|
||||||
|
|
||||||
[auditor]
|
[auditor]
|
||||||
TINY_AMOUNT = EUR:0.01
|
TINY_AMOUNT = EUR:0.01
|
||||||
|
|
||||||
[exchange]
|
[exchange]
|
||||||
|
|
||||||
|
AML_THRESHOLD = EUR:1000000
|
||||||
|
|
||||||
# Directory with our terms of service.
|
# Directory with our terms of service.
|
||||||
TERMS_DIR = ../../contrib/tos
|
TERMS_DIR = ../../contrib/tos
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ BEGIN
|
|||||||
',current_balance_frac INT4 NOT NULL DEFAULT(0)'
|
',current_balance_frac INT4 NOT NULL DEFAULT(0)'
|
||||||
',purses_active INT8 NOT NULL DEFAULT(0)'
|
',purses_active INT8 NOT NULL DEFAULT(0)'
|
||||||
',purses_allowed INT8 NOT NULL DEFAULT(0)'
|
',purses_allowed INT8 NOT NULL DEFAULT(0)'
|
||||||
',max_age INT4 NOT NULL DEFAULT(120)'
|
',max_age INT4 NOT NULL DEFAULT(0)'
|
||||||
',expiration_date INT8 NOT NULL'
|
',expiration_date INT8 NOT NULL'
|
||||||
',gc_date INT8 NOT NULL'
|
',gc_date INT8 NOT NULL'
|
||||||
') %s ;'
|
') %s ;'
|
||||||
@ -80,6 +80,12 @@ BEGIN
|
|||||||
,table_name
|
,table_name
|
||||||
,partition_suffix
|
,partition_suffix
|
||||||
);
|
);
|
||||||
|
PERFORM comment_partitioned_column(
|
||||||
|
'Birthday of the user in days after 1970, or 0 if user is an adult and is not subject to age restrictions'
|
||||||
|
,'max_age'
|
||||||
|
,table_name
|
||||||
|
,partition_suffix
|
||||||
|
);
|
||||||
END
|
END
|
||||||
$$;
|
$$;
|
||||||
|
|
||||||
|
44
src/exchangedb/0004-kyc_attributes.sql
Normal file
44
src/exchangedb/0004-kyc_attributes.sql
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
--
|
||||||
|
-- This file is part of TALER
|
||||||
|
-- Copyright (C) 2023 Taler Systems SA
|
||||||
|
--
|
||||||
|
-- TALER is free software; you can redistribute it and/or modify it under the
|
||||||
|
-- terms of the GNU General Public License as published by the Free Software
|
||||||
|
-- Foundation; either version 3, or (at your option) any later version.
|
||||||
|
--
|
||||||
|
-- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||||
|
-- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
--
|
||||||
|
-- You should have received a copy of the GNU General Public License along with
|
||||||
|
-- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION master_table_kyc_attributes_V2()
|
||||||
|
RETURNS VOID
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $$
|
||||||
|
DECLARE
|
||||||
|
table_name VARCHAR DEFAULT 'kyc_attributes';
|
||||||
|
BEGIN
|
||||||
|
EXECUTE FORMAT (
|
||||||
|
'ALTER TABLE ' || table_name ||
|
||||||
|
' DROP COLUMN birthdate;'
|
||||||
|
);
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
COMMENT ON FUNCTION master_table_kyc_attributes_V2
|
||||||
|
IS 'Removes birthdate column from the kyc_attributes table';
|
||||||
|
|
||||||
|
INSERT INTO exchange_tables
|
||||||
|
(name
|
||||||
|
,version
|
||||||
|
,action
|
||||||
|
,partitioned
|
||||||
|
,by_range)
|
||||||
|
VALUES
|
||||||
|
('kyc_attributes_V2'
|
||||||
|
,'exchange-0004'
|
||||||
|
,'master'
|
||||||
|
,TRUE
|
||||||
|
,FALSE);
|
@ -144,7 +144,6 @@ libtaler_plugin_exchangedb_postgres_la_SOURCES = \
|
|||||||
pg_aggregate.h pg_aggregate.c \
|
pg_aggregate.h pg_aggregate.c \
|
||||||
pg_create_aggregation_transient.h pg_create_aggregation_transient.c \
|
pg_create_aggregation_transient.h pg_create_aggregation_transient.c \
|
||||||
pg_insert_kyc_attributes.h pg_insert_kyc_attributes.c \
|
pg_insert_kyc_attributes.h pg_insert_kyc_attributes.c \
|
||||||
pg_update_kyc_attributes.h pg_update_kyc_attributes.c \
|
|
||||||
pg_select_similar_kyc_attributes.h pg_select_similar_kyc_attributes.c \
|
pg_select_similar_kyc_attributes.h pg_select_similar_kyc_attributes.c \
|
||||||
pg_select_kyc_attributes.h pg_select_kyc_attributes.c \
|
pg_select_kyc_attributes.h pg_select_kyc_attributes.c \
|
||||||
pg_insert_aml_officer.h pg_insert_aml_officer.c \
|
pg_insert_aml_officer.h pg_insert_aml_officer.c \
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
--
|
--
|
||||||
-- This file is part of TALER
|
-- This file is part of TALER
|
||||||
-- Copyright (C) 2014--2023 Taler Systems SA
|
-- Copyright (C) 2023 Taler Systems SA
|
||||||
--
|
--
|
||||||
-- TALER is free software; you can redistribute it and/or modify it under the
|
-- TALER is free software; you can redistribute it and/or modify it under the
|
||||||
-- terms of the GNU General Public License as published by the Free Software
|
-- terms of the GNU General Public License as published by the Free Software
|
||||||
@ -19,6 +19,7 @@ BEGIN;
|
|||||||
SELECT _v.register_patch('exchange-0004', NULL, NULL);
|
SELECT _v.register_patch('exchange-0004', NULL, NULL);
|
||||||
SET search_path TO exchange;
|
SET search_path TO exchange;
|
||||||
|
|
||||||
|
#include "0004-kyc_attributes.sql"
|
||||||
#include "0004-wire_accounts.sql"
|
#include "0004-wire_accounts.sql"
|
||||||
|
|
||||||
COMMIT;
|
COMMIT;
|
||||||
|
92
src/exchangedb/exchange_do_insert_kyc_attributes.sql
Normal file
92
src/exchangedb/exchange_do_insert_kyc_attributes.sql
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
--
|
||||||
|
-- This file is part of TALER
|
||||||
|
-- Copyright (C) 2023 Taler Systems SA
|
||||||
|
--
|
||||||
|
-- TALER is free software; you can redistribute it and/or modify it under the
|
||||||
|
-- terms of the GNU General Public License as published by the Free Software
|
||||||
|
-- Foundation; either version 3, or (at your option) any later version.
|
||||||
|
--
|
||||||
|
-- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||||
|
-- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
--
|
||||||
|
-- You should have received a copy of the GNU General Public License along with
|
||||||
|
-- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION exchange_do_insert_kyc_attributes(
|
||||||
|
IN in_process_row INT8,
|
||||||
|
IN in_h_payto BYTEA,
|
||||||
|
IN in_kyc_prox BYTEA,
|
||||||
|
IN in_provider_section VARCHAR,
|
||||||
|
IN in_birthday INT4,
|
||||||
|
IN in_provider_account_id VARCHAR,
|
||||||
|
IN in_provider_legitimization_id VARCHAR,
|
||||||
|
IN in_collection_time_ts INT8,
|
||||||
|
IN in_expiration_time INT8,
|
||||||
|
IN in_expiration_time_ts INT8,
|
||||||
|
IN in_enc_attributes BYTEA,
|
||||||
|
IN in_require_aml BOOLEAN,
|
||||||
|
IN in_kyc_completed_notify_s VARCHAR,
|
||||||
|
OUT out_ok BOOLEAN)
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $$
|
||||||
|
BEGIN
|
||||||
|
|
||||||
|
INSERT INTO exchange.kyc_attributes
|
||||||
|
(h_payto
|
||||||
|
,kyc_prox
|
||||||
|
,provider
|
||||||
|
,collection_time
|
||||||
|
,expiration_time
|
||||||
|
,encrypted_attributes
|
||||||
|
) VALUES
|
||||||
|
(in_h_payto
|
||||||
|
,in_kyc_prox
|
||||||
|
,in_provider_section
|
||||||
|
,in_collection_time_ts
|
||||||
|
,in_expiration_time_ts
|
||||||
|
,in_enc_attributes);
|
||||||
|
|
||||||
|
-- FIXME-Oec: modify to 'return' the reserve_pub here
|
||||||
|
-- (requires of course to modify other code to store
|
||||||
|
-- the reserve pub in the right table in the first place)
|
||||||
|
UPDATE exchange.legitimization_processes
|
||||||
|
SET provider_user_id=in_provider_account_id
|
||||||
|
,provider_legitimization_id=in_provider_legitimization_id
|
||||||
|
,expiration_time=GREATEST(expiration_time,in_expiration_time)
|
||||||
|
WHERE h_payto=in_h_payto
|
||||||
|
AND legitimization_process_serial_id=in_process_row
|
||||||
|
AND provider_section=in_provider_section;
|
||||||
|
out_ok = FOUND;
|
||||||
|
|
||||||
|
-- FIXME-Oec: update exchange reserve table to store in_birthday here!
|
||||||
|
-- UPDATE exchange.reserves SET max_age=in_birthday WHERE reserve_pub=X;
|
||||||
|
|
||||||
|
IF in_require_aml
|
||||||
|
THEN
|
||||||
|
INSERT INTO exchange.aml_status
|
||||||
|
(h_payto
|
||||||
|
,status)
|
||||||
|
VALUES
|
||||||
|
(in_h_payto
|
||||||
|
,1)
|
||||||
|
ON CONFLICT (h_payto) DO
|
||||||
|
UPDATE SET status=EXCLUDED.status | 1;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- Wake up everyone who might care...
|
||||||
|
PERFORM pg_notify (in_kyc_completed_notify_s, NULL);
|
||||||
|
|
||||||
|
INSERT INTO kyc_alerts
|
||||||
|
(h_payto
|
||||||
|
,trigger_type)
|
||||||
|
VALUES
|
||||||
|
(in_h_payto,1);
|
||||||
|
|
||||||
|
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
|
||||||
|
COMMENT ON FUNCTION exchange_do_insert_kyc_attributes(INT8, BYTEA, BYTEA, VARCHAR, INT4, VARCHAR, VARCHAR, INT8, INT8, INT8, BYTEA, BOOL, VARCHAR)
|
||||||
|
IS 'Inserts new KYC attributes and updates the status of the legitimization process and the AML status for the account';
|
@ -963,3 +963,139 @@ BEGIN
|
|||||||
CLOSE curs_transaction_exist;
|
CLOSE curs_transaction_exist;
|
||||||
RETURN;
|
RETURN;
|
||||||
END $$;
|
END $$;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
CREATE TYPE exchange_do_array_reserve_insert_return_type
|
||||||
|
AS
|
||||||
|
(transaction_duplicate BOOLEAN
|
||||||
|
,ruuid INT8);
|
||||||
|
EXCEPTION
|
||||||
|
WHEN duplicate_object THEN null;
|
||||||
|
END
|
||||||
|
$$;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION exchange_do_array_reserves_insert(
|
||||||
|
IN in_gc_date INT8,
|
||||||
|
IN in_reserve_expiration INT8,
|
||||||
|
IN ina_reserve_pub BYTEA[],
|
||||||
|
IN ina_wire_ref INT8[],
|
||||||
|
IN ina_credit_val INT8[],
|
||||||
|
IN ina_credit_frac INT4[],
|
||||||
|
IN ina_exchange_account_name VARCHAR[],
|
||||||
|
IN ina_execution_date INT8[],
|
||||||
|
IN ina_wire_source_h_payto BYTEA[],
|
||||||
|
IN ina_payto_uri VARCHAR[],
|
||||||
|
IN ina_notify TEXT[])
|
||||||
|
RETURNS SETOF exchange_do_array_reserve_insert_return_type
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $$
|
||||||
|
DECLARE
|
||||||
|
curs REFCURSOR;
|
||||||
|
DECLARE
|
||||||
|
conflict BOOL;
|
||||||
|
DECLARE
|
||||||
|
dup BOOL;
|
||||||
|
DECLARE
|
||||||
|
uuid INT8;
|
||||||
|
DECLARE
|
||||||
|
i RECORD;
|
||||||
|
BEGIN
|
||||||
|
|
||||||
|
INSERT INTO wire_targets
|
||||||
|
(wire_target_h_payto
|
||||||
|
,payto_uri)
|
||||||
|
SELECT
|
||||||
|
wire_source_h_payto
|
||||||
|
,payto_uri
|
||||||
|
FROM
|
||||||
|
UNNEST (ina_wire_source_h_payto) AS wire_source_h_payto
|
||||||
|
,UNNEST (ina_payto_uri) AS payto_uri
|
||||||
|
ON CONFLICT DO NOTHING;
|
||||||
|
|
||||||
|
FOR i IN
|
||||||
|
SELECT
|
||||||
|
reserve_pub
|
||||||
|
,wire_ref
|
||||||
|
,credit_val
|
||||||
|
,credit_frac
|
||||||
|
,exchange_account_name
|
||||||
|
,execution_date
|
||||||
|
,wire_source_h_payto
|
||||||
|
,payto_uri
|
||||||
|
,notify
|
||||||
|
FROM
|
||||||
|
UNNEST (ina_reserve_pub) AS reserve_pub
|
||||||
|
,UNNEST (ina_wire_ref) AS wire_ref
|
||||||
|
,UNNEST (ina_credit_val) AS credit_val
|
||||||
|
,UNNEST (ina_credit_frac) AS credit_frac
|
||||||
|
,UNNEST (ina_exchange_account_name) AS exchange_account_name
|
||||||
|
,UNNEST (ina_execution_date) AS execution_date
|
||||||
|
,UNNEST (ina_wire_source_h_payto) AS wire_source_h_payto
|
||||||
|
,UNNEST (ina_notify) AS notify
|
||||||
|
LOOP
|
||||||
|
INSERT INTO reserves
|
||||||
|
(reserve_pub
|
||||||
|
,current_balance_val
|
||||||
|
,current_balance_frac
|
||||||
|
,expiration_date
|
||||||
|
,gc_date
|
||||||
|
) VALUES (
|
||||||
|
i.reserve_pub
|
||||||
|
,i.credit_val
|
||||||
|
,i.credit_frac
|
||||||
|
,in_reserve_expiration
|
||||||
|
,in_gc_date
|
||||||
|
)
|
||||||
|
ON CONFLICT DO NOTHING
|
||||||
|
RETURNING reserve_uuid
|
||||||
|
INTO uuid;
|
||||||
|
conflict = NOT FOUND;
|
||||||
|
|
||||||
|
INSERT INTO reserves_in
|
||||||
|
(reserve_pub
|
||||||
|
,wire_reference
|
||||||
|
,credit_val
|
||||||
|
,credit_frac
|
||||||
|
,exchange_account_section
|
||||||
|
,wire_source_h_payto
|
||||||
|
,execution_date
|
||||||
|
) VALUES (
|
||||||
|
i.reserve_pub
|
||||||
|
,i.wire_reference
|
||||||
|
,i.credit_val
|
||||||
|
,i.credit_frac
|
||||||
|
,i.exchange_account_section
|
||||||
|
,i.wire_source_h_payto
|
||||||
|
,i.execution_date
|
||||||
|
)
|
||||||
|
ON CONFLICT DO NOTHING;
|
||||||
|
|
||||||
|
IF NOT FOUND
|
||||||
|
THEN
|
||||||
|
IF conflict
|
||||||
|
THEN
|
||||||
|
dup = TRUE;
|
||||||
|
else
|
||||||
|
dup = FALSE;
|
||||||
|
END IF;
|
||||||
|
ELSE
|
||||||
|
IF NOT conflict
|
||||||
|
THEN
|
||||||
|
EXECUTE FORMAT (
|
||||||
|
'NOTIFY %s'
|
||||||
|
,i.notify);
|
||||||
|
END IF;
|
||||||
|
dup = FALSE;
|
||||||
|
END IF;
|
||||||
|
RETURN NEXT (dup,uuid);
|
||||||
|
END LOOP;
|
||||||
|
|
||||||
|
RETURN;
|
||||||
|
END $$;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
This file is part of TALER
|
This file is part of TALER
|
||||||
Copyright (C) 2022 Taler Systems SA
|
Copyright (C) 2022, 2023 Taler Systems SA
|
||||||
|
|
||||||
TALER is free software; you can redistribute it and/or modify it under the
|
TALER is free software; you can redistribute it and/or modify it under the
|
||||||
terms of the GNU General Public License as published by the Free Software
|
terms of the GNU General Public License as published by the Free Software
|
||||||
@ -29,43 +29,72 @@
|
|||||||
enum GNUNET_DB_QueryStatus
|
enum GNUNET_DB_QueryStatus
|
||||||
TEH_PG_insert_kyc_attributes (
|
TEH_PG_insert_kyc_attributes (
|
||||||
void *cls,
|
void *cls,
|
||||||
|
uint64_t process_row,
|
||||||
const struct TALER_PaytoHashP *h_payto,
|
const struct TALER_PaytoHashP *h_payto,
|
||||||
const struct GNUNET_ShortHashCode *kyc_prox,
|
const struct GNUNET_ShortHashCode *kyc_prox,
|
||||||
const char *provider_section,
|
const char *provider_section,
|
||||||
const char *birthdate,
|
uint32_t birthday,
|
||||||
struct GNUNET_TIME_Timestamp collection_time,
|
struct GNUNET_TIME_Timestamp collection_time,
|
||||||
struct GNUNET_TIME_Timestamp expiration_time,
|
const char *provider_account_id,
|
||||||
|
const char *provider_legitimization_id,
|
||||||
|
struct GNUNET_TIME_Absolute expiration_time,
|
||||||
size_t enc_attributes_size,
|
size_t enc_attributes_size,
|
||||||
const void *enc_attributes)
|
const void *enc_attributes,
|
||||||
|
bool require_aml)
|
||||||
{
|
{
|
||||||
struct PostgresClosure *pg = cls;
|
struct PostgresClosure *pg = cls;
|
||||||
|
struct GNUNET_TIME_Timestamp expiration
|
||||||
|
= GNUNET_TIME_absolute_to_timestamp (expiration_time);
|
||||||
|
struct TALER_KycCompletedEventP rep = {
|
||||||
|
.header.size = htons (sizeof (rep)),
|
||||||
|
.header.type = htons (TALER_DBEVENT_EXCHANGE_KYC_COMPLETED),
|
||||||
|
.h_payto = *h_payto
|
||||||
|
};
|
||||||
|
char *kyc_completed_notify_s
|
||||||
|
= GNUNET_PG_get_event_notify_channel (&rep.header);
|
||||||
struct GNUNET_PQ_QueryParam params[] = {
|
struct GNUNET_PQ_QueryParam params[] = {
|
||||||
|
GNUNET_PQ_query_param_uint64 (&process_row),
|
||||||
GNUNET_PQ_query_param_auto_from_type (h_payto),
|
GNUNET_PQ_query_param_auto_from_type (h_payto),
|
||||||
GNUNET_PQ_query_param_auto_from_type (kyc_prox),
|
GNUNET_PQ_query_param_auto_from_type (kyc_prox),
|
||||||
GNUNET_PQ_query_param_string (provider_section),
|
GNUNET_PQ_query_param_string (provider_section),
|
||||||
(NULL == birthdate)
|
GNUNET_PQ_query_param_uint32 (&birthday),
|
||||||
|
(NULL == provider_account_id)
|
||||||
? GNUNET_PQ_query_param_null ()
|
? GNUNET_PQ_query_param_null ()
|
||||||
: GNUNET_PQ_query_param_string (birthdate),
|
: GNUNET_PQ_query_param_string (provider_account_id),
|
||||||
|
(NULL == provider_legitimization_id)
|
||||||
|
? GNUNET_PQ_query_param_null ()
|
||||||
|
: GNUNET_PQ_query_param_string (provider_legitimization_id),
|
||||||
GNUNET_PQ_query_param_timestamp (&collection_time),
|
GNUNET_PQ_query_param_timestamp (&collection_time),
|
||||||
GNUNET_PQ_query_param_timestamp (&expiration_time),
|
GNUNET_PQ_query_param_absolute_time (&expiration_time),
|
||||||
|
GNUNET_PQ_query_param_timestamp (&expiration),
|
||||||
GNUNET_PQ_query_param_fixed_size (enc_attributes,
|
GNUNET_PQ_query_param_fixed_size (enc_attributes,
|
||||||
enc_attributes_size),
|
enc_attributes_size),
|
||||||
|
GNUNET_PQ_query_param_bool (require_aml),
|
||||||
|
GNUNET_PQ_query_param_string (kyc_completed_notify_s),
|
||||||
GNUNET_PQ_query_param_end
|
GNUNET_PQ_query_param_end
|
||||||
};
|
};
|
||||||
|
bool ok;
|
||||||
|
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||||
|
GNUNET_PQ_result_spec_bool ("out_ok",
|
||||||
|
&ok),
|
||||||
|
GNUNET_PQ_result_spec_end
|
||||||
|
};
|
||||||
|
enum GNUNET_DB_QueryStatus qs;
|
||||||
|
|
||||||
PREPARE (pg,
|
PREPARE (pg,
|
||||||
"insert_kyc_attributes",
|
"insert_kyc_attributes",
|
||||||
"INSERT INTO kyc_attributes "
|
"SELECT "
|
||||||
"(h_payto"
|
" out_ok"
|
||||||
",kyc_prox"
|
" FROM exchange_do_insert_kyc_attributes "
|
||||||
",provider"
|
"($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13);");
|
||||||
",birthdate"
|
qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
|
||||||
",collection_time"
|
|
||||||
",expiration_time"
|
|
||||||
",encrypted_attributes"
|
|
||||||
") VALUES "
|
|
||||||
"($1, $2, $3, $4, $5, $6, $7);");
|
|
||||||
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
|
|
||||||
"insert_kyc_attributes",
|
"insert_kyc_attributes",
|
||||||
params);
|
params,
|
||||||
|
rs);
|
||||||
|
GNUNET_free (kyc_completed_notify_s);
|
||||||
|
if (qs < 0)
|
||||||
|
return qs;
|
||||||
|
if (! ok)
|
||||||
|
return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
|
||||||
|
return qs;
|
||||||
}
|
}
|
||||||
|
@ -27,30 +27,39 @@
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Store KYC attribute data.
|
* Store KYC attribute data, update KYC process status and
|
||||||
|
* AML status for the given account.
|
||||||
*
|
*
|
||||||
* @param cls closure
|
* @param cls closure
|
||||||
|
* @param process_row KYC process row to update
|
||||||
* @param h_payto account for which the attribute data is stored
|
* @param h_payto account for which the attribute data is stored
|
||||||
* @param kyc_prox key for similarity search
|
* @param kyc_prox key for similarity search
|
||||||
* @param provider_section provider that must be checked
|
* @param provider_section provider that must be checked
|
||||||
* @param birthdate birthdate of user, in format YYYY-MM-DD; can be NULL;
|
* @param provider_account_id provider account ID
|
||||||
* digits can be 0 if exact day, month or year are unknown
|
* @param provider_legitimization_id provider legitimization ID
|
||||||
|
* @param birthday birthdate of user, in days after 1990, or 0 if unknown or definitively adult
|
||||||
* @param collection_time when was the data collected
|
* @param collection_time when was the data collected
|
||||||
* @param expiration_time when does the data expire
|
* @param expiration_time when does the data expire
|
||||||
* @param enc_attributes_size number of bytes in @a enc_attributes
|
* @param enc_attributes_size number of bytes in @a enc_attributes
|
||||||
* @param enc_attributes encrypted attribute data
|
* @param enc_attributes encrypted attribute data
|
||||||
|
* @param require_aml true to trigger AML
|
||||||
* @return database transaction status
|
* @return database transaction status
|
||||||
*/
|
*/
|
||||||
enum GNUNET_DB_QueryStatus
|
enum GNUNET_DB_QueryStatus
|
||||||
TEH_PG_insert_kyc_attributes (
|
TEH_PG_insert_kyc_attributes (
|
||||||
void *cls,
|
void *cls,
|
||||||
|
uint64_t process_row,
|
||||||
const struct TALER_PaytoHashP *h_payto,
|
const struct TALER_PaytoHashP *h_payto,
|
||||||
const struct GNUNET_ShortHashCode *kyc_prox,
|
const struct GNUNET_ShortHashCode *kyc_prox,
|
||||||
const char *provider_section,
|
const char *provider_section,
|
||||||
const char *birthdate,
|
uint32_t birthday,
|
||||||
struct GNUNET_TIME_Timestamp collection_time,
|
struct GNUNET_TIME_Timestamp collection_time,
|
||||||
struct GNUNET_TIME_Timestamp expiration_time,
|
const char *provider_account_id,
|
||||||
|
const char *provider_legitimization_id,
|
||||||
|
struct GNUNET_TIME_Absolute expiration_time,
|
||||||
size_t enc_attributes_size,
|
size_t enc_attributes_size,
|
||||||
const void *enc_attributes);
|
const void *enc_attributes,
|
||||||
|
bool require_aml);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1995,10 +1995,6 @@ irbt_cb_table_kyc_attributes (struct PostgresClosure *pg,
|
|||||||
&td->details.kyc_attributes.kyc_prox),
|
&td->details.kyc_attributes.kyc_prox),
|
||||||
GNUNET_PQ_query_param_string (
|
GNUNET_PQ_query_param_string (
|
||||||
td->details.kyc_attributes.provider),
|
td->details.kyc_attributes.provider),
|
||||||
(NULL == td->details.kyc_attributes.birthdate)
|
|
||||||
? GNUNET_PQ_query_param_null ()
|
|
||||||
: GNUNET_PQ_query_param_string (
|
|
||||||
td->details.kyc_attributes.birthdate),
|
|
||||||
GNUNET_PQ_query_param_timestamp (
|
GNUNET_PQ_query_param_timestamp (
|
||||||
&td->details.kyc_attributes.collection_time),
|
&td->details.kyc_attributes.collection_time),
|
||||||
GNUNET_PQ_query_param_timestamp (
|
GNUNET_PQ_query_param_timestamp (
|
||||||
@ -2016,12 +2012,11 @@ irbt_cb_table_kyc_attributes (struct PostgresClosure *pg,
|
|||||||
",h_payto"
|
",h_payto"
|
||||||
",kyc_prox"
|
",kyc_prox"
|
||||||
",provider"
|
",provider"
|
||||||
",birthdate"
|
|
||||||
",collection_time"
|
",collection_time"
|
||||||
",expiration_time"
|
",expiration_time"
|
||||||
",encrypted_attributes"
|
",encrypted_attributes"
|
||||||
") VALUES "
|
") VALUES "
|
||||||
"($1, $2, $3, $4, $5, $6, $7, $8);");
|
"($1, $2, $3, $4, $5, $6, $7);");
|
||||||
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
|
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
|
||||||
"insert_into_table_kyc_attributes",
|
"insert_into_table_kyc_attributes",
|
||||||
params);
|
params);
|
||||||
|
@ -2684,11 +2684,6 @@ lrbt_cb_table_kyc_attributes (void *cls,
|
|||||||
GNUNET_PQ_result_spec_string (
|
GNUNET_PQ_result_spec_string (
|
||||||
"provider",
|
"provider",
|
||||||
&td.details.kyc_attributes.provider),
|
&td.details.kyc_attributes.provider),
|
||||||
GNUNET_PQ_result_spec_allow_null (
|
|
||||||
GNUNET_PQ_result_spec_string (
|
|
||||||
"birthdate",
|
|
||||||
&td.details.kyc_attributes.birthdate),
|
|
||||||
NULL),
|
|
||||||
GNUNET_PQ_result_spec_timestamp (
|
GNUNET_PQ_result_spec_timestamp (
|
||||||
"collection_time",
|
"collection_time",
|
||||||
&td.details.kyc_attributes.collection_time),
|
&td.details.kyc_attributes.collection_time),
|
||||||
@ -3577,7 +3572,6 @@ TEH_PG_lookup_records_by_table (void *cls,
|
|||||||
",h_payto"
|
",h_payto"
|
||||||
",kyc_prox"
|
",kyc_prox"
|
||||||
",provider"
|
",provider"
|
||||||
",birthdate"
|
|
||||||
",collection_time"
|
",collection_time"
|
||||||
",expiration_time"
|
",expiration_time"
|
||||||
",encrypted_attributes"
|
",encrypted_attributes"
|
||||||
|
@ -615,3 +615,284 @@ TEH_PG_reserves_in_insert (
|
|||||||
GNUNET_free (rrs[i].notify_s);
|
GNUNET_free (rrs[i].notify_s);
|
||||||
return qs;
|
return qs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closure for our helper_cb()
|
||||||
|
*/
|
||||||
|
struct Context
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Array of reserve UUIDs to initialize.
|
||||||
|
*/
|
||||||
|
uint64_t *reserve_uuids;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array with entries set to 'true' for duplicate transactions.
|
||||||
|
*/
|
||||||
|
bool *transaction_duplicates;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array with entries set to 'true' for rows with conflicts.
|
||||||
|
*/
|
||||||
|
bool *conflicts;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set to #GNUNET_SYSERR on failures.
|
||||||
|
*/
|
||||||
|
struct GNUNET_GenericReturnValue status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Single value (no array) set to true if we need
|
||||||
|
* to follow-up with an update.
|
||||||
|
*/
|
||||||
|
bool *needs_update;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to be called with the results of a SELECT statement
|
||||||
|
* that has returned @a num_results results.
|
||||||
|
*
|
||||||
|
* @param cls closure of type `struct Context *`
|
||||||
|
* @param result the postgres result
|
||||||
|
* @param num_results the number of results in @a result
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
helper_cb (void *cls,
|
||||||
|
PGresult *result,
|
||||||
|
unsigned int num_results)
|
||||||
|
{
|
||||||
|
struct Context *ctx = cls;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i<num_results; i++)
|
||||||
|
{
|
||||||
|
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||||
|
GNUNET_PQ_result_spec_bool (
|
||||||
|
"transaction_duplicate",
|
||||||
|
&ctx->transaction_duplicates[i]),
|
||||||
|
GNUNET_PQ_result_spec_allow_null (
|
||||||
|
GNUNET_PQ_result_spec_uint64 ("ruuid",
|
||||||
|
&ctx->reserve_uuids[i]),
|
||||||
|
&ctx->conflicts[i]),
|
||||||
|
GNUNET_PQ_result_spec_end
|
||||||
|
};
|
||||||
|
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
GNUNET_PQ_extract_result (result,
|
||||||
|
rs,
|
||||||
|
i))
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
ctx->status = GNUNET_SYSERR;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*ctx->need_update |= ctx->conflicts[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
enum GNUNET_DB_QueryStatus
|
||||||
|
TEH_PG_reserves_in_insertN (
|
||||||
|
void *cls,
|
||||||
|
const struct TALER_EXCHANGEDB_ReserveInInfo *reserves,
|
||||||
|
unsigned int reserves_length,
|
||||||
|
enum GNUNET_DB_QueryStatus *results)
|
||||||
|
{
|
||||||
|
struct PostgresClosure *pg = cls;
|
||||||
|
struct TALER_PaytoHashP h_paytos[GNUNET_NZL (reserves_length)];
|
||||||
|
char *notify_s[GNUNET_NZL (reserves_length)];
|
||||||
|
struct TALER_ReservePublicKeyP *reserve_pubs[GNUNET_NZL (reserves_length)];
|
||||||
|
struct TALER_Amount *balances[GNUNET_NZL (reserves_length)];
|
||||||
|
struct GNUNET_TIME_Timestamp execution_times[GNUNET_NZL (reserves_length)];
|
||||||
|
const char *sender_account_details[GNUNET_NZL (reserves_length)];
|
||||||
|
const char *exchange_account_names[GNUNET_NZL (reserves_length)];
|
||||||
|
uint64_t wire_references[GNUNET_NZL (reserves_length)];
|
||||||
|
uint64_t reserve_uuids[GNUNET_NZL (reserves_length)];
|
||||||
|
bool transaction_duplicates[GNUNET_NZL (reserves_length)];
|
||||||
|
bool conflicts[GNUNET_NZL (reserves_length)];
|
||||||
|
struct GNUNET_TIME_Timestamp reserve_expiration
|
||||||
|
= GNUNET_TIME_relative_to_timestamp (pg->idle_reserve_expiration_time);
|
||||||
|
struct GNUNET_TIME_Timestamp gc
|
||||||
|
= GNUNET_TIME_relative_to_timestamp (pg->legal_reserve_expiration_time);
|
||||||
|
bool needs_update = false;
|
||||||
|
enum GNUNET_DB_QueryStatus qs;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i<reserves_length; i++)
|
||||||
|
{
|
||||||
|
const struct TALER_EXCHANGEDB_ReserveInInfo *reserve = &reserves[i];
|
||||||
|
|
||||||
|
TALER_payto_hash (reserve->sender_account_details,
|
||||||
|
&h_paytos[i]);
|
||||||
|
notify_s[i] = compute_notify_on_reserve (reserve->reserve_pub);
|
||||||
|
reserve_pubs[i] = &reserve->reserve_pub;
|
||||||
|
balances[i] = &reserve->balance;
|
||||||
|
execution_times[i] = reserve->execution_time;
|
||||||
|
sender_account_details[i] = reserve->sender_account_details;
|
||||||
|
exchange_account_names[i] = reserve->exchange_account_name;
|
||||||
|
wire_references[i] = reserve->wire_reference;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NOTE: kind-of pointless to explicitly start a transaction here... */
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
TEH_PG_preflight (pg))
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
qs = GNUNET_DB_STATUS_HARD_ERROR;
|
||||||
|
goto finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
TEH_PG_start_read_committed (pg,
|
||||||
|
"READ_COMMITED"))
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
qs = GNUNET_DB_STATUS_HARD_ERROR;
|
||||||
|
goto finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
PREPARE (pg,
|
||||||
|
"reserves_insert_with_array",
|
||||||
|
"SELECT"
|
||||||
|
" transaction_duplicate"
|
||||||
|
",ruuid"
|
||||||
|
"FROM exchange_do_array_reserves_insert"
|
||||||
|
" ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10);");
|
||||||
|
{
|
||||||
|
struct GNUNET_PQ_QueryParam params[] = {
|
||||||
|
GNUNET_PQ_query_param_timestamp (&gc),
|
||||||
|
GNUNET_PQ_query_param_timestamp (&reserve_expiration),
|
||||||
|
GNUNET_PQ_query_param_array_auto_from_type (reserves_length,
|
||||||
|
reserve_pubs,
|
||||||
|
pg->conn),
|
||||||
|
GNUNET_PQ_query_param_array_uint64 (reserves_length,
|
||||||
|
wire_references,
|
||||||
|
pg->conn),
|
||||||
|
TALER_PQ_query_param_array_amount (reserves_length,
|
||||||
|
balances,
|
||||||
|
pg->conn),
|
||||||
|
GNUNET_PQ_query_param_array_string (reserves_length,
|
||||||
|
exchange_account_names,
|
||||||
|
pg->conn),
|
||||||
|
GNUNET_PQ_query_param_array_timestamp (reserves_length,
|
||||||
|
execution_times,
|
||||||
|
pg->conn),
|
||||||
|
GNUNET_PQ_query_param_array_bytes_same_size_cont_auto (
|
||||||
|
reserves_length,
|
||||||
|
h_paytos,
|
||||||
|
sizeof (struct GNUNET_PaytoHashP),
|
||||||
|
pg->conn),
|
||||||
|
GNUNET_PQ_query_param_array_string (reserves_length,
|
||||||
|
sender_account_details,
|
||||||
|
pg->conn),
|
||||||
|
GNUNET_PQ_query_param_array_string (reserves_length,
|
||||||
|
notify_s,
|
||||||
|
pg->conn),
|
||||||
|
GNUNET_PQ_query_param_end
|
||||||
|
};
|
||||||
|
struct Context ctx = {
|
||||||
|
.reserve_uuids = reserve_uuids,
|
||||||
|
.transaction_duplicates = transaction_duplicates,
|
||||||
|
.conflicts = conflicts,
|
||||||
|
.needs_update = &needs_update,
|
||||||
|
.status = GNUNET_OK
|
||||||
|
};
|
||||||
|
|
||||||
|
qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
|
||||||
|
"reserves_insert_with_array",
|
||||||
|
params,
|
||||||
|
&multi_res,
|
||||||
|
&ctx);
|
||||||
|
if ( (qs < 0) ||
|
||||||
|
(GNUNET_OK != ctx.status) )
|
||||||
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||||
|
"Failed to insert into reserves (%d)\n",
|
||||||
|
qs);
|
||||||
|
goto finished;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
enum GNUNET_DB_QueryStatus cs;
|
||||||
|
|
||||||
|
cs = TEH_PG_commit (pg);
|
||||||
|
if (cs < 0)
|
||||||
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||||
|
"Failed to commit\n");
|
||||||
|
qs = cs;
|
||||||
|
goto finished;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (unsigned int i = 0; i<reserves_length; i++)
|
||||||
|
{
|
||||||
|
results[i] = transaction_duplicates[i]
|
||||||
|
? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
|
||||||
|
: GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! need_update)
|
||||||
|
{
|
||||||
|
qs = reserves_length;
|
||||||
|
goto finished;
|
||||||
|
}
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
TEH_PG_start (pg,
|
||||||
|
"reserve-insert-continued"))
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
qs = GNUNET_DB_STATUS_HARD_ERROR;
|
||||||
|
goto finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i<reserves_length; i++)
|
||||||
|
{
|
||||||
|
if (! conflicts[i])
|
||||||
|
continue;
|
||||||
|
{
|
||||||
|
bool duplicate;
|
||||||
|
struct GNUNET_PQ_QueryParam params[] = {
|
||||||
|
GNUNET_PQ_query_param_auto_from_type (reserve_pubs[i]),
|
||||||
|
GNUNET_PQ_query_param_timestamp (&reserve_expiration),
|
||||||
|
GNUNET_PQ_query_param_uint64 (&wire_reference[i]),
|
||||||
|
TALER_PQ_query_param_amount (balances[i]),
|
||||||
|
GNUNET_PQ_query_param_string (exchange_account_names[i]),
|
||||||
|
GNUNET_PQ_query_param_auto_from_type (h_paytos[i]),
|
||||||
|
GNUNET_PQ_query_param_string (notify_s[i]),
|
||||||
|
GNUNET_PQ_query_param_end
|
||||||
|
};
|
||||||
|
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||||
|
GNUNET_PQ_result_spec_bool ("duplicate",
|
||||||
|
&duplicate),
|
||||||
|
GNUNET_PQ_result_spec_end
|
||||||
|
};
|
||||||
|
enum GNUNET_DB_QueryStatus qs;
|
||||||
|
|
||||||
|
qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
|
||||||
|
"reserves_update",
|
||||||
|
params,
|
||||||
|
rs);
|
||||||
|
if (qs < 0)
|
||||||
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||||
|
"Failed to update reserves (%d)\n",
|
||||||
|
qs);
|
||||||
|
results[i] = qs;
|
||||||
|
goto finished;
|
||||||
|
}
|
||||||
|
results[i] = duplicate
|
||||||
|
? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
|
||||||
|
: GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finished:
|
||||||
|
for (unsigned int i = 0; i<reserves_length; i++)
|
||||||
|
GNUNET_free (rrs[i].notify_s);
|
||||||
|
return qs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
@ -80,14 +80,9 @@ get_attributes_cb (void *cls,
|
|||||||
size_t enc_attributes_size;
|
size_t enc_attributes_size;
|
||||||
void *enc_attributes;
|
void *enc_attributes;
|
||||||
char *provider;
|
char *provider;
|
||||||
char *birthdate = NULL;
|
|
||||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||||
GNUNET_PQ_result_spec_string ("provider",
|
GNUNET_PQ_result_spec_string ("provider",
|
||||||
&provider),
|
&provider),
|
||||||
GNUNET_PQ_result_spec_allow_null (
|
|
||||||
GNUNET_PQ_result_spec_string ("birthdate",
|
|
||||||
&birthdate),
|
|
||||||
NULL),
|
|
||||||
GNUNET_PQ_result_spec_timestamp ("collection_time",
|
GNUNET_PQ_result_spec_timestamp ("collection_time",
|
||||||
&collection_time),
|
&collection_time),
|
||||||
GNUNET_PQ_result_spec_timestamp ("expiration_time",
|
GNUNET_PQ_result_spec_timestamp ("expiration_time",
|
||||||
@ -110,7 +105,6 @@ get_attributes_cb (void *cls,
|
|||||||
ctx->cb (ctx->cb_cls,
|
ctx->cb (ctx->cb_cls,
|
||||||
ctx->h_payto,
|
ctx->h_payto,
|
||||||
provider,
|
provider,
|
||||||
birthdate,
|
|
||||||
collection_time,
|
collection_time,
|
||||||
expiration_time,
|
expiration_time,
|
||||||
enc_attributes_size,
|
enc_attributes_size,
|
||||||
@ -145,7 +139,6 @@ TEH_PG_select_kyc_attributes (
|
|||||||
"select_kyc_attributes",
|
"select_kyc_attributes",
|
||||||
"SELECT "
|
"SELECT "
|
||||||
" provider"
|
" provider"
|
||||||
",birthdate"
|
|
||||||
",collection_time"
|
",collection_time"
|
||||||
",expiration_time"
|
",expiration_time"
|
||||||
",encrypted_attributes"
|
",encrypted_attributes"
|
||||||
|
@ -76,16 +76,11 @@ get_attributes_cb (void *cls,
|
|||||||
size_t enc_attributes_size;
|
size_t enc_attributes_size;
|
||||||
void *enc_attributes;
|
void *enc_attributes;
|
||||||
char *provider;
|
char *provider;
|
||||||
char *birthdate = NULL;
|
|
||||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||||
GNUNET_PQ_result_spec_auto_from_type ("h_payto",
|
GNUNET_PQ_result_spec_auto_from_type ("h_payto",
|
||||||
&h_payto),
|
&h_payto),
|
||||||
GNUNET_PQ_result_spec_string ("provider",
|
GNUNET_PQ_result_spec_string ("provider",
|
||||||
&provider),
|
&provider),
|
||||||
GNUNET_PQ_result_spec_allow_null (
|
|
||||||
GNUNET_PQ_result_spec_string ("birthdate",
|
|
||||||
&birthdate),
|
|
||||||
NULL),
|
|
||||||
GNUNET_PQ_result_spec_timestamp ("collection_time",
|
GNUNET_PQ_result_spec_timestamp ("collection_time",
|
||||||
&collection_time),
|
&collection_time),
|
||||||
GNUNET_PQ_result_spec_timestamp ("expiration_time",
|
GNUNET_PQ_result_spec_timestamp ("expiration_time",
|
||||||
@ -108,7 +103,6 @@ get_attributes_cb (void *cls,
|
|||||||
ctx->cb (ctx->cb_cls,
|
ctx->cb (ctx->cb_cls,
|
||||||
&h_payto,
|
&h_payto,
|
||||||
provider,
|
provider,
|
||||||
birthdate,
|
|
||||||
collection_time,
|
collection_time,
|
||||||
expiration_time,
|
expiration_time,
|
||||||
enc_attributes_size,
|
enc_attributes_size,
|
||||||
@ -143,7 +137,6 @@ TEH_PG_select_similar_kyc_attributes (
|
|||||||
"SELECT "
|
"SELECT "
|
||||||
" h_payto"
|
" h_payto"
|
||||||
",provider"
|
",provider"
|
||||||
",birthdate"
|
|
||||||
",collection_time"
|
",collection_time"
|
||||||
",expiration_time"
|
",expiration_time"
|
||||||
",encrypted_attributes"
|
",encrypted_attributes"
|
||||||
|
@ -1,68 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is part of TALER
|
|
||||||
Copyright (C) 2022 Taler Systems SA
|
|
||||||
|
|
||||||
TALER is free software; you can redistribute it and/or modify it under the
|
|
||||||
terms of the GNU General Public License as published by the Free Software
|
|
||||||
Foundation; either version 3, or (at your option) any later version.
|
|
||||||
|
|
||||||
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
|
||||||
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @file exchangedb/pg_update_kyc_attributes.c
|
|
||||||
* @brief Implementation of the update_kyc_attributes function for Postgres
|
|
||||||
* @author Christian Grothoff
|
|
||||||
*/
|
|
||||||
#include "platform.h"
|
|
||||||
#include "taler_error_codes.h"
|
|
||||||
#include "taler_dbevents.h"
|
|
||||||
#include "taler_pq_lib.h"
|
|
||||||
#include "pg_update_kyc_attributes.h"
|
|
||||||
#include "pg_helper.h"
|
|
||||||
|
|
||||||
|
|
||||||
enum GNUNET_DB_QueryStatus
|
|
||||||
TEH_PG_update_kyc_attributes (
|
|
||||||
void *cls,
|
|
||||||
const struct TALER_PaytoHashP *h_payto,
|
|
||||||
const struct GNUNET_ShortHashCode *kyc_prox,
|
|
||||||
const char *provider_section,
|
|
||||||
const char *birthdate,
|
|
||||||
struct GNUNET_TIME_Timestamp collection_time,
|
|
||||||
struct GNUNET_TIME_Timestamp expiration_time,
|
|
||||||
size_t enc_attributes_size,
|
|
||||||
const void *enc_attributes)
|
|
||||||
{
|
|
||||||
struct PostgresClosure *pg = cls;
|
|
||||||
struct GNUNET_PQ_QueryParam params[] = {
|
|
||||||
GNUNET_PQ_query_param_auto_from_type (h_payto),
|
|
||||||
GNUNET_PQ_query_param_auto_from_type (kyc_prox),
|
|
||||||
GNUNET_PQ_query_param_string (provider_section),
|
|
||||||
(NULL == birthdate)
|
|
||||||
? GNUNET_PQ_query_param_null ()
|
|
||||||
: GNUNET_PQ_query_param_string (birthdate),
|
|
||||||
GNUNET_PQ_query_param_timestamp (&collection_time),
|
|
||||||
GNUNET_PQ_query_param_timestamp (&expiration_time),
|
|
||||||
GNUNET_PQ_query_param_fixed_size (enc_attributes,
|
|
||||||
enc_attributes_size),
|
|
||||||
GNUNET_PQ_query_param_end
|
|
||||||
};
|
|
||||||
|
|
||||||
PREPARE (pg,
|
|
||||||
"update_kyc_attributes",
|
|
||||||
"UPDATE kyc_attributes SET "
|
|
||||||
" kyc_prox=$2"
|
|
||||||
",birthdate=$4"
|
|
||||||
",collection_time=$5"
|
|
||||||
",expiration_time=$6"
|
|
||||||
",encrypted_attributes=$7"
|
|
||||||
" WHERE h_payto=$1 AND provider_section=$3;");
|
|
||||||
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
|
|
||||||
"update_kyc_attributes",
|
|
||||||
params);
|
|
||||||
}
|
|
@ -1,57 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is part of TALER
|
|
||||||
Copyright (C) 2022 Taler Systems SA
|
|
||||||
|
|
||||||
TALER is free software; you can redistribute it and/or modify it under the
|
|
||||||
terms of the GNU General Public License as published by the Free Software
|
|
||||||
Foundation; either version 3, or (at your option) any later version.
|
|
||||||
|
|
||||||
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
|
||||||
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @file exchangedb/pg_update_kyc_attributes.h
|
|
||||||
* @brief implementation of the update_kyc_attributes function for Postgres
|
|
||||||
* @author Christian Grothoff
|
|
||||||
*/
|
|
||||||
#ifndef PG_UPDATE_KYC_ATTRIBUTES_H
|
|
||||||
#define PG_UPDATE_KYC_ATTRIBUTES_H
|
|
||||||
|
|
||||||
#include "taler_util.h"
|
|
||||||
#include "taler_json_lib.h"
|
|
||||||
#include "taler_exchangedb_plugin.h"
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update KYC attribute data.
|
|
||||||
*
|
|
||||||
* @param cls closure
|
|
||||||
* @param h_payto account for which the attribute data is stored
|
|
||||||
* @param kyc_prox key for similarity search
|
|
||||||
* @param provider_section provider that must be checked
|
|
||||||
* @param birthdate birthdate of user, in format YYYY-MM-DD; can be NULL;
|
|
||||||
* digits can be 0 if exact day, month or year are unknown
|
|
||||||
* @param collection_time when was the data collected
|
|
||||||
* @param expiration_time when does the data expire
|
|
||||||
* @param enc_attributes_size number of bytes in @a enc_attributes
|
|
||||||
* @param enc_attributes encrypted attribute data
|
|
||||||
* @return database transaction status
|
|
||||||
*/
|
|
||||||
enum GNUNET_DB_QueryStatus
|
|
||||||
TEH_PG_update_kyc_attributes (
|
|
||||||
void *cls,
|
|
||||||
const struct TALER_PaytoHashP *h_payto,
|
|
||||||
const struct GNUNET_ShortHashCode *kyc_prox,
|
|
||||||
const char *provider_section,
|
|
||||||
const char *birthdate,
|
|
||||||
struct GNUNET_TIME_Timestamp collection_time,
|
|
||||||
struct GNUNET_TIME_Timestamp expiration_time,
|
|
||||||
size_t enc_attributes_size,
|
|
||||||
const void *enc_attributes);
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
@ -68,7 +68,8 @@ TEH_PG_update_kyc_process_by_row (
|
|||||||
if (qs <= 0)
|
if (qs <= 0)
|
||||||
{
|
{
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||||
"Failed to update legitimization process: %d\n",
|
"Failed to update legitimization process %llu: %d\n",
|
||||||
|
(unsigned long long) process_row,
|
||||||
qs);
|
qs);
|
||||||
return qs;
|
return qs;
|
||||||
}
|
}
|
||||||
|
@ -207,7 +207,6 @@
|
|||||||
#include "pg_setup_wire_target.h"
|
#include "pg_setup_wire_target.h"
|
||||||
#include "pg_compute_shard.h"
|
#include "pg_compute_shard.h"
|
||||||
#include "pg_insert_kyc_attributes.h"
|
#include "pg_insert_kyc_attributes.h"
|
||||||
#include "pg_update_kyc_attributes.h"
|
|
||||||
#include "pg_select_similar_kyc_attributes.h"
|
#include "pg_select_similar_kyc_attributes.h"
|
||||||
#include "pg_select_kyc_attributes.h"
|
#include "pg_select_kyc_attributes.h"
|
||||||
#include "pg_insert_aml_officer.h"
|
#include "pg_insert_aml_officer.h"
|
||||||
@ -754,8 +753,6 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
|
|||||||
= &TEH_PG_set_purse_balance;
|
= &TEH_PG_set_purse_balance;
|
||||||
plugin->insert_kyc_attributes
|
plugin->insert_kyc_attributes
|
||||||
= &TEH_PG_insert_kyc_attributes;
|
= &TEH_PG_insert_kyc_attributes;
|
||||||
plugin->update_kyc_attributes
|
|
||||||
= &TEH_PG_update_kyc_attributes;
|
|
||||||
plugin->select_similar_kyc_attributes
|
plugin->select_similar_kyc_attributes
|
||||||
= &TEH_PG_select_similar_kyc_attributes;
|
= &TEH_PG_select_similar_kyc_attributes;
|
||||||
plugin->select_kyc_attributes
|
plugin->select_kyc_attributes
|
||||||
|
@ -39,6 +39,7 @@ SET search_path TO exchange;
|
|||||||
#include "exchange_do_insert_or_update_policy_details.sql"
|
#include "exchange_do_insert_or_update_policy_details.sql"
|
||||||
#include "exchange_do_insert_aml_decision.sql"
|
#include "exchange_do_insert_aml_decision.sql"
|
||||||
#include "exchange_do_insert_aml_officer.sql"
|
#include "exchange_do_insert_aml_officer.sql"
|
||||||
|
#include "exchange_do_insert_kyc_attributes.sql"
|
||||||
#include "exchange_do_reserves_in_insert.sql"
|
#include "exchange_do_reserves_in_insert.sql"
|
||||||
#include "exchange_do_batch_reserves_update.sql"
|
#include "exchange_do_batch_reserves_update.sql"
|
||||||
#include "exchange_do_refund_by_coin.sql"
|
#include "exchange_do_refund_by_coin.sql"
|
||||||
|
@ -402,7 +402,7 @@ TALER_amount_multiply (struct TALER_Amount *result,
|
|||||||
* #GNUNET_NO if value was already normalized
|
* #GNUNET_NO if value was already normalized
|
||||||
* #GNUNET_SYSERR if value was invalid or could not be normalized
|
* #GNUNET_SYSERR if value was invalid or could not be normalized
|
||||||
*/
|
*/
|
||||||
int
|
enum GNUNET_GenericReturnValue
|
||||||
TALER_amount_normalize (struct TALER_Amount *amount);
|
TALER_amount_normalize (struct TALER_Amount *amount);
|
||||||
|
|
||||||
|
|
||||||
|
@ -366,6 +366,10 @@ struct TALER_EXCHANGE_Keys
|
|||||||
*/
|
*/
|
||||||
char *asset_type;
|
char *asset_type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set to true if tipping is allowed at this exchange.
|
||||||
|
*/
|
||||||
|
bool tipping_allowed;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -756,7 +756,6 @@ struct TALER_EXCHANGEDB_TableData
|
|||||||
struct TALER_PaytoHashP h_payto;
|
struct TALER_PaytoHashP h_payto;
|
||||||
struct GNUNET_ShortHashCode kyc_prox;
|
struct GNUNET_ShortHashCode kyc_prox;
|
||||||
char *provider;
|
char *provider;
|
||||||
char *birthdate; /* NULL allowed! */
|
|
||||||
struct GNUNET_TIME_Timestamp collection_time;
|
struct GNUNET_TIME_Timestamp collection_time;
|
||||||
struct GNUNET_TIME_Timestamp expiration_time;
|
struct GNUNET_TIME_Timestamp expiration_time;
|
||||||
void *encrypted_attributes;
|
void *encrypted_attributes;
|
||||||
@ -2429,8 +2428,6 @@ typedef void
|
|||||||
* @param cls closure
|
* @param cls closure
|
||||||
* @param h_payto account for which the attribute data is stored
|
* @param h_payto account for which the attribute data is stored
|
||||||
* @param provider_section provider that must be checked
|
* @param provider_section provider that must be checked
|
||||||
* @param birthdate birthdate of user, in format YYYY-MM-DD; can be NULL;
|
|
||||||
* digits can be 0 if exact day, month or year are unknown
|
|
||||||
* @param collection_time when was the data collected
|
* @param collection_time when was the data collected
|
||||||
* @param expiration_time when does the data expire
|
* @param expiration_time when does the data expire
|
||||||
* @param enc_attributes_size number of bytes in @a enc_attributes
|
* @param enc_attributes_size number of bytes in @a enc_attributes
|
||||||
@ -2441,7 +2438,6 @@ typedef void
|
|||||||
void *cls,
|
void *cls,
|
||||||
const struct TALER_PaytoHashP *h_payto,
|
const struct TALER_PaytoHashP *h_payto,
|
||||||
const char *provider_section,
|
const char *provider_section,
|
||||||
const char *birthdate,
|
|
||||||
struct GNUNET_TIME_Timestamp collection_time,
|
struct GNUNET_TIME_Timestamp collection_time,
|
||||||
struct GNUNET_TIME_Timestamp expiration_time,
|
struct GNUNET_TIME_Timestamp expiration_time,
|
||||||
size_t enc_attributes_size,
|
size_t enc_attributes_size,
|
||||||
@ -6765,59 +6761,39 @@ struct TALER_EXCHANGEDB_Plugin
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Store KYC attribute data.
|
* Store KYC attribute data, update KYC process status and
|
||||||
|
* AML status for the given account.
|
||||||
*
|
*
|
||||||
* @param cls closure
|
* @param cls closure
|
||||||
|
* @param process_row KYC process row to update
|
||||||
* @param h_payto account for which the attribute data is stored
|
* @param h_payto account for which the attribute data is stored
|
||||||
* @param kyc_prox key for similarity search
|
* @param kyc_prox key for similarity search
|
||||||
* @param provider_section provider that must be checked
|
* @param provider_section provider that must be checked
|
||||||
* @param birthdate birthdate of user, in format YYYY-MM-DD; can be NULL;
|
* @param provider_account_id provider account ID
|
||||||
* digits can be 0 if exact day, month or year are unknown
|
* @param provider_legitimization_id provider legitimization ID
|
||||||
|
* @param birthday birthdate of user, in days after 1990, or 0 if unknown or definitively adult
|
||||||
* @param collection_time when was the data collected
|
* @param collection_time when was the data collected
|
||||||
* @param expiration_time when does the data expire
|
* @param expiration_time when does the data expire
|
||||||
* @param enc_attributes_size number of bytes in @a enc_attributes
|
* @param enc_attributes_size number of bytes in @a enc_attributes
|
||||||
* @param enc_attributes encrypted attribute data
|
* @param enc_attributes encrypted attribute data
|
||||||
|
* @param require_aml true to trigger AML
|
||||||
* @return database transaction status
|
* @return database transaction status
|
||||||
*/
|
*/
|
||||||
enum GNUNET_DB_QueryStatus
|
enum GNUNET_DB_QueryStatus
|
||||||
(*insert_kyc_attributes)(
|
(*insert_kyc_attributes)(
|
||||||
void *cls,
|
void *cls,
|
||||||
|
uint64_t process_row,
|
||||||
const struct TALER_PaytoHashP *h_payto,
|
const struct TALER_PaytoHashP *h_payto,
|
||||||
const struct GNUNET_ShortHashCode *kyc_prox,
|
const struct GNUNET_ShortHashCode *kyc_prox,
|
||||||
const char *provider_section,
|
const char *provider_section,
|
||||||
const char *birthdate,
|
uint32_t birthday,
|
||||||
struct GNUNET_TIME_Timestamp collection_time,
|
struct GNUNET_TIME_Timestamp collection_time,
|
||||||
struct GNUNET_TIME_Timestamp expiration_time,
|
const char *provider_account_id,
|
||||||
|
const char *provider_legitimization_id,
|
||||||
|
struct GNUNET_TIME_Absolute expiration_time,
|
||||||
size_t enc_attributes_size,
|
size_t enc_attributes_size,
|
||||||
const void *enc_attributes);
|
const void *enc_attributes,
|
||||||
|
bool require_aml);
|
||||||
|
|
||||||
/**
|
|
||||||
* Update KYC attribute data.
|
|
||||||
*
|
|
||||||
* @param cls closure
|
|
||||||
* @param h_payto account for which the attribute data is stored
|
|
||||||
* @param kyc_prox key for similarity search
|
|
||||||
* @param provider_section provider that must be checked
|
|
||||||
* @param birthdate birthdate of user, in format YYYY-MM-DD; can be NULL;
|
|
||||||
* digits can be 0 if exact day, month or year are unknown
|
|
||||||
* @param collection_time when was the data collected
|
|
||||||
* @param expiration_time when does the data expire
|
|
||||||
* @param enc_attributes_size number of bytes in @a enc_attributes
|
|
||||||
* @param enc_attributes encrypted attribute data
|
|
||||||
* @return database transaction status
|
|
||||||
*/
|
|
||||||
enum GNUNET_DB_QueryStatus
|
|
||||||
(*update_kyc_attributes)(
|
|
||||||
void *cls,
|
|
||||||
const struct TALER_PaytoHashP *h_payto,
|
|
||||||
const struct GNUNET_ShortHashCode *kyc_prox,
|
|
||||||
const char *provider_section,
|
|
||||||
const char *birthdate,
|
|
||||||
struct GNUNET_TIME_Timestamp collection_time,
|
|
||||||
struct GNUNET_TIME_Timestamp expiration_time,
|
|
||||||
size_t enc_attributes_size,
|
|
||||||
const void *enc_attributes);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -20,6 +20,7 @@ EXTRA_DIST = \
|
|||||||
persona-sample-reply.json
|
persona-sample-reply.json
|
||||||
|
|
||||||
bin_SCRIPTS = \
|
bin_SCRIPTS = \
|
||||||
|
taler-exchange-kyc-kycaid-converter.sh \
|
||||||
taler-exchange-kyc-persona-converter.sh
|
taler-exchange-kyc-persona-converter.sh
|
||||||
|
|
||||||
lib_LTLIBRARIES = \
|
lib_LTLIBRARIES = \
|
||||||
|
@ -12,6 +12,10 @@ PROVIDED_CHECKS = EXAMPLE_DO_NOT_USE
|
|||||||
# How long is the KYC check valid?
|
# How long is the KYC check valid?
|
||||||
KYC_KYCAID_VALIDITY = forever
|
KYC_KYCAID_VALIDITY = forever
|
||||||
|
|
||||||
|
# Program that converts Persona KYC data into the
|
||||||
|
# GNU Taler format.
|
||||||
|
KYC_KYCAID_CONVERTER_HELPER = taler-exchange-kyc-kycaid-converter.sh
|
||||||
|
|
||||||
# Authentication token to use.
|
# Authentication token to use.
|
||||||
KYC_KYCAID_AUTH_TOKEN = XXX
|
KYC_KYCAID_AUTH_TOKEN = XXX
|
||||||
|
|
||||||
|
@ -13,11 +13,11 @@ PROVIDED_CHECKS = EXAMPLE_DO_NOT_USE
|
|||||||
KYC_OAUTH2_VALIDITY = forever
|
KYC_OAUTH2_VALIDITY = forever
|
||||||
|
|
||||||
# URL where we initiate the user's login process
|
# URL where we initiate the user's login process
|
||||||
KYC_OAUTH2_LOGIN_URL = http://kyc.example.com/login
|
KYC_OAUTH2_AUTHORIZE_URL = https://kyc.example.com/authorize
|
||||||
# URL where we send the user's authentication information
|
# URL where we send the user's authentication information
|
||||||
KYC_OAUTH2_AUTH_URL = http://kyc.example.com/auth
|
KYC_OAUTH2_TOKEN_URL = https://kyc.example.com/token
|
||||||
# URL of the user info access point.
|
# URL of the user info access point.
|
||||||
KYC_OAUTH2_INFO_URL = http://kyc.example.com/info
|
KYC_OAUTH2_INFO_URL = https://kyc.example.com/info
|
||||||
|
|
||||||
# Where does the client get redirected upon completion?
|
# Where does the client get redirected upon completion?
|
||||||
KYC_OAUTH2_POST_URL = http://example.com/thank-you
|
KYC_OAUTH2_POST_URL = http://example.com/thank-you
|
||||||
|
@ -87,6 +87,12 @@ struct TALER_KYCLOGIC_ProviderDetails
|
|||||||
*/
|
*/
|
||||||
char *form_id;
|
char *form_id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper binary to convert attributes returned by
|
||||||
|
* KYCAID into our internal format.
|
||||||
|
*/
|
||||||
|
char *conversion_helper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validity time for a successful KYC process.
|
* Validity time for a successful KYC process.
|
||||||
*/
|
*/
|
||||||
@ -215,6 +221,12 @@ struct TALER_KYCLOGIC_WebhookHandle
|
|||||||
*/
|
*/
|
||||||
struct PluginState *ps;
|
struct PluginState *ps;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle to helper process to extract attributes
|
||||||
|
* we care about.
|
||||||
|
*/
|
||||||
|
struct TALER_JSON_ExternalConversion *econ;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Our configuration details.
|
* Our configuration details.
|
||||||
*/
|
*/
|
||||||
@ -225,6 +237,11 @@ struct TALER_KYCLOGIC_WebhookHandle
|
|||||||
*/
|
*/
|
||||||
struct MHD_Connection *connection;
|
struct MHD_Connection *connection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSON response we got back, or NULL for none.
|
||||||
|
*/
|
||||||
|
json_t *json_response;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verification ID from the service.
|
* Verification ID from the service.
|
||||||
*/
|
*/
|
||||||
@ -261,6 +278,11 @@ struct TALER_KYCLOGIC_WebhookHandle
|
|||||||
*/
|
*/
|
||||||
uint64_t process_row;
|
uint64_t process_row;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP response code we got from KYCAID.
|
||||||
|
*/
|
||||||
|
unsigned int kycaid_response_code;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HTTP response code to return asynchronously.
|
* HTTP response code to return asynchronously.
|
||||||
*/
|
*/
|
||||||
@ -277,6 +299,7 @@ static void
|
|||||||
kycaid_unload_configuration (struct TALER_KYCLOGIC_ProviderDetails *pd)
|
kycaid_unload_configuration (struct TALER_KYCLOGIC_ProviderDetails *pd)
|
||||||
{
|
{
|
||||||
curl_slist_free_all (pd->slist);
|
curl_slist_free_all (pd->slist);
|
||||||
|
GNUNET_free (pd->conversion_helper);
|
||||||
GNUNET_free (pd->auth_token);
|
GNUNET_free (pd->auth_token);
|
||||||
GNUNET_free (pd->form_id);
|
GNUNET_free (pd->form_id);
|
||||||
GNUNET_free (pd->section);
|
GNUNET_free (pd->section);
|
||||||
@ -337,6 +360,18 @@ kycaid_load_configuration (void *cls,
|
|||||||
kycaid_unload_configuration (pd);
|
kycaid_unload_configuration (pd);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
GNUNET_CONFIGURATION_get_value_filename (ps->cfg,
|
||||||
|
provider_section_name,
|
||||||
|
"KYC_KYCAID_CONVERTER_HELPER",
|
||||||
|
&pd->conversion_helper))
|
||||||
|
{
|
||||||
|
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
|
||||||
|
provider_section_name,
|
||||||
|
"KYC_KYCAID_CONVERTER_HELPER");
|
||||||
|
kycaid_unload_configuration (pd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
{
|
{
|
||||||
char *auth;
|
char *auth;
|
||||||
|
|
||||||
@ -695,11 +730,21 @@ kycaid_webhook_cancel (struct TALER_KYCLOGIC_WebhookHandle *wh)
|
|||||||
GNUNET_SCHEDULER_cancel (wh->task);
|
GNUNET_SCHEDULER_cancel (wh->task);
|
||||||
wh->task = NULL;
|
wh->task = NULL;
|
||||||
}
|
}
|
||||||
|
if (NULL != wh->econ)
|
||||||
|
{
|
||||||
|
TALER_JSON_external_conversion_stop (wh->econ);
|
||||||
|
wh->econ = NULL;
|
||||||
|
}
|
||||||
if (NULL != wh->job)
|
if (NULL != wh->job)
|
||||||
{
|
{
|
||||||
GNUNET_CURL_job_cancel (wh->job);
|
GNUNET_CURL_job_cancel (wh->job);
|
||||||
wh->job = NULL;
|
wh->job = NULL;
|
||||||
}
|
}
|
||||||
|
if (NULL != wh->json_response)
|
||||||
|
{
|
||||||
|
json_decref (wh->json_response);
|
||||||
|
wh->json_response = NULL;
|
||||||
|
}
|
||||||
GNUNET_free (wh->verification_id);
|
GNUNET_free (wh->verification_id);
|
||||||
GNUNET_free (wh->applicant_id);
|
GNUNET_free (wh->applicant_id);
|
||||||
GNUNET_free (wh->url);
|
GNUNET_free (wh->url);
|
||||||
@ -750,6 +795,97 @@ log_failure (json_t *verifications)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type of a callback that receives a JSON @a result.
|
||||||
|
*
|
||||||
|
* @param cls closure our `struct TALER_KYCLOGIC_WebhookHandle *`
|
||||||
|
* @param status_type how did the process die
|
||||||
|
* @param code termination status code from the process
|
||||||
|
* @param result converted attribute data, NULL on failure
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
webhook_conversion_cb (void *cls,
|
||||||
|
enum GNUNET_OS_ProcessStatusType status_type,
|
||||||
|
unsigned long code,
|
||||||
|
const json_t *result)
|
||||||
|
{
|
||||||
|
struct TALER_KYCLOGIC_WebhookHandle *wh = cls;
|
||||||
|
struct GNUNET_TIME_Absolute expiration;
|
||||||
|
struct MHD_Response *resp;
|
||||||
|
|
||||||
|
wh->econ = NULL;
|
||||||
|
if ( (0 == code) ||
|
||||||
|
(NULL == result) )
|
||||||
|
{
|
||||||
|
/* No result, but *our helper* was OK => bad input */
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
json_dumpf (wh->json_response,
|
||||||
|
stderr,
|
||||||
|
JSON_INDENT (2));
|
||||||
|
resp = TALER_MHD_MAKE_JSON_PACK (
|
||||||
|
GNUNET_JSON_pack_uint64 ("kycaid_http_status",
|
||||||
|
wh->kycaid_response_code),
|
||||||
|
GNUNET_JSON_pack_object_incref ("kycaid_body",
|
||||||
|
(json_t *) wh->json_response));
|
||||||
|
wh->cb (wh->cb_cls,
|
||||||
|
wh->process_row,
|
||||||
|
&wh->h_payto,
|
||||||
|
wh->pd->section,
|
||||||
|
wh->applicant_id,
|
||||||
|
wh->verification_id,
|
||||||
|
TALER_KYCLOGIC_STATUS_PROVIDER_FAILED,
|
||||||
|
GNUNET_TIME_UNIT_ZERO_ABS, /* expiration */
|
||||||
|
NULL,
|
||||||
|
MHD_HTTP_BAD_GATEWAY,
|
||||||
|
resp);
|
||||||
|
kycaid_webhook_cancel (wh);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (NULL == result)
|
||||||
|
{
|
||||||
|
/* Failure in our helper */
|
||||||
|
GNUNET_break (0);
|
||||||
|
json_dumpf (wh->json_response,
|
||||||
|
stderr,
|
||||||
|
JSON_INDENT (2));
|
||||||
|
resp = TALER_MHD_MAKE_JSON_PACK (
|
||||||
|
GNUNET_JSON_pack_uint64 ("kycaid_http_status",
|
||||||
|
wh->kycaid_response_code),
|
||||||
|
GNUNET_JSON_pack_object_incref ("kycaid_body",
|
||||||
|
(json_t *) wh->json_response));
|
||||||
|
wh->cb (wh->cb_cls,
|
||||||
|
wh->process_row,
|
||||||
|
&wh->h_payto,
|
||||||
|
wh->pd->section,
|
||||||
|
wh->applicant_id,
|
||||||
|
wh->verification_id,
|
||||||
|
TALER_KYCLOGIC_STATUS_PROVIDER_FAILED,
|
||||||
|
GNUNET_TIME_UNIT_ZERO_ABS, /* expiration */
|
||||||
|
NULL,
|
||||||
|
MHD_HTTP_BAD_GATEWAY,
|
||||||
|
resp);
|
||||||
|
kycaid_webhook_cancel (wh);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
expiration = GNUNET_TIME_relative_to_absolute (wh->pd->validity);
|
||||||
|
resp = MHD_create_response_from_buffer (0,
|
||||||
|
"",
|
||||||
|
MHD_RESPMEM_PERSISTENT);
|
||||||
|
wh->cb (wh->cb_cls,
|
||||||
|
wh->process_row,
|
||||||
|
&wh->h_payto,
|
||||||
|
wh->pd->section,
|
||||||
|
wh->applicant_id,
|
||||||
|
wh->verification_id,
|
||||||
|
TALER_KYCLOGIC_STATUS_SUCCESS,
|
||||||
|
expiration,
|
||||||
|
result,
|
||||||
|
MHD_HTTP_NO_CONTENT,
|
||||||
|
resp);
|
||||||
|
kycaid_webhook_cancel (wh);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function called when we're done processing the
|
* Function called when we're done processing the
|
||||||
* HTTP "/applicants/{verification_id}" request.
|
* HTTP "/applicants/{verification_id}" request.
|
||||||
@ -768,246 +904,20 @@ handle_webhook_finished (void *cls,
|
|||||||
struct MHD_Response *resp;
|
struct MHD_Response *resp;
|
||||||
|
|
||||||
wh->job = NULL;
|
wh->job = NULL;
|
||||||
|
wh->kycaid_response_code = response_code;
|
||||||
|
wh->json_response = json_incref ((json_t *) j);
|
||||||
switch (response_code)
|
switch (response_code)
|
||||||
{
|
{
|
||||||
case MHD_HTTP_OK:
|
case MHD_HTTP_OK:
|
||||||
{
|
{
|
||||||
const char *type;
|
|
||||||
const char *profile_status;
|
const char *profile_status;
|
||||||
const char *first_name = NULL;
|
|
||||||
const char *last_name = NULL;
|
|
||||||
const char *middle_name = NULL;
|
|
||||||
const char *dob = NULL;
|
|
||||||
const char *residence_country = NULL;
|
|
||||||
const char *gender = NULL;
|
|
||||||
bool pep = false;
|
|
||||||
bool no_pep = false;
|
|
||||||
const char *company_name = NULL;
|
|
||||||
const char *business_activity_id = NULL;
|
|
||||||
const char *registration_country = NULL;
|
|
||||||
const char *email = NULL;
|
|
||||||
const char *phone = NULL;
|
|
||||||
json_t *addresses = NULL;
|
|
||||||
json_t *documents = NULL;
|
|
||||||
struct GNUNET_JSON_Specification spec[] = {
|
|
||||||
GNUNET_JSON_spec_string ("type",
|
|
||||||
&type),
|
|
||||||
GNUNET_JSON_spec_string ("profile_status",
|
|
||||||
&profile_status), /* valid, invalid, pending */
|
|
||||||
GNUNET_JSON_spec_mark_optional (
|
|
||||||
GNUNET_JSON_spec_string ("email",
|
|
||||||
&email),
|
|
||||||
NULL),
|
|
||||||
GNUNET_JSON_spec_mark_optional (
|
|
||||||
GNUNET_JSON_spec_string ("phone",
|
|
||||||
&phone),
|
|
||||||
NULL),
|
|
||||||
GNUNET_JSON_spec_mark_optional (
|
|
||||||
GNUNET_JSON_spec_json ("addresses",
|
|
||||||
&addresses),
|
|
||||||
NULL),
|
|
||||||
GNUNET_JSON_spec_mark_optional (
|
|
||||||
GNUNET_JSON_spec_json ("documents",
|
|
||||||
&documents),
|
|
||||||
NULL),
|
|
||||||
GNUNET_JSON_spec_end ()
|
|
||||||
};
|
|
||||||
struct GNUNET_JSON_Specification bspec[] = {
|
|
||||||
GNUNET_JSON_spec_mark_optional (
|
|
||||||
GNUNET_JSON_spec_string ("company_name",
|
|
||||||
&company_name),
|
|
||||||
NULL),
|
|
||||||
GNUNET_JSON_spec_mark_optional (
|
|
||||||
GNUNET_JSON_spec_string ("business_activity_id",
|
|
||||||
&business_activity_id),
|
|
||||||
NULL),
|
|
||||||
GNUNET_JSON_spec_mark_optional (
|
|
||||||
GNUNET_JSON_spec_string ("registration_country",
|
|
||||||
®istration_country),
|
|
||||||
NULL),
|
|
||||||
GNUNET_JSON_spec_end ()
|
|
||||||
};
|
|
||||||
struct GNUNET_JSON_Specification pspec[] = {
|
|
||||||
GNUNET_JSON_spec_mark_optional (
|
|
||||||
GNUNET_JSON_spec_string ("first_name",
|
|
||||||
&first_name),
|
|
||||||
NULL),
|
|
||||||
GNUNET_JSON_spec_mark_optional (
|
|
||||||
GNUNET_JSON_spec_string ("middle_name",
|
|
||||||
&middle_name),
|
|
||||||
NULL),
|
|
||||||
GNUNET_JSON_spec_mark_optional (
|
|
||||||
GNUNET_JSON_spec_string ("last_name",
|
|
||||||
&last_name),
|
|
||||||
NULL),
|
|
||||||
GNUNET_JSON_spec_mark_optional (
|
|
||||||
GNUNET_JSON_spec_string ("dob",
|
|
||||||
&dob),
|
|
||||||
NULL),
|
|
||||||
GNUNET_JSON_spec_mark_optional (
|
|
||||||
GNUNET_JSON_spec_string ("residence_country",
|
|
||||||
&residence_country),
|
|
||||||
NULL),
|
|
||||||
GNUNET_JSON_spec_mark_optional (
|
|
||||||
GNUNET_JSON_spec_string ("gender",
|
|
||||||
&gender),
|
|
||||||
NULL),
|
|
||||||
GNUNET_JSON_spec_mark_optional (
|
|
||||||
GNUNET_JSON_spec_bool ("pep",
|
|
||||||
&pep),
|
|
||||||
&no_pep),
|
|
||||||
GNUNET_JSON_spec_end ()
|
|
||||||
};
|
|
||||||
struct GNUNET_JSON_Specification *ispec = NULL;
|
|
||||||
struct GNUNET_TIME_Absolute expiration;
|
|
||||||
bool no_parse;
|
|
||||||
enum TALER_KYCLOGIC_KycUserType ut;
|
|
||||||
|
|
||||||
no_parse = (GNUNET_OK !=
|
profile_status = json_string_value (
|
||||||
GNUNET_JSON_parse (j,
|
json_object_get (
|
||||||
spec,
|
j,
|
||||||
NULL, NULL));
|
"profile_status"));
|
||||||
if (! no_parse)
|
if (0 != strcasecmp ("valid",
|
||||||
{
|
|
||||||
ut = (0 == strcasecmp ("person",
|
|
||||||
type))
|
|
||||||
? TALER_KYCLOGIC_KYC_UT_INDIVIDUAL
|
|
||||||
: TALER_KYCLOGIC_KYC_UT_BUSINESS;
|
|
||||||
ispec = (ut == TALER_KYCLOGIC_KYC_UT_INDIVIDUAL)
|
|
||||||
? pspec
|
|
||||||
: bspec;
|
|
||||||
no_parse = (GNUNET_OK !=
|
|
||||||
GNUNET_JSON_parse (j,
|
|
||||||
ispec,
|
|
||||||
NULL, NULL));
|
|
||||||
}
|
|
||||||
if (no_parse)
|
|
||||||
{
|
|
||||||
GNUNET_break_op (0);
|
|
||||||
json_dumpf (j,
|
|
||||||
stderr,
|
|
||||||
JSON_INDENT (2));
|
|
||||||
resp = TALER_MHD_MAKE_JSON_PACK (
|
|
||||||
GNUNET_JSON_pack_uint64 ("kycaid_http_status",
|
|
||||||
response_code),
|
|
||||||
GNUNET_JSON_pack_object_incref ("kycaid_body",
|
|
||||||
(json_t *) j));
|
|
||||||
wh->cb (wh->cb_cls,
|
|
||||||
wh->process_row,
|
|
||||||
&wh->h_payto,
|
|
||||||
wh->pd->section,
|
|
||||||
wh->applicant_id,
|
|
||||||
wh->verification_id,
|
|
||||||
TALER_KYCLOGIC_STATUS_PROVIDER_FAILED,
|
|
||||||
GNUNET_TIME_UNIT_ZERO_ABS, /* expiration */
|
|
||||||
NULL,
|
|
||||||
MHD_HTTP_BAD_GATEWAY,
|
|
||||||
resp);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (0 == strcasecmp ("valid",
|
|
||||||
profile_status))
|
profile_status))
|
||||||
{
|
|
||||||
log_failure (json_object_get (j,
|
|
||||||
"decline_reasons"));
|
|
||||||
}
|
|
||||||
resp = MHD_create_response_from_buffer (0,
|
|
||||||
"",
|
|
||||||
MHD_RESPMEM_PERSISTENT);
|
|
||||||
if (0 == strcasecmp ("valid",
|
|
||||||
profile_status))
|
|
||||||
{
|
|
||||||
json_t *attr;
|
|
||||||
|
|
||||||
if (ut == TALER_KYCLOGIC_KYC_UT_INDIVIDUAL)
|
|
||||||
{
|
|
||||||
char *name = NULL;
|
|
||||||
|
|
||||||
if ( (NULL != last_name) ||
|
|
||||||
(NULL != first_name) ||
|
|
||||||
(NULL != middle_name) )
|
|
||||||
{
|
|
||||||
GNUNET_asprintf (&name,
|
|
||||||
"%s, %s %s",
|
|
||||||
(NULL != last_name)
|
|
||||||
? last_name
|
|
||||||
: "",
|
|
||||||
(NULL != first_name)
|
|
||||||
? first_name
|
|
||||||
: "",
|
|
||||||
(NULL != middle_name)
|
|
||||||
? middle_name
|
|
||||||
: "");
|
|
||||||
}
|
|
||||||
attr = GNUNET_JSON_PACK (
|
|
||||||
GNUNET_JSON_pack_allow_null (
|
|
||||||
GNUNET_JSON_pack_string (
|
|
||||||
TALER_ATTRIBUTE_BIRTHDATE,
|
|
||||||
dob)),
|
|
||||||
GNUNET_JSON_pack_allow_null (
|
|
||||||
no_pep
|
|
||||||
? GNUNET_JSON_pack_string (
|
|
||||||
TALER_ATTRIBUTE_PEP,
|
|
||||||
NULL)
|
|
||||||
: GNUNET_JSON_pack_bool (
|
|
||||||
TALER_ATTRIBUTE_PEP,
|
|
||||||
pep)),
|
|
||||||
GNUNET_JSON_pack_allow_null (
|
|
||||||
GNUNET_JSON_pack_string (
|
|
||||||
TALER_ATTRIBUTE_FULL_NAME,
|
|
||||||
name)),
|
|
||||||
GNUNET_JSON_pack_allow_null (
|
|
||||||
GNUNET_JSON_pack_string (
|
|
||||||
TALER_ATTRIBUTE_PHONE,
|
|
||||||
phone)),
|
|
||||||
GNUNET_JSON_pack_allow_null (
|
|
||||||
GNUNET_JSON_pack_string (
|
|
||||||
TALER_ATTRIBUTE_EMAIL,
|
|
||||||
email)),
|
|
||||||
GNUNET_JSON_pack_allow_null (
|
|
||||||
GNUNET_JSON_pack_string (
|
|
||||||
TALER_ATTRIBUTE_RESIDENCES,
|
|
||||||
residence_country))
|
|
||||||
);
|
|
||||||
GNUNET_free (name);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
attr = GNUNET_JSON_PACK (
|
|
||||||
GNUNET_JSON_pack_allow_null (
|
|
||||||
GNUNET_JSON_pack_string (
|
|
||||||
TALER_ATTRIBUTE_COMPANY_NAME,
|
|
||||||
company_name)),
|
|
||||||
GNUNET_JSON_pack_allow_null (
|
|
||||||
GNUNET_JSON_pack_string (
|
|
||||||
TALER_ATTRIBUTE_PHONE,
|
|
||||||
phone)),
|
|
||||||
GNUNET_JSON_pack_allow_null (
|
|
||||||
GNUNET_JSON_pack_string (
|
|
||||||
TALER_ATTRIBUTE_EMAIL,
|
|
||||||
email)),
|
|
||||||
GNUNET_JSON_pack_allow_null (
|
|
||||||
GNUNET_JSON_pack_string (
|
|
||||||
TALER_ATTRIBUTE_REGISTRATION_COUNTRY,
|
|
||||||
residence_country))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
// FIXME: do something about addresses & documents!
|
|
||||||
expiration = GNUNET_TIME_relative_to_absolute (wh->pd->validity);
|
|
||||||
wh->cb (wh->cb_cls,
|
|
||||||
wh->process_row,
|
|
||||||
&wh->h_payto,
|
|
||||||
wh->pd->section,
|
|
||||||
wh->applicant_id,
|
|
||||||
wh->verification_id,
|
|
||||||
TALER_KYCLOGIC_STATUS_SUCCESS,
|
|
||||||
expiration,
|
|
||||||
attr,
|
|
||||||
MHD_HTTP_NO_CONTENT,
|
|
||||||
resp);
|
|
||||||
json_decref (attr);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
enum TALER_KYCLOGIC_KycStatus ks;
|
enum TALER_KYCLOGIC_KycStatus ks;
|
||||||
|
|
||||||
@ -1015,6 +925,9 @@ handle_webhook_finished (void *cls,
|
|||||||
profile_status))
|
profile_status))
|
||||||
? TALER_KYCLOGIC_STATUS_PENDING
|
? TALER_KYCLOGIC_STATUS_PENDING
|
||||||
: TALER_KYCLOGIC_STATUS_USER_ABORTED;
|
: TALER_KYCLOGIC_STATUS_USER_ABORTED;
|
||||||
|
resp = MHD_create_response_from_buffer (0,
|
||||||
|
"",
|
||||||
|
MHD_RESPMEM_PERSISTENT);
|
||||||
wh->cb (wh->cb_cls,
|
wh->cb (wh->cb_cls,
|
||||||
wh->process_row,
|
wh->process_row,
|
||||||
&wh->h_payto,
|
&wh->h_payto,
|
||||||
@ -1026,9 +939,19 @@ handle_webhook_finished (void *cls,
|
|||||||
NULL,
|
NULL,
|
||||||
MHD_HTTP_NO_CONTENT,
|
MHD_HTTP_NO_CONTENT,
|
||||||
resp);
|
resp);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
GNUNET_JSON_parse_free (ispec);
|
wh->econ
|
||||||
GNUNET_JSON_parse_free (spec);
|
= TALER_JSON_external_conversion_start (
|
||||||
|
j,
|
||||||
|
&webhook_conversion_cb,
|
||||||
|
wh,
|
||||||
|
wh->pd->conversion_helper,
|
||||||
|
wh->pd->conversion_helper,
|
||||||
|
"-a",
|
||||||
|
wh->pd->auth_token,
|
||||||
|
NULL);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MHD_HTTP_BAD_REQUEST:
|
case MHD_HTTP_BAD_REQUEST:
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
This file is part of GNU Taler
|
This file is part of GNU Taler
|
||||||
Copyright (C) 2022 Taler Systems SA
|
Copyright (C) 2022-2023 Taler Systems SA
|
||||||
|
|
||||||
Taler is free software; you can redistribute it and/or modify it under the
|
Taler is free software; you can redistribute it and/or modify it under the
|
||||||
terms of the GNU Affero General Public License as published by the Free Software
|
terms of the GNU Affero General Public License as published by the Free Software
|
||||||
@ -75,15 +75,21 @@ struct TALER_KYCLOGIC_ProviderDetails
|
|||||||
char *section;
|
char *section;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* URL of the OAuth2.0 endpoint for KYC checks.
|
* URL of the Challenger ``/setup`` endpoint for
|
||||||
* (token/auth)
|
* approving address validations. NULL if not used.
|
||||||
*/
|
*/
|
||||||
char *auth_url;
|
char *setup_url;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* URL of the OAuth2.0 endpoint for KYC checks.
|
* URL of the OAuth2.0 endpoint for KYC checks.
|
||||||
*/
|
*/
|
||||||
char *login_url;
|
char *authorize_url;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* URL of the OAuth2.0 endpoint for KYC checks.
|
||||||
|
* (token/auth)
|
||||||
|
*/
|
||||||
|
char *token_url;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* URL of the user info access endpoint.
|
* URL of the user info access endpoint.
|
||||||
@ -147,6 +153,11 @@ struct TALER_KYCLOGIC_InitiateHandle
|
|||||||
*/
|
*/
|
||||||
struct GNUNET_SCHEDULER_Task *task;
|
struct GNUNET_SCHEDULER_Task *task;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle for the OAuth 2.0 setup request.
|
||||||
|
*/
|
||||||
|
struct GNUNET_CURL_Job *job;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Continuation to call.
|
* Continuation to call.
|
||||||
*/
|
*/
|
||||||
@ -283,8 +294,9 @@ static void
|
|||||||
oauth2_unload_configuration (struct TALER_KYCLOGIC_ProviderDetails *pd)
|
oauth2_unload_configuration (struct TALER_KYCLOGIC_ProviderDetails *pd)
|
||||||
{
|
{
|
||||||
GNUNET_free (pd->section);
|
GNUNET_free (pd->section);
|
||||||
GNUNET_free (pd->auth_url);
|
GNUNET_free (pd->token_url);
|
||||||
GNUNET_free (pd->login_url);
|
GNUNET_free (pd->setup_url);
|
||||||
|
GNUNET_free (pd->authorize_url);
|
||||||
GNUNET_free (pd->info_url);
|
GNUNET_free (pd->info_url);
|
||||||
GNUNET_free (pd->client_id);
|
GNUNET_free (pd->client_id);
|
||||||
GNUNET_free (pd->client_secret);
|
GNUNET_free (pd->client_secret);
|
||||||
@ -327,12 +339,12 @@ oauth2_load_configuration (void *cls,
|
|||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
GNUNET_CONFIGURATION_get_value_string (ps->cfg,
|
GNUNET_CONFIGURATION_get_value_string (ps->cfg,
|
||||||
provider_section_name,
|
provider_section_name,
|
||||||
"KYC_OAUTH2_AUTH_URL",
|
"KYC_OAUTH2_TOKEN_URL",
|
||||||
&s))
|
&s))
|
||||||
{
|
{
|
||||||
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
|
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
|
||||||
provider_section_name,
|
provider_section_name,
|
||||||
"KYC_OAUTH2_AUTH_URL");
|
"KYC_OAUTH2_TOKEN_URL");
|
||||||
oauth2_unload_configuration (pd);
|
oauth2_unload_configuration (pd);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -346,23 +358,23 @@ oauth2_load_configuration (void *cls,
|
|||||||
{
|
{
|
||||||
GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
|
GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
|
||||||
provider_section_name,
|
provider_section_name,
|
||||||
"KYC_OAUTH2_AUTH_URL",
|
"KYC_OAUTH2_TOKEN_URL",
|
||||||
"not a valid URL");
|
"not a valid URL");
|
||||||
GNUNET_free (s);
|
GNUNET_free (s);
|
||||||
oauth2_unload_configuration (pd);
|
oauth2_unload_configuration (pd);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
pd->auth_url = s;
|
pd->token_url = s;
|
||||||
|
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
GNUNET_CONFIGURATION_get_value_string (ps->cfg,
|
GNUNET_CONFIGURATION_get_value_string (ps->cfg,
|
||||||
provider_section_name,
|
provider_section_name,
|
||||||
"KYC_OAUTH2_LOGIN_URL",
|
"KYC_OAUTH2_AUTHORIZE_URL",
|
||||||
&s))
|
&s))
|
||||||
{
|
{
|
||||||
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
|
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
|
||||||
provider_section_name,
|
provider_section_name,
|
||||||
"KYC_OAUTH2_LOGIN_URL");
|
"KYC_OAUTH2_AUTHORIZE_URL");
|
||||||
oauth2_unload_configuration (pd);
|
oauth2_unload_configuration (pd);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -376,13 +388,41 @@ oauth2_load_configuration (void *cls,
|
|||||||
{
|
{
|
||||||
GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
|
GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
|
||||||
provider_section_name,
|
provider_section_name,
|
||||||
"KYC_OAUTH2_LOGIN_URL",
|
"KYC_OAUTH2_AUTHORIZE_URL",
|
||||||
"not a valid URL");
|
"not a valid URL");
|
||||||
oauth2_unload_configuration (pd);
|
oauth2_unload_configuration (pd);
|
||||||
GNUNET_free (s);
|
GNUNET_free (s);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
pd->login_url = s;
|
if (NULL != strchr (s, '#'))
|
||||||
|
{
|
||||||
|
const char *extra = strchr (s, '#');
|
||||||
|
const char *slash = strrchr (s, '/');
|
||||||
|
|
||||||
|
if ( (0 != strcmp (extra,
|
||||||
|
"#setup")) ||
|
||||||
|
(NULL == slash) )
|
||||||
|
{
|
||||||
|
GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
|
||||||
|
provider_section_name,
|
||||||
|
"KYC_OAUTH2_AUTHORIZE_URL",
|
||||||
|
"not a valid authorze URL (bad fragment)");
|
||||||
|
oauth2_unload_configuration (pd);
|
||||||
|
GNUNET_free (s);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
pd->authorize_url = GNUNET_strndup (s,
|
||||||
|
extra - s);
|
||||||
|
GNUNET_asprintf (&pd->setup_url,
|
||||||
|
"%.*s/setup",
|
||||||
|
(int) (slash - s),
|
||||||
|
s);
|
||||||
|
GNUNET_free (s);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pd->authorize_url = s;
|
||||||
|
}
|
||||||
|
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
GNUNET_CONFIGURATION_get_value_string (ps->cfg,
|
GNUNET_CONFIGURATION_get_value_string (ps->cfg,
|
||||||
@ -480,19 +520,20 @@ oauth2_load_configuration (void *cls,
|
|||||||
* how to begin the OAuth2.0 checking process to
|
* how to begin the OAuth2.0 checking process to
|
||||||
* the client.
|
* the client.
|
||||||
*
|
*
|
||||||
* @param cls a `struct TALER_KYCLOGIC_InitiateHandle *`
|
* @param ih process to redirect for
|
||||||
|
* @param authorize_url authorization URL to use
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
initiate_task (void *cls)
|
initiate_with_url (struct TALER_KYCLOGIC_InitiateHandle *ih,
|
||||||
|
const char *authorize_url)
|
||||||
{
|
{
|
||||||
struct TALER_KYCLOGIC_InitiateHandle *ih = cls;
|
|
||||||
const struct TALER_KYCLOGIC_ProviderDetails *pd = ih->pd;
|
const struct TALER_KYCLOGIC_ProviderDetails *pd = ih->pd;
|
||||||
struct PluginState *ps = pd->ps;
|
struct PluginState *ps = pd->ps;
|
||||||
char *hps;
|
char *hps;
|
||||||
char *url;
|
char *url;
|
||||||
char legi_s[42];
|
char legi_s[42];
|
||||||
|
|
||||||
ih->task = NULL;
|
|
||||||
GNUNET_snprintf (legi_s,
|
GNUNET_snprintf (legi_s,
|
||||||
sizeof (legi_s),
|
sizeof (legi_s),
|
||||||
"%llu",
|
"%llu",
|
||||||
@ -515,16 +556,11 @@ initiate_task (void *cls)
|
|||||||
}
|
}
|
||||||
GNUNET_asprintf (&url,
|
GNUNET_asprintf (&url,
|
||||||
"%s?response_type=code&client_id=%s&redirect_uri=%s",
|
"%s?response_type=code&client_id=%s&redirect_uri=%s",
|
||||||
pd->login_url,
|
authorize_url,
|
||||||
pd->client_id,
|
pd->client_id,
|
||||||
redirect_uri_encoded);
|
redirect_uri_encoded);
|
||||||
GNUNET_free (redirect_uri_encoded);
|
GNUNET_free (redirect_uri_encoded);
|
||||||
}
|
}
|
||||||
/* FIXME-API: why do we *redirect* the client here,
|
|
||||||
instead of making the HTTP request *ourselves*
|
|
||||||
and forwarding the response? This prevents us
|
|
||||||
from using authentication on initiation,
|
|
||||||
(which is desirable for challenger!) */
|
|
||||||
ih->cb (ih->cb_cls,
|
ih->cb (ih->cb_cls,
|
||||||
TALER_EC_NONE,
|
TALER_EC_NONE,
|
||||||
url,
|
url,
|
||||||
@ -537,6 +573,142 @@ initiate_task (void *cls)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* After we are done with the CURL interaction we
|
||||||
|
* need to update our database state with the information
|
||||||
|
* retrieved.
|
||||||
|
*
|
||||||
|
* @param cls a `struct TALER_KYCLOGIC_InitiateHandle *`
|
||||||
|
* @param response_code HTTP response code from server, 0 on hard error
|
||||||
|
* @param response in JSON, NULL if response was not in JSON format
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
handle_curl_setup_finished (void *cls,
|
||||||
|
long response_code,
|
||||||
|
const void *response)
|
||||||
|
{
|
||||||
|
struct TALER_KYCLOGIC_InitiateHandle *ih = cls;
|
||||||
|
const struct TALER_KYCLOGIC_ProviderDetails *pd = ih->pd;
|
||||||
|
const json_t *j = response;
|
||||||
|
|
||||||
|
ih->job = NULL;
|
||||||
|
switch (response_code)
|
||||||
|
{
|
||||||
|
case MHD_HTTP_OK:
|
||||||
|
{
|
||||||
|
const char *nonce;
|
||||||
|
struct GNUNET_JSON_Specification spec[] = {
|
||||||
|
GNUNET_JSON_spec_string ("nonce",
|
||||||
|
&nonce),
|
||||||
|
GNUNET_JSON_spec_end ()
|
||||||
|
};
|
||||||
|
enum GNUNET_GenericReturnValue res;
|
||||||
|
const char *emsg;
|
||||||
|
unsigned int line;
|
||||||
|
char *url;
|
||||||
|
|
||||||
|
res = GNUNET_JSON_parse (j,
|
||||||
|
spec,
|
||||||
|
&emsg,
|
||||||
|
&line);
|
||||||
|
if (GNUNET_OK != res)
|
||||||
|
{
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
json_dumpf (j,
|
||||||
|
stderr,
|
||||||
|
JSON_INDENT (2));
|
||||||
|
ih->cb (ih->cb_cls,
|
||||||
|
TALER_EC_EXCHANGE_KYC_PROOF_BACKEND_INVALID_RESPONSE,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
"Unexpected response from KYC gateway: setup must return a nonce");
|
||||||
|
GNUNET_free (ih);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
GNUNET_asprintf (&url,
|
||||||
|
"%s/%s",
|
||||||
|
pd->setup_url,
|
||||||
|
nonce);
|
||||||
|
initiate_with_url (ih,
|
||||||
|
url);
|
||||||
|
GNUNET_free (url);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||||
|
"/setup URL returned HTTP status %u\n",
|
||||||
|
(unsigned int) response_code);
|
||||||
|
ih->cb (ih->cb_cls,
|
||||||
|
TALER_EC_EXCHANGE_KYC_PROOF_BACKEND_INVALID_RESPONSE,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
"/setup request to OAuth 2.0 backend returned unexpected HTTP status code");
|
||||||
|
GNUNET_free (ih);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logic to asynchronously return the response for how to begin the OAuth2.0
|
||||||
|
* checking process to the client. May first request a dynamic URL via
|
||||||
|
* ``/setup`` if configured to use a client-authenticated setup process.
|
||||||
|
*
|
||||||
|
* @param cls a `struct TALER_KYCLOGIC_InitiateHandle *`
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
initiate_task (void *cls)
|
||||||
|
{
|
||||||
|
struct TALER_KYCLOGIC_InitiateHandle *ih = cls;
|
||||||
|
const struct TALER_KYCLOGIC_ProviderDetails *pd = ih->pd;
|
||||||
|
struct PluginState *ps = pd->ps;
|
||||||
|
char *hdr;
|
||||||
|
struct curl_slist *slist;
|
||||||
|
CURL *eh;
|
||||||
|
|
||||||
|
ih->task = NULL;
|
||||||
|
if (NULL == pd->setup_url)
|
||||||
|
{
|
||||||
|
initiate_with_url (ih,
|
||||||
|
pd->authorize_url);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
eh = curl_easy_init ();
|
||||||
|
if (NULL == eh)
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
ih->cb (ih->cb_cls,
|
||||||
|
TALER_EC_GENERIC_ALLOCATION_FAILURE,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
"curl_easy_init() failed");
|
||||||
|
GNUNET_free (ih);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
GNUNET_assert (CURLE_OK ==
|
||||||
|
curl_easy_setopt (eh,
|
||||||
|
CURLOPT_URL,
|
||||||
|
pd->setup_url));
|
||||||
|
GNUNET_asprintf (&hdr,
|
||||||
|
"%s: Bearer %s",
|
||||||
|
MHD_HTTP_HEADER_AUTHORIZATION,
|
||||||
|
pd->client_secret);
|
||||||
|
slist = curl_slist_append (NULL,
|
||||||
|
hdr);
|
||||||
|
ih->job = GNUNET_CURL_job_add2 (ps->curl_ctx,
|
||||||
|
eh,
|
||||||
|
slist,
|
||||||
|
&handle_curl_setup_finished,
|
||||||
|
ih);
|
||||||
|
curl_slist_free_all (slist);
|
||||||
|
GNUNET_free (hdr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initiate KYC check.
|
* Initiate KYC check.
|
||||||
*
|
*
|
||||||
@ -584,6 +756,11 @@ oauth2_initiate_cancel (struct TALER_KYCLOGIC_InitiateHandle *ih)
|
|||||||
GNUNET_SCHEDULER_cancel (ih->task);
|
GNUNET_SCHEDULER_cancel (ih->task);
|
||||||
ih->task = NULL;
|
ih->task = NULL;
|
||||||
}
|
}
|
||||||
|
if (NULL != ih->job)
|
||||||
|
{
|
||||||
|
GNUNET_CURL_job_cancel (ih->job);
|
||||||
|
ih->job = NULL;
|
||||||
|
}
|
||||||
GNUNET_free (ih);
|
GNUNET_free (ih);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1002,7 +1179,7 @@ handle_curl_login_finished (void *cls,
|
|||||||
eh = curl_easy_init ();
|
eh = curl_easy_init ();
|
||||||
if (NULL == eh)
|
if (NULL == eh)
|
||||||
{
|
{
|
||||||
GNUNET_break_op (0);
|
GNUNET_break (0);
|
||||||
ph->response
|
ph->response
|
||||||
= TALER_MHD_make_error (
|
= TALER_MHD_make_error (
|
||||||
TALER_EC_GENERIC_ALLOCATION_FAILURE,
|
TALER_EC_GENERIC_ALLOCATION_FAILURE,
|
||||||
@ -1129,7 +1306,7 @@ oauth2_proof (void *cls,
|
|||||||
GNUNET_assert (CURLE_OK ==
|
GNUNET_assert (CURLE_OK ==
|
||||||
curl_easy_setopt (ph->eh,
|
curl_easy_setopt (ph->eh,
|
||||||
CURLOPT_URL,
|
CURLOPT_URL,
|
||||||
pd->auth_url));
|
pd->token_url));
|
||||||
GNUNET_assert (CURLE_OK ==
|
GNUNET_assert (CURLE_OK ==
|
||||||
curl_easy_setopt (ph->eh,
|
curl_easy_setopt (ph->eh,
|
||||||
CURLOPT_POST,
|
CURLOPT_POST,
|
||||||
|
86
src/kyclogic/taler-exchange-kyc-kycaid-converter.sh
Normal file
86
src/kyclogic/taler-exchange-kyc-kycaid-converter.sh
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# This file is in the public domain.
|
||||||
|
#
|
||||||
|
# This code converts (some of) the JSON output from KYCAID into the GNU Taler
|
||||||
|
# specific KYC attribute data (again in JSON format). We may need to download
|
||||||
|
# and inline file data in the process, for authorization pass "-a" with the
|
||||||
|
# respective bearer token.
|
||||||
|
#
|
||||||
|
|
||||||
|
# Die if anything goes wrong.
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
# Parse command-line options
|
||||||
|
while getopts ':a:' OPTION; do
|
||||||
|
case "$OPTION" in
|
||||||
|
a)
|
||||||
|
TOKEN="$OPTARG"
|
||||||
|
;;
|
||||||
|
?)
|
||||||
|
echo "Unrecognized command line option"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# First, extract everything from stdin.
|
||||||
|
J=$(jq '{"type":.type,"email":.email,"phone":.phone,"first_name":.first_name,"name-middle":.middle_name,"last_name":.last_name,"dob":.dob,"residence_country":.residence_country,"gender":.gender,"pep":.pep,"addresses":.addresses,"documents":.documents,"company_name":.company_name,"business_activity_id":.business_activity_id,"registration_country":.registration_country,"documents":.documents,"decline_reasons":.decline_reasons}')
|
||||||
|
|
||||||
|
# TODO:
|
||||||
|
# log_failure (json_object_get (j, "decline_reasons"));
|
||||||
|
|
||||||
|
TYPE=$(echo "$J" | jq -r '.person')
|
||||||
|
|
||||||
|
N=0
|
||||||
|
DOCS_RAW=""
|
||||||
|
DOCS_JSON=""
|
||||||
|
for ID in $(jq -r '.documents[]|select(.status=="valid")|.id')
|
||||||
|
do
|
||||||
|
TYPE=$(jq -r ".documents[]|select(.id==\"$ID\")|.type")
|
||||||
|
EXPIRY=$(jq -r ".documents[]|select(.id==\"$ID\")|.expiry_date")
|
||||||
|
DOCUMENT_FILE=$(mktemp -t tmp.XXXXXXXXXX)
|
||||||
|
# Authoriazation: Token $TOKEN
|
||||||
|
DOCUMENT_URL="https://api.kycaid.com/documents/$ID"
|
||||||
|
if [ -z "${TOKEN:-}" ]
|
||||||
|
then
|
||||||
|
wget -q --output-document=- "$DOCUMENT_URL" \
|
||||||
|
| gnunet-base32 > ${DOCUMENT_FILE}
|
||||||
|
else
|
||||||
|
wget -q --output-document=- "$DOCUMENT_URL" \
|
||||||
|
--header "Authorization: Token $TOKEN" \
|
||||||
|
| gnunet-base32 > ${DOCUMENT_FILE}
|
||||||
|
fi
|
||||||
|
DOCS_RAW="$DOCS_RAW --rawfile photo$N \"${DOCUMENT_FILE}\""
|
||||||
|
if [ "$N" = 0 ]
|
||||||
|
then
|
||||||
|
DOCS_JSON="{\"type\":\"$TYPE\",\"image\":\$photo$N}"
|
||||||
|
else
|
||||||
|
DOCS_JSON="{\"type\":\"$TYPE\",\"image\":\$photo$N},$DOCS_JSON"
|
||||||
|
fi
|
||||||
|
N=$(expr $N + 1)
|
||||||
|
done
|
||||||
|
|
||||||
|
|
||||||
|
if [ "person" = "${TYPE}" ]
|
||||||
|
then
|
||||||
|
|
||||||
|
# Next, combine some fields into larger values.
|
||||||
|
FULLNAME=$(echo "$J" | jq -r '[.first_name,.middle_name,.last_name]|join(" ")')
|
||||||
|
# STREET=$(echo $J | jq -r '[."street-1",."street-2"]|join(" ")')
|
||||||
|
# CITY=$(echo $J | jq -r '[.postcode,.city,."address-subdivision,.cc"]|join(" ")')
|
||||||
|
|
||||||
|
# Combine into final result for individual.
|
||||||
|
# FIXME: does jq tolerate 'pep = NULL' here?
|
||||||
|
echo "$J" | jq \
|
||||||
|
--arg full_name "${FULLNAME}" \
|
||||||
|
'{$full_name,"birthdate":.dob,"pep":.pep,"phone":."phone","email",.email,"residences":.residence_country}'
|
||||||
|
|
||||||
|
else
|
||||||
|
# Combine into final result for business.
|
||||||
|
echo "$J" | jq \
|
||||||
|
--arg full_name "${FULLNAME}" \
|
||||||
|
$DOCS_RAW \
|
||||||
|
"{\"company_name\":.company_name,\"phone\":.phone,\"email\":.email,\"registration_country\":.registration_country,\"documents\":[${DOCS_JSON}]}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
@ -733,6 +733,7 @@ decode_keys_json (const json_t *resp_obj,
|
|||||||
struct TALER_ExchangePublicKeyP pub;
|
struct TALER_ExchangePublicKeyP pub;
|
||||||
const char *currency;
|
const char *currency;
|
||||||
const char *asset_type;
|
const char *asset_type;
|
||||||
|
bool tipping_allowed = true;
|
||||||
json_t *wblwk = NULL;
|
json_t *wblwk = NULL;
|
||||||
struct GNUNET_JSON_Specification mspec[] = {
|
struct GNUNET_JSON_Specification mspec[] = {
|
||||||
GNUNET_JSON_spec_fixed_auto ("denominations_sig",
|
GNUNET_JSON_spec_fixed_auto ("denominations_sig",
|
||||||
@ -749,6 +750,10 @@ decode_keys_json (const json_t *resp_obj,
|
|||||||
¤cy),
|
¤cy),
|
||||||
GNUNET_JSON_spec_string ("asset_type",
|
GNUNET_JSON_spec_string ("asset_type",
|
||||||
&asset_type),
|
&asset_type),
|
||||||
|
GNUNET_JSON_spec_mark_optional (
|
||||||
|
GNUNET_JSON_spec_bool ("tipping_allowed",
|
||||||
|
&tipping_allowed),
|
||||||
|
NULL),
|
||||||
GNUNET_JSON_spec_mark_optional (
|
GNUNET_JSON_spec_mark_optional (
|
||||||
GNUNET_JSON_spec_json ("wallet_balance_limit_without_kyc",
|
GNUNET_JSON_spec_json ("wallet_balance_limit_without_kyc",
|
||||||
&wblwk),
|
&wblwk),
|
||||||
@ -819,6 +824,7 @@ decode_keys_json (const json_t *resp_obj,
|
|||||||
NULL, NULL));
|
NULL, NULL));
|
||||||
key_data->currency = GNUNET_strdup (currency);
|
key_data->currency = GNUNET_strdup (currency);
|
||||||
key_data->asset_type = GNUNET_strdup (asset_type);
|
key_data->asset_type = GNUNET_strdup (asset_type);
|
||||||
|
key_data->tipping_allowed = tipping_allowed;
|
||||||
|
|
||||||
/* parse the global fees */
|
/* parse the global fees */
|
||||||
{
|
{
|
||||||
|
@ -78,7 +78,7 @@ TALER_MHD_parse_config (const struct GNUNET_CONFIGURATION_Handle *cfg,
|
|||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
GNUNET_CONFIGURATION_get_value_number (cfg,
|
GNUNET_CONFIGURATION_get_value_number (cfg,
|
||||||
section,
|
section,
|
||||||
"port",
|
"PORT",
|
||||||
&port))
|
&port))
|
||||||
{
|
{
|
||||||
GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
|
GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
|
||||||
|
@ -150,7 +150,7 @@ qconv_json (void *cls,
|
|||||||
if (SQLITE_OK != sqlite3_bind_text (stmt,
|
if (SQLITE_OK != sqlite3_bind_text (stmt,
|
||||||
(int) off,
|
(int) off,
|
||||||
str,
|
str,
|
||||||
strlen (str) + 1,
|
strlen (str),
|
||||||
SQLITE_TRANSIENT))
|
SQLITE_TRANSIENT))
|
||||||
return GNUNET_SYSERR;
|
return GNUNET_SYSERR;
|
||||||
GNUNET_free (str);
|
GNUNET_free (str);
|
||||||
|
@ -15,6 +15,8 @@ taler_mustach_tool_SOURCES = \
|
|||||||
taler_mustach_tool_LDADD = \
|
taler_mustach_tool_LDADD = \
|
||||||
libmustach.la \
|
libmustach.la \
|
||||||
-ljansson
|
-ljansson
|
||||||
|
taler_mustach_tool_CFLAGS = \
|
||||||
|
-DTOOL=MUSTACH_TOOL_JANSSON
|
||||||
|
|
||||||
lib_LTLIBRARIES = \
|
lib_LTLIBRARIES = \
|
||||||
libtalertemplating.la
|
libtalertemplating.la
|
||||||
|
@ -245,7 +245,7 @@ basic-tests: mustach
|
|||||||
@$(MAKE) -C test3 test
|
@$(MAKE) -C test3 test
|
||||||
@$(MAKE) -C test4 test
|
@$(MAKE) -C test4 test
|
||||||
@$(MAKE) -C test5 test
|
@$(MAKE) -C test5 test
|
||||||
@$(MAKE) -C test6 test
|
# @$(MAKE) -C test6 test
|
||||||
|
|
||||||
spec-tests: $(TESTSPECS)
|
spec-tests: $(TESTSPECS)
|
||||||
|
|
||||||
@ -298,4 +298,3 @@ manuals: mustach.1.gz
|
|||||||
|
|
||||||
mustach.1.gz: mustach.1.scd
|
mustach.1.gz: mustach.1.scd
|
||||||
if which scdoc >/dev/null 2>&1; then scdoc < mustach.1.scd | gzip > mustach.1.gz; fi
|
if which scdoc >/dev/null 2>&1; then scdoc < mustach.1.scd | gzip > mustach.1.gz; fi
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ template specification.
|
|||||||
|
|
||||||
The main site for `mustach` is on [gitlab](https://gitlab.com/jobol/mustach).
|
The main site for `mustach` is on [gitlab](https://gitlab.com/jobol/mustach).
|
||||||
|
|
||||||
The simpliest way to use mustach is to copy the files **mustach.h** and **mustach.c**
|
The simplest way to use mustach is to copy the files **mustach.h** and **mustach.c**
|
||||||
directly into your project and use it.
|
directly into your project and use it.
|
||||||
|
|
||||||
If you are using one of the JSON libraries listed below, you can get extended feature
|
If you are using one of the JSON libraries listed below, you can get extended feature
|
||||||
@ -85,7 +85,7 @@ It then outputs the result of applying the templates files to the JSON file.
|
|||||||
### Portability
|
### Portability
|
||||||
|
|
||||||
Some system does not provide *open_memstream*. In that case, tell your
|
Some system does not provide *open_memstream*. In that case, tell your
|
||||||
prefered compiler to declare the preprocessor symbol **NO_OPEN_MEMSTREAM**.
|
preferred compiler to declare the preprocessor symbol **NO_OPEN_MEMSTREAM**.
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
CFLAGS=-DNO_OPEN_MEMSTREAM make
|
CFLAGS=-DNO_OPEN_MEMSTREAM make
|
||||||
@ -163,7 +163,7 @@ Here is the summary.
|
|||||||
|
|
||||||
Flag name | Description
|
Flag name | Description
|
||||||
-------------------------------+------------------------------------------------
|
-------------------------------+------------------------------------------------
|
||||||
Mustach_With_Colon | Explicit tag substition with colon
|
Mustach_With_Colon | Explicit tag substitution with colon
|
||||||
Mustach_With_EmptyTag | Empty Tag Allowed
|
Mustach_With_EmptyTag | Empty Tag Allowed
|
||||||
-------------------------------+------------------------------------------------
|
-------------------------------+------------------------------------------------
|
||||||
Mustach_With_Equal | Value Testing Equality
|
Mustach_With_Equal | Value Testing Equality
|
||||||
@ -180,7 +180,7 @@ For the details, see below.
|
|||||||
|
|
||||||
### Explicit Tag Substitution With Colon (Mustach_With_Colon)
|
### Explicit Tag Substitution With Colon (Mustach_With_Colon)
|
||||||
|
|
||||||
In somecases the name of the key used for substition begins with a
|
In somecases the name of the key used for substitution begins with a
|
||||||
character reserved for mustach: one of `#`, `^`, `/`, `&`, `{`, `>` and `=`.
|
character reserved for mustach: one of `#`, `^`, `/`, `&`, `{`, `>` and `=`.
|
||||||
|
|
||||||
This extension introduces the special character `:` to explicitly
|
This extension introduces the special character `:` to explicitly
|
||||||
@ -311,4 +311,3 @@ The table below summarize the changes.
|
|||||||
fdmustach_json_c | mustach_json_c_fd
|
fdmustach_json_c | mustach_json_c_fd
|
||||||
mustach_json_c | mustach_json_c_mem
|
mustach_json_c | mustach_json_c_mem
|
||||||
mustach_json_c | mustach_json_c_write
|
mustach_json_c | mustach_json_c_write
|
||||||
|
|
||||||
|
@ -174,8 +174,6 @@ int main(int ac, char **av)
|
|||||||
#define MUSTACH_TOOL_JANSSON 2
|
#define MUSTACH_TOOL_JANSSON 2
|
||||||
#define MUSTACH_TOOL_CJSON 3
|
#define MUSTACH_TOOL_CJSON 3
|
||||||
|
|
||||||
#define TOOL MUSTACH_TOOL_JANSSON
|
|
||||||
|
|
||||||
#if TOOL == MUSTACH_TOOL_JSON_C
|
#if TOOL == MUSTACH_TOOL_JSON_C
|
||||||
|
|
||||||
#include "mustach-json-c.h"
|
#include "mustach-json-c.h"
|
||||||
|
@ -5,6 +5,9 @@ set -eu
|
|||||||
# even bother testing for it in configure.ac.
|
# even bother testing for it in configure.ac.
|
||||||
# However, in that case, skip the test suite.
|
# However, in that case, skip the test suite.
|
||||||
|
|
||||||
|
export CFLAGS="-g"
|
||||||
|
|
||||||
make -f Makefile.orig mustach || exit 77
|
make -f Makefile.orig mustach || exit 77
|
||||||
make -f Makefile.orig test
|
make -f Makefile.orig clean || true
|
||||||
|
make -f Makefile.orig basic-tests
|
||||||
make -f Makefile.orig clean || true
|
make -f Makefile.orig clean || true
|
||||||
|
@ -183,7 +183,7 @@ TALER_TEMPLATING_fill (const char *tmpl,
|
|||||||
(eno = mustach_jansson_mem (tmpl,
|
(eno = mustach_jansson_mem (tmpl,
|
||||||
0, /* length of tmpl */
|
0, /* length of tmpl */
|
||||||
(json_t *) root,
|
(json_t *) root,
|
||||||
Mustach_With_NoExtensions,
|
Mustach_With_AllExtensions,
|
||||||
(char **) result,
|
(char **) result,
|
||||||
result_size)))
|
result_size)))
|
||||||
{
|
{
|
||||||
|
@ -5,12 +5,12 @@
|
|||||||
"in_ca": true,
|
"in_ca": true,
|
||||||
"person": false,
|
"person": false,
|
||||||
"repo": [
|
"repo": [
|
||||||
{ "name": "resque", "who": [ { "committer": "joe" }, { "reviewer": "avrel" }, { "committer": "william" } ] },
|
{ "name": "resque", "who": [ { "commiter": "joe" }, { "reviewer": "avrel" }, { "commiter": "william" } ] },
|
||||||
{ "name": "hub", "who": [ { "committer": "jack" }, { "reviewer": "avrel" }, { "committer": "greg" } ] },
|
{ "name": "hub", "who": [ { "commiter": "jack" }, { "reviewer": "avrel" }, { "commiter": "greg" } ] },
|
||||||
{ "name": "rip", "who": [ { "reviewer": "joe" }, { "reviewer": "jack" }, { "committer": "greg" } ] }
|
{ "name": "rip", "who": [ { "reviewer": "joe" }, { "reviewer": "jack" }, { "commiter": "greg" } ] }
|
||||||
],
|
],
|
||||||
"person?": { "name": "Jon" },
|
"person?": { "name": "Jon" },
|
||||||
"special": "----{{extra}}----",
|
"special": "----{{extra}}----\n",
|
||||||
"extra": 3.14159,
|
"extra": 3.14159,
|
||||||
"#sharp": "#",
|
"#sharp": "#",
|
||||||
"!bang": "!",
|
"!bang": "!",
|
||||||
|
@ -12,7 +12,7 @@ Shown.
|
|||||||
{{/person}}
|
{{/person}}
|
||||||
|
|
||||||
{{#repo}}
|
{{#repo}}
|
||||||
<b>{{name}}</b> reviewers:{{#who}} {{reviewer}}{{/who}} committers:{{#who}} {{committer}}{{/who}}
|
<b>{{name}}</b> reviewers:{{#who}} {{reviewer}}{{/who}} commiters:{{#who}} {{commiter}}{{/who}}
|
||||||
{{/repo}}
|
{{/repo}}
|
||||||
|
|
||||||
{{#person?}}
|
{{#person?}}
|
||||||
@ -23,7 +23,7 @@ Shown.
|
|||||||
=====================================
|
=====================================
|
||||||
%(%! gros commentaire %)%
|
%(%! gros commentaire %)%
|
||||||
%(%#repo%)%
|
%(%#repo%)%
|
||||||
<b>%(%name%)%</b> reviewers:%(%#who%)% %(%reviewer%)%%(%/who%)% committers:%(%#who%)% %(%committer%)%%(%/who%)%
|
<b>%(%name%)%</b> reviewers:%(%#who%)% %(%reviewer%)%%(%/who%)% commiters:%(%#who%)% %(%commiter%)%%(%/who%)%
|
||||||
%(%/repo%)%
|
%(%/repo%)%
|
||||||
=====================================
|
=====================================
|
||||||
%(%={{ }}=%)%
|
%(%={{ }}=%)%
|
||||||
|
@ -1,49 +0,0 @@
|
|||||||
Hello Chris
|
|
||||||
You have just won 10000 dollars!
|
|
||||||
|
|
||||||
Well, 6000 dollars, after taxes.
|
|
||||||
|
|
||||||
Shown.
|
|
||||||
|
|
||||||
|
|
||||||
No person
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<b>resque</b> reviewers: avrel committers: joe william
|
|
||||||
|
|
||||||
<b>hub</b> reviewers: avrel committers: jack greg
|
|
||||||
|
|
||||||
<b>rip</b> reviewers: joe jack committers: greg
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Hi Jon!
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
=====================================
|
|
||||||
|
|
||||||
|
|
||||||
<b>resque</b> reviewers: avrel committers: joe william
|
|
||||||
|
|
||||||
<b>hub</b> reviewers: avrel committers: jack greg
|
|
||||||
|
|
||||||
<b>rip</b> reviewers: joe jack committers: greg
|
|
||||||
|
|
||||||
=====================================
|
|
||||||
|
|
||||||
ggggggggg
|
|
||||||
----3.14159----
|
|
||||||
jjjjjjjjj
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
!
|
|
||||||
~
|
|
||||||
~
|
|
||||||
/ see json pointers IETF RFC 6901
|
|
||||||
^
|
|
||||||
=
|
|
||||||
:
|
|
||||||
>
|
|
@ -1,22 +0,0 @@
|
|||||||
<h1>Colors</h1>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<li><strong>red</strong></li>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<li><a href="#Green">green</a></li>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<li><a href="#Blue">blue</a></li>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
|||||||
* Chris
|
|
||||||
* 18
|
|
||||||
* <b>GitHub & Co</b>
|
|
||||||
* <b>GitHub & Co</b>
|
|
||||||
* <b>GitHub & Co</b>
|
|
||||||
|
|
||||||
* <b>GitHub & Co</b>
|
|
||||||
* <b>GitHub & Co</b>
|
|
||||||
* <b>GitHub & Co</b>
|
|
||||||
|
|
||||||
|
|
||||||
* <ul><li>Chris</li><li>Kross</li></ul>
|
|
||||||
* skills: <ul><li>JavaScript</li><li>PHP</li><li>Java</li></ul>
|
|
||||||
* age: 18
|
|
||||||
|
|
@ -1,100 +0,0 @@
|
|||||||
This are extensions!!
|
|
||||||
|
|
||||||
Jon
|
|
||||||
25
|
|
||||||
|
|
||||||
Fred
|
|
||||||
The other Fred.
|
|
||||||
|
|
||||||
|
|
||||||
Hello Jon
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
No Harry? Hey Calahan...
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Hello Fred
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Hello Fred#2
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Hello Jon, 25 years
|
|
||||||
|
|
||||||
|
|
||||||
Hello Henry, 27 years
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Salut Amed, 24 ans
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Jon: /25/25
|
|
||||||
|
|
||||||
Henry: /27/
|
|
||||||
|
|
||||||
Amed: 24/24/24
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Jon: /25/25
|
|
||||||
|
|
||||||
Henry: /27/
|
|
||||||
|
|
||||||
Amed: 24/24/24
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(1) person: { "name": "Jon", "age": 25 }
|
|
||||||
|
|
||||||
(2) name: Jon
|
|
||||||
|
|
||||||
|
|
||||||
(2) age: 25
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(1) person.name: Fred
|
|
||||||
|
|
||||||
|
|
||||||
(1) person.name=Fred: The other Fred.
|
|
||||||
|
|
||||||
|
|
||||||
(1) persons: [ { "name": "Jon", "age": 25, "lang": "en" }, { "name": "Henry", "age": 27, "lang": "en" }, { "name": "Amed", "age": 24, "lang": "fr" } ]
|
|
||||||
|
|
||||||
|
|
||||||
(1) fellows: { "Jon": { "age": 25, "lang": "en" }, "Henry": { "age": 27, "lang": "en" }, "Amed": { "age": 24, "lang": "fr" } }
|
|
||||||
|
|
||||||
(2) Jon: { "age": 25, "lang": "en" }
|
|
||||||
|
|
||||||
(3) age: 25
|
|
||||||
|
|
||||||
(3) lang: en
|
|
||||||
|
|
||||||
|
|
||||||
(2) Henry: { "age": 27, "lang": "en" }
|
|
||||||
|
|
||||||
(3) age: 27
|
|
||||||
|
|
||||||
(3) lang: en
|
|
||||||
|
|
||||||
|
|
||||||
(2) Amed: { "age": 24, "lang": "fr" }
|
|
||||||
|
|
||||||
(3) age: 24
|
|
||||||
|
|
||||||
(3) lang: fr
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -5,12 +5,12 @@
|
|||||||
"in_ca": true,
|
"in_ca": true,
|
||||||
"person": false,
|
"person": false,
|
||||||
"repo": [
|
"repo": [
|
||||||
{ "name": "resque", "who": [ { "committer": "joe" }, { "reviewer": "avrel" }, { "committer": "william" } ] },
|
{ "name": "resque", "who": [ { "commiter": "joe" }, { "reviewer": "avrel" }, { "commiter": "william" } ] },
|
||||||
{ "name": "hub", "who": [ { "committer": "jack" }, { "reviewer": "avrel" }, { "committer": "greg" } ] },
|
{ "name": "hub", "who": [ { "commiter": "jack" }, { "reviewer": "avrel" }, { "commiter": "greg" } ] },
|
||||||
{ "name": "rip", "who": [ { "reviewer": "joe" }, { "reviewer": "jack" }, { "committer": "greg" } ] }
|
{ "name": "rip", "who": [ { "reviewer": "joe" }, { "reviewer": "jack" }, { "commiter": "greg" } ] }
|
||||||
],
|
],
|
||||||
"person?": { "name": "Jon" },
|
"person?": { "name": "Jon" },
|
||||||
"special": "----{{extra}}----",
|
"special": "----{{extra}}----\n",
|
||||||
"extra": 3.14159,
|
"extra": 3.14159,
|
||||||
"#sharp": "#",
|
"#sharp": "#",
|
||||||
"!bang": "!",
|
"!bang": "!",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
must3.mustache == BEGIN
|
must3.mustache == BEGIN
|
||||||
{{#repo}}
|
{{#repo}}
|
||||||
<b>{{name}}</b> reviewers:{{#who}} {{reviewer}}{{/who}} committers:{{#who}} {{committer}}{{/who}}
|
<b>{{name}}</b> reviewers:{{#who}} {{reviewer}}{{/who}} commiters:{{#who}} {{commiter}}{{/who}}
|
||||||
{{/repo}}
|
{{/repo}}
|
||||||
|
|
||||||
{{#person?}}
|
{{#person?}}
|
||||||
@ -11,7 +11,7 @@ must3.mustache == BEGIN
|
|||||||
=====================================
|
=====================================
|
||||||
%(%! big comment %)%
|
%(%! big comment %)%
|
||||||
%(%#repo%)%
|
%(%#repo%)%
|
||||||
<b>%(%name%)%</b> reviewers:%(%#who%)% %(%reviewer%)%%(%/who%)% committers:%(%#who%)% %(%committer%)%%(%/who%)%
|
<b>%(%name%)%</b> reviewers:%(%#who%)% %(%reviewer%)%%(%/who%)% commiters:%(%#who%)% %(%commiter%)%%(%/who%)%
|
||||||
%(%/repo%)%
|
%(%/repo%)%
|
||||||
=====================================
|
=====================================
|
||||||
must3.mustache == END
|
must3.mustache == END
|
||||||
|
@ -1,60 +0,0 @@
|
|||||||
=====================================
|
|
||||||
from json
|
|
||||||
----3.14159----
|
|
||||||
=====================================
|
|
||||||
not found
|
|
||||||
|
|
||||||
=====================================
|
|
||||||
without extension first
|
|
||||||
must2 == BEGIN
|
|
||||||
Hello Chris
|
|
||||||
You have just won 10000 dollars!
|
|
||||||
|
|
||||||
Well, 6000 dollars, after taxes.
|
|
||||||
|
|
||||||
Shown.
|
|
||||||
|
|
||||||
|
|
||||||
No person
|
|
||||||
|
|
||||||
must2 == END
|
|
||||||
|
|
||||||
=====================================
|
|
||||||
last with extension
|
|
||||||
must3.mustache == BEGIN
|
|
||||||
|
|
||||||
<b>resque</b> reviewers: avrel committers: joe william
|
|
||||||
|
|
||||||
<b>hub</b> reviewers: avrel committers: jack greg
|
|
||||||
|
|
||||||
<b>rip</b> reviewers: joe jack committers: greg
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Hi Jon!
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
=====================================
|
|
||||||
|
|
||||||
|
|
||||||
<b>resque</b> reviewers: avrel committers: joe william
|
|
||||||
|
|
||||||
<b>hub</b> reviewers: avrel committers: jack greg
|
|
||||||
|
|
||||||
<b>rip</b> reviewers: joe jack committers: greg
|
|
||||||
|
|
||||||
=====================================
|
|
||||||
must3.mustache == END
|
|
||||||
|
|
||||||
=====================================
|
|
||||||
Ensure must3 didn't change specials
|
|
||||||
|
|
||||||
|
|
||||||
Hi Jon!
|
|
||||||
|
|
||||||
|
|
||||||
%(%#person?%)%
|
|
||||||
Hi %(%name%)%!
|
|
||||||
%(%/person?%)%
|
|
||||||
|
|
@ -1 +0,0 @@
|
|||||||
special ==SHOULD NOT BE SEEN==
|
|
@ -1 +0,0 @@
|
|||||||
special.mustache ==SHOULD NOT BE SEEN==
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user