# Internet Banking ![Badge](https://gitlab.com/khuedoan/internet-banking/badges/master/pipeline.svg) - [Internet Banking](#internet-banking) - [Thuật toán bảo mật API](#thuật-toán-bảo-mật-api) - [Hướng dẫn sử dụng api](#hướng-dẫn-sử-dụng-api) - [API dành cho partner](#api-dành-cho-partner) - [Lấy thông tin tài khoản khách hàng bằng số tài khoản](#lấy-thông-tin-tài-khoản-khách-hàng-bằng-số-tài-khoản) - [Nạp tiền vào tài khoản](#nạp-tiền-vào-tài-khoản) - [Rút tiền từ tài khoản](#rút-tiền-từ-tài-khoản) - [API dành cho customer](#api-dành-cho-customer) - [Đăng Nhập](#đăng-nhập) - [Lấy tên khách hàng bằng số tài khoản tín dụng](#lấy-tên-khách-hàng-bằng-số-tài-khoản-tín-dụng) - [Lấy toàn bộ danh sách tài khoản (credit + saving)](#lấy-toàn-bộ-danh-sách-tài-khoản-credit--saving) - [Xem lịch sử giao dịch](#xem-lịch-sử-giao-dịch) - [Chuyển khoản](#chuyển-khoản) - [Xác thực mã otp](#xác-thực-mã-otp) - [Reset mật khẩu](#reset-mật-khẩu) - [Xác thực otp đổi mật khẩu](#xác-thực-otp-đổi-mật-khẩu) - [Đổi mật khẩu](#đổi-mật-khẩu) - [CRUD thông tin gợi nhớ](#crud-thông-tin-gợi-nhớ) - [Xem thông tin gợi nhớ](#xem-thông-tin-gợi-nhớ) - [Tạo thông tin gợi nhớ](#tạo-thông-tin-gợi-nhớ) - [Xóa thông tin gợi nhớ](#xóa-thông-tin-gợi-nhớ) - [Chỉnh sửa thông tin gợi nhớ](#chỉnh-sửa-thông-tin-gợi-nhớ) - [API dành cho employee](#api-dành-cho-employee) - [Đăng Nhập](#đăng-nhập-1) - [Thêm thông tin khách hàng vào hệ thống](#thêm-thông-tin-khách-hàng-vào-hệ-thống) - [Thêm tài khoản tiết kiệm](#thêm-tài-khoản-tiết-kiệm) - [API dành cho admin](#api-dành-cho-admin) - [Thêm thông tin partner vào hệ thống](#thêm-thông-tin-partner-vào-hệ-thống) - [Tạo tài khoản employee](#tạo-tài-khoản-employee) - [Xóa tài khoản employee](#xóa-tài-khoản-employee) - [Cập nhật username của employee](#cập-nhật-username-của-employee) - [Cập nhật password của employee](#cập-nhật-password-của-employee) - [Liệt kê danh sách employee](#liệt-kê-danh-sách-employee) - [Lấy thông tin employee thông qua ID](#lấy-thông-tin-employee-thông-qua-id) - [Một số thông tin mặc định được khởi tạo cùng với project, dùng để test api](#một-số-thông-tin-mặc-định-được-khởi-tạo-cùng-với-project-dùng-để-test-api) - [Danh sách các ngân hàng liên kết](#danh-sách-các-ngân-hàng-liên-kết) - [Ngân hàng đại diện nhóm chẵn (PGP)](#ngân-hàng-đại-diện-nhóm-chẵn-pgp) - [Ngân hàng đại diện nhóm lẻ (RSA)](#ngân-hàng-đại-diện-nhóm-lẻ-rsa) - [Docker và Kubernetes](#docker-và-kubernetes) - [Môi trường lập trình local](#môi-trường-lập-trình-local) - [Deploy lên Kubernetes cluster trên Google Cloud](#deploy-lên-kubernetes-cluster-trên-google-cloud) - [CI/CD](#cicd) - [Trang web hữu ích](#trang-web-hữu-ích) ## Thuật toán bảo mật API - encode sử dụng **base64** cho chuỗi hash và signature - Signature sử dụng **rsa-sha256**, ví dụ chương trình tạo signature và verify bằng nodejs ```js const crypto = require('crypto'); const fs = require('fs'); function RSASign(privateKey, data) { const sign = crypto.createSign('RSA-SHA256') const signature = sign.update(data).sign(privateKey, 'base64'); console.log(signature); return signature; } function RSAVerify(publicKey, signature, data) { const verify = crypto.createVerify('RSA-SHA256'); verify.update(data); console.log(verify.verify(publicKey, signature, 'base64')); } const privateKey = fs.readFileSync('linh.private.key'); const publicKey = fs.readFileSync('linh.public.key'); var dataToSign = '1589520986kQYtFpj7pJfi5VVfoeGD{"credit_number":"565572661049","amount":200000}'; var signature = RSASign(privateKey, dataToSign); RSAVerify(publicKey, signature, dataToSign); ``` ```html OUTPUT EpQlSKV/gkr41Y1I3XmyBtdxS51l3po1QZA19X2CQm6jSKkLecVVrlr6SNrXPSLMeRp+dBEdI+XIdwynTaiyrCY53MF/vm6cJAZ3ZkUb9a5p9nv3Qq4NzRTEJkZApviU7FZBbfxsV5wsqesTHtKeMGF9K5nh0sq5CXowGkwxtR8= true ``` - Hash algo (cho **secret_text**) sử dụng **sha256**, ví dụ chương trình tạo chuỗi hash bằng nodejs ```js const crypto = require('crypto'); const dataToHash = '1589520986kQYtFpj7pJfi5VVfoeGD{"credit_number":"565572661049","amount":200000}'; let hashString = crypto.createHash('sha256').update(dataToHash).digest('base64'); console.log(hashString); ``` ```html OUTPUT d1JAmSmW2fXBElQ/NjXT7Yk+xQM1oWthn0iItHfL0io= ``` - Ví dụ cách encode and decode base64 bằng nodejs ```js console.log(Buffer.from("Hello World").toString('base64')); console.log(Buffer.from("SGVsbG8gV29ybGQ=", 'base64').toString('ascii')) ``` ```html OUTPUT SGVsbG8gV29ybGQ= Hello World ``` ## Hướng dẫn sử dụng api ### API dành cho partner #### Lấy thông tin tài khoản khách hàng bằng số tài khoản ```json GET /api/partner/get-account-info?credit_number=565572661049 HEADER "partner-code": "linh" "timestamp": 1589520986 "authen-hash": "BNAX7ITAnYu8rVliY5b6z4Waxs2GMk64FZd+ivBmNMo=" ``` - timestamp là thời điểm gởi request, format sử dụng unix utc second, có thể xem ở <https://www.epochconverter.com/,> lưu ý timestamp không được **lớn hơn** hoặc nhỏ hơn quá **60**s so với thời gian thực - partner-code là chuỗi code để xác định partner nào đã đăng kí api - authen-hash là chuỗi hash sha256 của **timestamp+secret+body**, nếu body empty thì là **{}**,sau đó được encode base64 lại và gửi đi, ví dụ ở trên - Không yêu cầu **authen-sig** #### Nạp tiền vào tài khoản ```json POST /api/partner/deposit HEADER "partner-code": "linh" "timestamp": 1589520986 "authen-hash": "d1JAmSmW2fXBElQ/NjXT7Yk+xQM1oWthn0iItHfL0io=" "authen-sig": "EpQlSKV/gkr41Y1I3XmyBtdxS51l3po1QZA19X2CQm6jSKkLecVVrlr6SNrXPSLMeRp+dBEdI+XIdwynTaiyrCY53MF/vm6cJAZ3ZkUb9a5p9nv3Qq4NzRTEJkZApviU7FZBbfxsV5wsqesTHtKeMGF9K5nh0sq5CXowGkwxtR8=" BODY {"credit_number":"565572661049","amount":200000} ``` - authen-sig là chuỗi signature được tạo bởi thuật toán **RSA-SHA256** của chuỗi **timestamp+secret+body**, xem ví dụ ở trên #### Rút tiền từ tài khoản ```json POST /api/partner/withdraw HEADER "partner-code": "linh" "timestamp": 1589520986 "authen-hash": "d1JAmSmW2fXBElQ/NjXT7Yk+xQM1oWthn0iItHfL0io=" "authen-sig": "EpQlSKV/gkr41Y1I3XmyBtdxS51l3po1QZA19X2CQm6jSKkLecVVrlr6SNrXPSLMeRp+dBEdI+XIdwynTaiyrCY53MF/vm6cJAZ3ZkUb9a5p9nv3Qq4NzRTEJkZApviU7FZBbfxsV5wsqesTHtKeMGF9K5nh0sq5CXowGkwxtR8=" BODY {"credit_number":"565572661049","amount":200000} ``` ### API dành cho customer #### Đăng Nhập ```json POST /api/customer/login BODY { "username": "linh", "password": "linh" } ``` - Hệ thống sẽ trả lại access token, dùng access_token để xác thực danh tính user #### Lấy tên khách hàng bằng số tài khoản tín dụng ```json GET /api/customer/get-credit-info?credit_number=565572661049 HEADER "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjdXN0b21lcl9pZCI6MSwiaWF0IjoxNTkwODQ4NTQ3LCJleHAiOjE1OTA4NTQ1NDd9.F_IHlYq9QbpbJ5YmOVFrseZyqQaWzwBSYniZg8Ykdts" ``` #### Lấy toàn bộ danh sách tài khoản (credit + saving) ```json GET /api/customer/get-list-account HEADER "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjdXN0b21lcl9pZCI6MSwiaWF0IjoxNTkwODQ4NTQ3LCJleHAiOjE1OTA4NTQ1NDd9.F_IHlYq9QbpbJ5YmOVFrseZyqQaWzwBSYniZg8Ykdts" ``` #### Xem lịch sử giao dịch ```json GET /api/customer/transaction-history HEADER "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjdXN0b21lcl9pZCI6MSwiaWF0IjoxNTkwODQ4NTQ3LCJleHAiOjE1OTA4NTQ1NDd9.F_IHlYq9QbpbJ5YmOVFrseZyqQaWzwBSYniZg8Ykdts" ``` #### Chuyển khoản ```json POST /api/customer/transfer-fund HEADER "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjdXN0b21lcl9pZCI6MSwiaWF0IjoxNTkwODQ4NTQ3LCJleHAiOjE1OTA4NTQ1NDd9.F_IHlYq9QbpbJ5YmOVFrseZyqQaWzwBSYniZg8Ykdts" BODY { "target_fullname": "nguyen van linh", "from_credit_number": "025917154505", "to_credit_number": "565572661049", "amount": 10000, "fee_payer": "sender", "partner_code": "local", "message": "hello dude" } ``` - Nếu yêu cầu chuyển khoản thành công, mã otp sẽ được gửi vào email của customer yêu cầu chuyển khoản - API trả về transaction_id #### Xác thực mã otp ```json POST /api/customer/verify-otp HEADER "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjdXN0b21lcl9pZCI6MSwiaWF0IjoxNTkwODQ4NTQ3LCJleHAiOjE1OTA4NTQ1NDd9.F_IHlYq9QbpbJ5YmOVFrseZyqQaWzwBSYniZg8Ykdts" BODY { "transaction_id": 12, "otp": "019628" } ``` #### Reset mật khẩu ```json POST /api/customer/reset-password BODY { "username": "linh", "identity_number": "025895863" } ``` - Hệ thống sẽ trả về reset_id và mã otp được gửi vào email customer yêu cầu đổi mật khẩu #### Xác thực otp đổi mật khẩu ```json POST /api/customer/verify-otp-resetpass BODY { "reset_id": 1, "otp": "448890" } ``` #### Đổi mật khẩu ```json POST /api/customer/change-password HEADER "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjdXN0b21lcl9pZCI6MSwiaWF0IjoxNTkxOTQ1OTE0LCJleHAiOjE1OTE5NTE5MTR9.JRYklbQtj-jCvEXWj1109RfdZtHrecZYBBjrTHJuH8Y" BODY { "old_password": "noob", "new_password": "linh", "confirm_new_password": "linh" } ``` #### CRUD thông tin gợi nhớ ```json POST /api/customer/remind-list HEADER "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjdXN0b21lcl9pZCI6MSwiaWF0IjoxNTkxOTQ1OTE0LCJleHAiOjE1OTE5NTE5MTR9.JRYklbQtj-jCvEXWj1109RfdZtHrecZYBBjrTHJuH8Y" ``` ##### Xem thông tin gợi nhớ ```json GET /api/customer/remind-list HEADER "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjdXN0b21lcl9pZCI6MSwiaWF0IjoxNTkxOTQ1OTE0LCJleHAiOjE1OTE5NTE5MTR9.JRYklbQtj-jCvEXWj1109RfdZtHrecZYBBjrTHJuH8Y" ``` ##### Tạo thông tin gợi nhớ ```json POST /api/customer/remind-list HEADER "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjdXN0b21lcl9pZCI6MSwiaWF0IjoxNTkxOTQ1OTE0LCJleHAiOjE1OTE5NTE5MTR9.JRYklbQtj-jCvEXWj1109RfdZtHrecZYBBjrTHJuH8Y" BODY { "credit_number": "27893492732", "remind_name": "dmdcs", "partner_code": "hcmbank" } ``` ##### Xóa thông tin gợi nhớ ```json DELETE /api/customer/remind-list HEADER "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjdXN0b21lcl9pZCI6MSwiaWF0IjoxNTkxOTQ1OTE0LCJleHAiOjE1OTE5NTE5MTR9.JRYklbQtj-jCvEXWj1109RfdZtHrecZYBBjrTHJuH8Y" BODY { "remind_id": 1 } ``` ##### Chỉnh sửa thông tin gợi nhớ ```json POST /api/customer/remind-list HEADER "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjdXN0b21lcl9pZCI6MSwiaWF0IjoxNTkxOTQ1OTE0LCJleHAiOjE1OTE5NTE5MTR9.JRYklbQtj-jCvEXWj1109RfdZtHrecZYBBjrTHJuH8Y" BODY { "remind_id": 1, "credit_number": "1111111111", "remind_name": "idkwtfigo", "partner_code": "changed" } ``` ### API dành cho employee #### Đăng Nhập ```json POST /api/employee/login BODY { "username": "trump", "password": "idiot" } ``` - Hệ thống sẽ trả lại access token, dùng access_token để xác thực danh tính employee #### Thêm thông tin khách hàng vào hệ thống ```json POST /api/employee/add-customer BODY { "username": "linh", "password": "linh", "identity_number": "025895863", "phone_number": "0704468257", "firstname": "linh", "lastname": "nguyen van", "date_of_birth": "1998-11-12", "email_address": "linh1612340@gmail.com" } ``` #### Thêm tài khoản tiết kiệm ```json POST /api/employee/add-saving-account BODY { "customer_id": 1, "balance": 1000000 } ``` ### API dành cho admin #### Thêm thông tin partner vào hệ thống ```json POST /api/admin/add-partner BODY { "partner_code": "bankdbb", "bankname": "bankdbb", "public_key": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlHZk1BMEdDU3FHU0liM0RRRUJBUVVBQTRHTkFEQ0JpUUtCZ1FDRVVaSnd2VFlvcnVzdFFZK0YzaXFoSmUrTQordmsxMFYxZ2QrdFhBVDVlUTZCZngvRU9FRW9GaXduSC9JNUttUngzRDNhMkdIZ1dZSUxEbkNWbzVLbjZISC9SCkl1dmkxMXJsdks1Qzc5OFdZUmp2TmtPbGNmSTNNNml4UWYrZkFKU25mbE9xQ2NvUHAvUk0wSGdjeXdvVGtOV0sKUFFZcFBwazl0bm8vcWxPY3d3SURBUUFCCi0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQ==", "partner_secret": "bankdbb" } ``` - Hệ thống sẽ tự động tạo 1 bank_secret trả về #### Tạo tài khoản employee ```json POST /api/admin/add-employee BODY { "username": "trump", "password": "idiot" } ``` - Hệ thống sẽ tự động tạo 1 bank_secret trả về #### Xóa tài khoản employee ```json POST /api/admin/delete-employee BODY { "employee_id": "3" } ``` - Hệ thống sẽ trả về kết quả của database, ví dụ: ```json { "fieldCount": 0, "affectedRows": 1, "insertId": 0, "serverStatus": 2, "warningCount": 0, "message": "", "protocol41": true, "changedRows": 0 } ``` Với affectedRows là 1, tức là đã xóa. #### Cập nhật username của employee ```json POST /api/admin/update-employee-username BODY { "employee_id": "3", "username": "newname" } ``` Hệ thống sẽ trả về kết quả từ database tương tự như trên. #### Cập nhật password của employee ```json POST /api/admin/update-employee-password BODY { "employee_id": "3", "password": "newpassword" } ``` Hệ thống sẽ trả về kết quả từ database tương tự như trên. #### Liệt kê danh sách employee ```json GET /api/admin/employee-list ``` - Hệ thống sẽ trả về danh sách tất cả employee dưới dạng JSON #### Lấy thông tin employee thông qua ID ```json GET /api/admin/get-employee-info?employee_id=<ID của employee> ``` Hệ thống sẽ trả về thông tin của employee duới dạng JSON, ví dụ: ```json [ { "username": "obama", "employee_id": 5, "hashed_password": "$2a$08$nLoMEK84g.U4JPuvjLKisu3Nl6Pt/tEVpX6VerU0kiEW6yDggD51a", "refresh_secret": "rQFn3MSsYZN2UzK8idJv" } ] ``` ## Một số thông tin mặc định được khởi tạo cùng với project, dùng để test api - Thông tin khách hàng linh ```json { "customer_id": 1, "username": "linh", "password": "linh", "identity_number": "025895863", "phone_number": "0704468257", "firstname": "LINH", "lastname": "NGUYEN VAN", "date_of_birth": "1998-11-12", "email_address": "linh1612340@gmail.com", "refresh_secret": "5FmWSukHG8PapSAcGrNS" } ``` - credit account gắn liền với khách hàng ```json { "customer_id": 1, "credit_number": "565572661049", "balance": 100000, "status": 1 } ``` - Thông tin partner linh mặc định, public key ở dạng **base64** ```json { "partner_id": 1, "partner_code": "linh", "bankname": "linhbank", "public_key": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlHZk1BMEdDU3FHU0liM0RRRUJBUVVBQTRHTkFEQ0JpUUtCZ1FDSmxRWi9tMStpTGZLL2xwWURtaWNsZTZ2MApsbExXdGRZaFNrSDZidWlPck5iYVhWSC8vWmNHOVRwT0xVMXZMK1BrdnByQ1ovTjFTdHF6MHhOcnpjZFQwekZJCnhRU3IzMWZCMXF6RDIrVDRuakJjR1JPU3R2MHV4aGFhcm1XVkp3akxpYTBybEw3Z3JSTDBheHc0ckVTTTluc04KYmU4WG5KR1ZLdEZ5OU1YSEJ3SURBUUFCCi0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQ==", "bank_secret": "kQYtFpj7pJfi5VVfoeGD", "partner_secret": "idk" } ``` - partner linh public key ```html -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCJlQZ/m1+iLfK/lpYDmicle6v0 llLWtdYhSkH6buiOrNbaXVH//ZcG9TpOLU1vL+PkvprCZ/N1Stqz0xNrzcdT0zFI xQSr31fB1qzD2+T4njBcGROStv0uxhaarmWVJwjLia0rlL7grRL0axw4rESM9nsN be8XnJGVKtFy9MXHBwIDAQAB -----END PUBLIC KEY----- ``` - partner linh secret key ```html -----BEGIN RSA PRIVATE KEY----- MIICWwIBAAKBgGFkPDYzYPPrWGryFdZXEXtjRFlBycKW/cAdiBLUCcNQMYgyB3Kc +oPRy7TV17xsuZC8qovx6P1XT9CXOHg63j1bJtyEQRkCXr/V2l2tkJxtjcHYjtDd j2uupLYqodZ3Sb+UMi0LkRdk8fVE+taVk/Fn6ny/lLvcRhNPb01/yevBAgMBAAEC gYA88EoYo/djSHwvlsCBOEOxEADhVJ/ZCT9HaXMOTOy68D+994ffeEfsGWa8BR4T QXivDs4r+LcPZgWEAEsON898j83HjClnvpAKPzPwuJch+fQz26DPau6UQWdfMm5q 1GVx1yYOujjwi2gETb1hGlhagiZV1X+APm84bry7knDgAQJBALFqWZqFjGBUO2ro liFsnY52vtl/xdfTwRqhwW98uEfi9xiM8D634abaYWlGAOZDDOpSgvxRgoKsxqF6 lrYvbUECQQCMh76mrbjYTh9DeEaPlNGfcWvwgKZggpsKNAiNoxpcBglS2WJ67psH yQgx7AQgg7XMGsNetQa7xVGPyhxoRl6BAkB72kl5NNfde5ALPxlndgK7rKvo/Gjq FZqN8/Qs1z1yecCT8/fXYNj3eSZdro/8Lzy57CYi7OgWP3Vez0ydHJjBAkAzcqro qKcIgalOcSUcAbawsbx7ow3GPWp3VM9g0zqeQBN/wlgce2hEdGPMqwRjxvRykcW+ 0XVynu2aP7sgrcqBAkEAsIWp2vZJvbJnqHoJX0qEQECEVj49PmscBpKIJZZL8FVf gP78h6zdxHh1xq/oLavoZue7xpP6nFMQmRrqPek8+A== -----END RSA PRIVATE KEY----- ``` - bank RSA public key ```html -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCJlQZ/m1+iLfK/lpYDmicle6v0 llLWtdYhSkH6buiOrNbaXVH//ZcG9TpOLU1vL+PkvprCZ/N1Stqz0xNrzcdT0zFI xQSr31fB1qzD2+T4njBcGROStv0uxhaarmWVJwjLia0rlL7grRL0axw4rESM9nsN be8XnJGVKtFy9MXHBwIDAQAB -----END PUBLIC KEY----- ``` - bank RSA secret key ```html -----BEGIN RSA PRIVATE KEY----- MIICWwIBAAKBgQCJlQZ/m1+iLfK/lpYDmicle6v0llLWtdYhSkH6buiOrNbaXVH/ /ZcG9TpOLU1vL+PkvprCZ/N1Stqz0xNrzcdT0zFIxQSr31fB1qzD2+T4njBcGROS tv0uxhaarmWVJwjLia0rlL7grRL0axw4rESM9nsNbe8XnJGVKtFy9MXHBwIDAQAB AoGAFxRq3KlB58DxgfZPABeyDXWrqQI2r1Ids8PzQYGtfZG9ETCqetkdpssolsi+ vrI39r2K1KX/j2OZQKVeEq2YjFR+etusQzCRF6jqbk5O+/ajLL4veyxKQmTQXDVx DwjsRDc1MvMsfqmnk5b0uYs9ntnT/iaqkLVtEwKMpnjFW/ECQQDvfz1wpjRKCduV sdaH1JxqKw2mYu79Cyp7LkHKz0fvfg6SP7EAPt4j7dlBuA0n99OAklcvtfVpiXF3 rQOauC99AkEAkw/+JX4dfvGXOQ+fZerFamOUjVLEhH7I19wrHU4y56SDC2uQ1Q9n xvxH81CxFTN7HXOKQ8uFNY06kyfzWNif0wJAd+dhMEPVy/eReymU+V4ljTXO2K2R bxinBRLMl6gdILcgvnGqwS+4cY6EBdYKqCb4OdeKVPWpT1QjfcIeGtj51QJAMZgC F/i4z7d/TOHk2kTbAG7GiQYxeZEcABeifoaBijajbrV+qStBzwwC454BqemrihoN taErsgyHhVrCqOKcuwJAWyuluw+LXjvwY/sFgPXLqCPMfEP4kBXhqM/+hHK7ZerR aLvYFAwzssSuUGlksRon0xjQ7M9P2+Bld3gcV6hUyg== -----END RSA PRIVATE KEY----- ``` - Bank PGP public key ```html -----BEGIN PGP PUBLIC KEY BLOCK----- Version: Keybase OpenPGP v1.0.0 Comment: https://keybase.io/crypto xo0EXsNd1gEEANMSmHxTjdL1XBcP09QGmky3Z75ePYfK8ywBKWJriAdqgy3nNHC+ 9Gn7yWxdG0yCIPUvsNfYFscXjyIWl2A5KUWgP7Tvnb88u1KDSV2WmXLJE+Mvxz28 IkoZsRcOHNe9UDNDjxqJMYc6+vXHn+6KktTNEv45k+WVvzcbUUDUveURABEBAAHN HGxpbmggPGxpbmgxNjEyMzQwQGdtYWlsLmNvbT7CrQQTAQoAFwUCXsNd1gIbLwML CQcDFQoIAh4BAheAAAoJEAqwub56bRzrrNMD/iXzoYWhGgD1PW8hq4x04eY1FDTh UKIL7PNLqcWP/UIjIkVFwuJWPHRNKle804pLIOg1Kd0KKnefQ8/o48ekB8K3erlZ I7fMozmIEqqmmTXZLSNCCPieAHmtrHrcemjzhLRn6qG2VVUNbQPpHuK0yNVcWTqR RmbDeUyOMHja0Kf0zo0EXsNd1gEEAN1a3UNxi+/zqZbBSkAFGCBwGBzeg0GdRbgq kn44z3Ue+T0/iswS/mxRGPdtMYvagL1cZzvGBilJgzCQg4R2Jt5UMoieDo+YrIe9 QrjjcopJ262Aee5aZB2Gu4YHbRMn4+hEKaTIpqL8rCLou/bhbkJG65YsDe8EiNwP i9iMJmmtABEBAAHCwIMEGAEKAA8FAl7DXdYFCQ8JnAACGy4AqAkQCrC5vnptHOud IAQZAQoABgUCXsNd1gAKCRBwACQaae7pkSQqBACN4v1lNA0ni2j2wJ29Piw4qRVv 2mPfFHag3ilHj7wiEscQuBMA+659TvWPemXrBycsNkD3McueFAy/svLE28tqy9z2 0udFIW7Jqni4q0nz7NInzyVXghF1Gv6KjnUppj1QLVyHar15Nr8IM8u1+vrVNgFC zz3lwqI0oSYY4UY/2OcbBAC19IGj8bM4EmOf7IEJd9lLGIo/mkDloRONeOM7R/Hi 0aWuDeH4SViUdqz4303cdvf2LETVg16vffXzhOBUU+obLt0iKQrBS6QQLOFcxi1I OmC76AG/MpsD+Dis0l4D0TN1g08qIN/4t0owcwenkkuKWCpSMnO+T8CkoeSXC/kH C86NBF7DXdYBBADZTNl/VGoebXPlzJ5Sb0JZAnmMj8wTcd2hyT7WsrOvsu3t+qpR 5l3XOgZMg6QvnNI+QAPw/sb0GzG5B5Bgq/HXhyyosyFEGMRxDoC6YLwTVS1Nt5mM dcHUuOipBWpbc6oZFUb5ldPibTYhyoWhjATwVjJArddBxl8rWq6vQ4mJxQARAQAB wsCDBBgBCgAPBQJew13WBQkPCZwAAhsuAKgJEAqwub56bRzrnSAEGQEKAAYFAl7D XdYACgkQPiF9sII2k1NKYAQApRbyELkB6/bkgyL/jJey95KobUzCv0tEdY7j0V/0 2srSRg4xiJjbfxtrZtZNV2XJnHY6Y1Yws8zWXtvWW7CASqOKvqu1CeAER6HXJS+y KGGYzQaiwyDitLuTKpjsMp32YXBWkDMFaewsetRF1Q335/5us/oWOi/Q036X4B7J VWZobgQAyvxrw3OVc3soHZtr31FgblZFIfLvIGvAUhzlHm7SGtkzQdd7UjLkG48a aEaRRTz9FcbxFYI+68GOPX29aAbw3CcLBFXzPwH72E9v4uah4BapGFEFHrv+Zq2A xrc92e45BI8C3nuBrgZEvZT9l5sGR9lcaCWq0NwmO1mQK53XX94= =S6eu -----END PGP PUBLIC KEY BLOCK----- ``` - Bank PGP private key ```html -----BEGIN PGP PRIVATE KEY BLOCK----- Version: Keybase OpenPGP v1.0.0 Comment: https://keybase.io/crypto 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 l5sGR9lcaCWq0NwmO1mQK53XX94= =MZrG -----END PGP PRIVATE KEY BLOCK----- ``` ## Danh sách các ngân hàng liên kết ### Ngân hàng đại diện nhóm chẵn (PGP) - Partner code: ```html NaniBank ``` - Public key (RSA): ```html -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgsRrmYvqFeXGntLRa/84 Zx7I5iJkDYNVlCXCxr2WVAoYKkiQWW/jlDD4OEhKCZCJgVVGT43XxUkQ3sv7+eVO 1MO1iSbMql96VSBLwybIfPrFjMXnoXE4lgRy06lAmCSTmjvWZW6xrlGRwdkWNxIb ktR6eRiI//ERKqhFM+XZ2ur/xTyv28hZhj8UInyHJogfPiX/cal1dr/7GKzqyqUp /mRnta31hVZZsXb1LCQtynZI6pfUKLZ7jok4L7Lm+S9+D3dhcMxBwJD15IjCDtQE 37lhuaRWB72hOpNFXFEUWXl408SMRyqbGPps/u+TEmstyo9qyUvdwWEbMg3GmE7M GQIDAQAB -----END PUBLIC KEY----- ``` - Secrettext of partner: ```html hi mom ``` - Secrettext of bank: ```html M0ec3lAqjHV82v66VYDb ``` - Host address ```html 35.240.195.17 ``` ### Ngân hàng đại diện nhóm lẻ (RSA) - Tên ngân hàng: ```html bankdbb ``` - Public key (RSA): ```html -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCEUZJwvTYorustQY+F3iqhJe+M +vk10V1gd+tXAT5eQ6Bfx/EOEEoFiwnH/I5KmRx3D3a2GHgWYILDnCVo5Kn6HH/R Iuvi11rlvK5C798WYRjvNkOlcfI3M6ixQf+fAJSnflOqCcoPp/RM0HgcywoTkNWK PQYpPpk9tno/qlOcwwIDAQAB -----END PUBLIC KEY----- ``` - Secrettext of partner: ```html bankdbb ``` - Secrettext of bank: ```html Tj0xYDEDiQF9f2GYCxSv ``` ## Docker và Kubernetes ### Môi trường lập trình local Cài đặt `docker` và `docker-compose` Chạy app bao gồm frontend, backend, database trong các container: ```sh docker-compose up --build ``` Restore database bằng script có sẵn: ```sh cd mariadb ./restore.sh ``` ### Deploy lên Kubernetes cluster trên Google Cloud Cài đặt `kubectl` Build image nodejs và push lên [Docker Hub](https://hub.docker.com/repository/docker/khuedoan/node-kubernetes): ```sh docker login -u khuedoan docker build -t khuedoan/node-kubernetes . docker push khuedoan/node-kubernetes ``` Deploy lên Google Kubernetes Engine: ```sh kubectl apply -f kubernetes/ ``` Restore database bằng script có sẵn: ```sh cd mariadb ./restore-kubernetes.sh ``` ### CI/CD TODO ## Trang web hữu ích - Tạo signature <https://8gwifi.org/rsasignverifyfunctions.jsp> - utc timestamp <https://www.epochconverter.com/> - Hex to base64 <https://base64.guru/converter/encode/hex> - Beautify và minify json <https://codebeautify.org/jsonviewer> - Hash, encode decode <https://emn178.github.io/online-tools/sha256.html> - Hash online <https://quickhash.com/>