Skip to content

Commit

Permalink
Merge pull request LiskArchive#51 from LiskHQ/50-Update-validation-sc…
Browse files Browse the repository at this point in the history
…ripts-to-validate-for-at-least-one-base-demon-with-zero-decimals-in-native-Tokens

Update validation scripts to validate for at least one base demon with zero decimals in native Tokens
  • Loading branch information
sameersubudhi authored Dec 1, 2023
2 parents a01cca9 + 30ba8ae commit 6f3e9fd
Show file tree
Hide file tree
Showing 15 changed files with 444 additions and 102 deletions.
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,12 @@ Example: *mainnet/Lisk/app.json*
- Prior to the metadata submission, please ensure that the Lisk applications are registered on the Lisk mainchain and vice-versa.
- For logos pointing to app-registry GitHub URL, use the main branch in the URL to ensure working functionality after PR merge. All logos submitted need to adhere to `64px x 64px` resolution.
- For `mainnet` and `testnet` submissions, it is necessary that all the API deployments are secured with SSL/TLS.
- For every SSL/TLS secured API deployment (i.e. for `appNodes`, and `serviceURLs`), it is mandatory to specify the `apiCertificatePublicKey`. In case you need support in extracting the public key from your SSL/TLS certificate, you can use one of the following methods:
1. [Using OpenSSL](./docs/extracting-pubkey-from-cert-using-openssl.md)
2. [Using the NodeJS script](./utility/README.md)
- For every SSL/TLS secured API deployment (i.e. for `appNodes`, and `serviceURLs`), it is mandatory to specify the `apiCertificatePublicKey`.
1. In case you need support in extracting the public key from your SSL/TLS certificate, you can use one of the following methods:
1. [Using OpenSSL](./docs/extracting-pubkey-from-cert-using-openssl.md)
2. [Using the NodeJS script](./utility/extractPublicKeyFromCertificate/README.md)
2. In case you need support in extracting the public key from a URL, you can use the following method:
1. [Using the NodeJS script](./utility/extractPublicKeyFromURL/README.md)

### Native Tokens JSON

Expand Down
6 changes: 3 additions & 3 deletions testnet/Lisk/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
{
"http": "https://testnet-service.lisk.com",
"ws": "wss://testnet-service.lisk.com",
"apiCertificatePublicKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqiQIDBSSlqKeWo0st2Hy\nJRbDzqYgcZfQvOpttr4kMbDjAYnz6XvZe3kOHcnMM2ePWrAS66SHTqdVbEEiu9Kf\njEQQkmk/Xv7XSMQ5kwidv+ANNDjTaC9GRnUHQ3pH77ZZY5msq0kEvmDvyMljU9kD\neqpugQn7jQVTG7te7PyXnZxvzMq8tgDILEwRnkF2hUF6jCH5X763aOT7X6yKUKY5\nZSUqmStKGPt1i34E5Pvb2AumsApkyqXfST/N/h8NV3UXRTBQ/fwAEvtOj3IMNNrw\nRUZIYAvwPFxTLXF0Dfj0fEiLFQzq+VPk3jsD9EbH1FotHXPtgA7brvG0uHfWKNsQ\nIQIDAQAB\n-----END PUBLIC KEY-----"
"apiCertificatePublicKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA55eVRxMsjgsakiSmRJGN\ng7u5XCO63BzbyFeUUuZ5YGRodFDw/cVAaIg9mWAtYRQM3FemJRt6zGcneFTbfmFC\nFcrGFbFqbcBssuHeyaBQroP8E5NcYVy7ZYJmZTaFBL9fpFzgrGdnLgjrlTkx7G+d\n95299QFRfX+mtSXuU0qzsSJzLaO9TsED3+I0aH80nJtxO8/ZI+RqjmomV5aAU0EO\n4S7a7npMZjxVKqwEcUcHeGf+4VLFGDc821IV45T4OZCxRG0sWgbc/AglY1xzRzJv\n1PTTWSYaukKM4rsuVEh6P12dAvMowh4wPGGPkQopXfS135xuHeefjnILl5/OcwHF\n3wIDAQAB\n-----END PUBLIC KEY-----"
}
],
"explorers": [
Expand All @@ -32,12 +32,12 @@
"appNodes": [
{
"url": "https://testnet.lisk.com",
"apiCertificatePublicKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqiQIDBSSlqKeWo0st2Hy\nJRbDzqYgcZfQvOpttr4kMbDjAYnz6XvZe3kOHcnMM2ePWrAS66SHTqdVbEEiu9Kf\njEQQkmk/Xv7XSMQ5kwidv+ANNDjTaC9GRnUHQ3pH77ZZY5msq0kEvmDvyMljU9kD\neqpugQn7jQVTG7te7PyXnZxvzMq8tgDILEwRnkF2hUF6jCH5X763aOT7X6yKUKY5\nZSUqmStKGPt1i34E5Pvb2AumsApkyqXfST/N/h8NV3UXRTBQ/fwAEvtOj3IMNNrw\nRUZIYAvwPFxTLXF0Dfj0fEiLFQzq+VPk3jsD9EbH1FotHXPtgA7brvG0uHfWKNsQ\nIQIDAQAB\n-----END PUBLIC KEY-----",
"apiCertificatePublicKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA55eVRxMsjgsakiSmRJGN\ng7u5XCO63BzbyFeUUuZ5YGRodFDw/cVAaIg9mWAtYRQM3FemJRt6zGcneFTbfmFC\nFcrGFbFqbcBssuHeyaBQroP8E5NcYVy7ZYJmZTaFBL9fpFzgrGdnLgjrlTkx7G+d\n95299QFRfX+mtSXuU0qzsSJzLaO9TsED3+I0aH80nJtxO8/ZI+RqjmomV5aAU0EO\n4S7a7npMZjxVKqwEcUcHeGf+4VLFGDc821IV45T4OZCxRG0sWgbc/AglY1xzRzJv\n1PTTWSYaukKM4rsuVEh6P12dAvMowh4wPGGPkQopXfS135xuHeefjnILl5/OcwHF\n3wIDAQAB\n-----END PUBLIC KEY-----",
"maintainer": "Lightcurve GmbH"
},
{
"url": "wss://testnet.lisk.com",
"apiCertificatePublicKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqiQIDBSSlqKeWo0st2Hy\nJRbDzqYgcZfQvOpttr4kMbDjAYnz6XvZe3kOHcnMM2ePWrAS66SHTqdVbEEiu9Kf\njEQQkmk/Xv7XSMQ5kwidv+ANNDjTaC9GRnUHQ3pH77ZZY5msq0kEvmDvyMljU9kD\neqpugQn7jQVTG7te7PyXnZxvzMq8tgDILEwRnkF2hUF6jCH5X763aOT7X6yKUKY5\nZSUqmStKGPt1i34E5Pvb2AumsApkyqXfST/N/h8NV3UXRTBQ/fwAEvtOj3IMNNrw\nRUZIYAvwPFxTLXF0Dfj0fEiLFQzq+VPk3jsD9EbH1FotHXPtgA7brvG0uHfWKNsQ\nIQIDAQAB\n-----END PUBLIC KEY-----",
"apiCertificatePublicKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA55eVRxMsjgsakiSmRJGN\ng7u5XCO63BzbyFeUUuZ5YGRodFDw/cVAaIg9mWAtYRQM3FemJRt6zGcneFTbfmFC\nFcrGFbFqbcBssuHeyaBQroP8E5NcYVy7ZYJmZTaFBL9fpFzgrGdnLgjrlTkx7G+d\n95299QFRfX+mtSXuU0qzsSJzLaO9TsED3+I0aH80nJtxO8/ZI+RqjmomV5aAU0EO\n4S7a7npMZjxVKqwEcUcHeGf+4VLFGDc821IV45T4OZCxRG0sWgbc/AglY1xzRzJv\n1PTTWSYaukKM4rsuVEh6P12dAvMowh4wPGGPkQopXfS135xuHeefjnILl5/OcwHF\n3wIDAQAB\n-----END PUBLIC KEY-----",
"maintainer": "Lightcurve GmbH"
}
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Before using the script, kindly ensure that you have Node.js installed on your s

1. **Download the script:**

Download the [`extractPublicKeyFromCertificate.js`](https://github.com/LiskHQ/app-registry/blob/main/utility/extractPublicKeyFromCertificate.js) file from this repository and save it to a location on your computer.
Download the [`extractPublicKeyFromCertificate.js`](./extractPublicKeyFromCertificate.js) file from this repository and save it to a location on your computer.

2. **Open a Terminal or Command Prompt:**

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
/*
* LiskHQ/lisk-service
* Copyright © 2023 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/

const fs = require('fs');
const crypto = require('crypto');

Expand Down
27 changes: 27 additions & 0 deletions utility/extractPublicKeyFromURL/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Extract public key from PEM Certificate using Node.js

This Node.js script lets you extract the public key from a URL and save it locally to your filesystem. Follow the steps below to use the script:

## Prerequisites

Before using the script, kindly ensure that you have Node.js installed on your system. You can download Node.js from the [official website](https://nodejs.org).

## Getting Started

1. **Download the script:**

Download the [`extractPublicKeyFromURL.js`](./extractPublicKeyFromURL.js) file from this repository and save it to a location on your computer.

2. **Open a Terminal or Command Prompt:**

Navigate to the directory where you saved the `extractPublicKeyFromURL.js` file using the terminal or command prompt.

4. **Generate Public Key:**

To run the script and generate the public key, use the following command:

```bash
node extractPublicKeyFromURL.js <URL> <path/to/public_key.pem>
```

Replace `<URL>` with the desiered URL without port number, and `<path/to/public_key.pem>` with the desired output file path for the public key to be extracted.
67 changes: 67 additions & 0 deletions utility/extractPublicKeyFromURL/extractPublicKeyFromURL.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright © 2023 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*/

const fs = require('fs')
const { exec } = require('child_process');
const crypto = require('crypto');

const url = process.argv[2];
const publicKeyFilePath = process.argv[3];

const getCertificateFromURL = async (url) => new Promise((resolve, reject) => {
const { host } = new URL(url);

// Use OpenSSL to retrieve the PEM certificate
const command = `openssl s_client -connect ${host}:443 -showcerts </dev/null 2>/dev/null | openssl x509 -outform PEM`;

exec(command, (error, stdout, stderr) => {
if (error) {
reject(error);
return;
}

if (stderr) {
reject(new Error(`Error: ${stderr}`));
return;
}

const pemCertificate = stdout;
resolve(pemCertificate);
});
});

const convertCertificateToPemPublicKey = (pemCertificate) => new Promise((resolve, reject) => {
try {
// Create a certificate object from the PEM data
const certificate = crypto.createPublicKey({
key: pemCertificate,
format: 'pem',
});

// Convert the certificate to PEM format for public key
const publicKeyPem = certificate.export({
format: 'pem',
type: 'spki',
});

// Write the public key to the output file
fs.writeFileSync(publicKeyFilePath, publicKeyPem);
} catch (error) {
reject(new Error(`Error occurred while extracting the public key: ${error.message}.`));
}
});

getCertificateFromURL(url).then((cert) => {
convertCertificateToPemPublicKey(cert);
});
8 changes: 4 additions & 4 deletions validation/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion validation/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"ajv": "8.12.0",
"ajv-formats": "2.1.1",
"ansi-colors": "^4.1.3",
"axios": "1.3.5",
"axios": ">=1.6.0",
"pemtools": "^0.4.7",
"sharp": "^0.32.4",
"socket.io-client": "^4.7.1"
Expand Down
6 changes: 5 additions & 1 deletion validation/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const { validateURLs } = require('./validateURLs');
const { validateAllWhitelistedFiles } = require('./validateWhitelistedFiles');
const { validateAllConfigFiles } = require('./validateConfigFiles');
const { validateConfigFilePaths } = require('./validateConfigFilePaths');
const { validateTokens } = require('./validateTokens');
const { exists } = require('./utils/fs');
const config = require('../config');

Expand Down Expand Up @@ -96,8 +97,11 @@ const validate = async () => {
// Validate serviceURLs
const urlErrors = await validateURLs(changedAppFiles, allChangedFiles, isAuthorFromDevTeam);

// Validate tokens
const tokenErrors = await validateTokens(changedAppFiles);

// Merge all validation errors
validationErrors = [...configFileErrors, ...schemaErrors, ...validateConfigFilesErrors, ...urlErrors];
validationErrors = [...configFileErrors, ...schemaErrors, ...validateConfigFilesErrors, ...urlErrors, ...tokenErrors];

// Check if any non-whitelisted files are modified
if (!isAuthorFromDevTeam) {
Expand Down
73 changes: 35 additions & 38 deletions validation/src/utils/request/certificate.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,61 +12,58 @@
* Removal or modification of this copyright notice is prohibited.
*/

const https = require('https');
const { exec } = require('child_process');
const config = require('../../../config');
const crypto = require('crypto');

const cachedCerts = {};

const getCertificateFromURL = async (url, timeout = config.API_TIMEOUT) => {
// eslint-disable-next-line consistent-return
const getCertificateFromURL = async (url) => new Promise((resolve, reject) => {
const { host } = new URL(url);

if (host in cachedCerts) {
return Promise.resolve(cachedCerts[host]);
return resolve(cachedCerts[host]);
}

return new Promise((resolve, reject) => {
const options = {
hostname: host,
port: 443,
method: 'GET',
};
// Use OpenSSL to retrieve the PEM certificate
const command = `openssl s_client -connect ${host}:443 -showcerts </dev/null 2>/dev/null | openssl x509 -outform PEM`;

const req = https.request(options, (res) => {
const certificate = res.socket.getPeerCertificate();
if (!certificate) {
reject(new Error(`No certificate found for URL: ${url}.`));
}

cachedCerts[host] = certificate.raw;
resolve(certificate.raw);
});

req.on('error', (error) => {
exec(command, (error, stdout, stderr) => {
if (error) {
reject(error);
});
return;
}

req.setTimeout(timeout, () => {
req.destroy();
reject(new Error(`Request timed out when fetching certificate from URL: ${url}.`));
});
if (stderr) {
reject(new Error(`Error: ${stderr}`));
return;
}

req.end();
const pemCertificate = stdout;
cachedCerts[host] = pemCertificate;
resolve(pemCertificate);
});
};
});

const convertCertificateToPemPublicKey = async (certificate) => new Promise((resolve, reject) => {
const command = 'openssl x509 -inform der -pubkey -noout | openssl rsa -pubin -inform pem';
const child = exec(command, (error, stdout) => {
if (error) {
reject(error);
}
// eslint-disable-next-line consistent-return
const convertCertificateToPemPublicKey = (pemCertificate) => new Promise((resolve, reject) => {
try {
// Create a certificate object from the PEM data
const certificate = crypto.createPublicKey({
key: pemCertificate,
format: 'pem',
});

resolve(stdout);
});
// Convert the certificate to PEM format for public key
const publicKeyPem = certificate.export({
format: 'pem',
type: 'spki',
});

child.stdin.write(Buffer.from((certificate), 'base64'));
child.stdin.end();
return resolve(publicKeyPem);
} catch (error) {
reject(new Error(`Error occurred while extracting the public key: ${error.message}.`));
}
});

module.exports = {
Expand Down
47 changes: 47 additions & 0 deletions validation/src/validateTokens.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright © 2023 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*/
const config = require('../config');
const { readJsonFile } = require('./utils/fs');

const validateTokens = async (changedAppFiles) => {
const validationErrors = [];

const nativetokenFiles = changedAppFiles.filter((filename) => filename.endsWith(config.filename.NATIVE_TOKENS));

// eslint-disable-next-line no-restricted-syntax
for (const nativetokenFile of nativetokenFiles) {
// eslint-disable-next-line no-await-in-loop
const nativeTokensdata = await readJsonFile(nativetokenFile);
const { tokens } = nativeTokensdata;

// eslint-disable-next-line no-restricted-syntax
for (const token of tokens) {
const isBaseDenomInDenomUnits = token.denomUnits.some(unit => unit.denom === token.baseDenom);
if (!isBaseDenomInDenomUnits) {
validationErrors.push(`baseDenom "${token.baseDenom}" is not defined in denomUnits.`);
}

const isBaseDenomDefinitionValid = token.denomUnits.some(unit => unit.denom === token.baseDenom && unit.decimals === 0);
if (isBaseDenomInDenomUnits && !isBaseDenomDefinitionValid) {
validationErrors.push(`baseDenom "${token.baseDenom}" defined in denomUnits does not have "decimals" set to 0.`);
}
}
}

return validationErrors;
};

module.exports = {
validateTokens,
};
Loading

0 comments on commit 6f3e9fd

Please sign in to comment.