Skip to content
This repository has been archived by the owner on Oct 4, 2024. It is now read-only.

Commit

Permalink
API keys support (MVP) (#878)
Browse files Browse the repository at this point in the history
* set-api-key command added
  • Loading branch information
volovyks authored Dec 13, 2021
1 parent bb4de4d commit fc4c835
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 13 deletions.
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,34 @@ export NEAR_ENV=mainnet

---

### Custom RPC server selection
You can set custom RPC server URL by setting this env variables:
```bash
NEAR_CLI_MAINNET_RPC_SERVER_URL
NEAR_CLI_TESTNET_RPC_SERVER_URL
NEAR_CLI_BETANET_RPC_SERVER_URL
NEAR_CLI_GUILDNET_RPC_SERVER_URL
NEAR_CLI_LOCALNET_RPC_SERVER_URL
NEAR_CLI_CI_RPC_SERVER_URL
```
Clear them in case you want to get back to the default RPC server.

Example:
```bash
export NEAR_CLI_TESTNET_RPC_SERVER_URL=<put_your_rpc_server_url_here>
```
---
### RPC server API Keys
Some RPC servers may require that you provide a valid API key to use them.

You can set `x-api-key` for a server by running the next command:
```bash
near set-api-key <rpc-server-url> <api-key>
```
This API Key will be saved in a config and used for each command you execute with this RPC URL.

---

## Access Keys

### `near login`
Expand Down
6 changes: 6 additions & 0 deletions bin/near-cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,11 @@ yargs // eslint-disable-line
type: 'string',
default: config.nodeUrl
})
.option('headers', {
hidden: true,
desc: 'headers for NEAR RPC server calls',
type: 'string',
})
.option('networkId', {
desc: 'NEAR network ID, allows using different keys based on network',
type: 'string',
Expand Down Expand Up @@ -256,6 +261,7 @@ yargs // eslint-disable-line
.command(require('../commands/evm-call'))
.command(require('../commands/evm-dev-init'))
.command(require('../commands/evm-view'))
.command(require('../commands/set-x-api-key'))
.config(config)
.alias({
'accountId': ['account_id'],
Expand Down
15 changes: 15 additions & 0 deletions commands/set-x-api-key.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const { setXApiKey, getXApiKey } = require('../utils/x-api-key-settings');
const chalk = require('chalk');
const exitOnError = require('../utils/exit-on-error');

module.exports = {
command: 'set-api-key <rpc-server> <x-api-key>',
desc: 'Add x-api-key for RPC Server',
builder: (yargs) => yargs,
handler: exitOnError(setApiKey)
};

async function setApiKey(options) {
setXApiKey(options.rpcServer, options.xApiKey);
console.log(chalk`x-api-key: {bold.white ${getXApiKey(options.rpcServer)}} is set for {bold.white ${options.rpcServer}} RPC Server`);
}
38 changes: 25 additions & 13 deletions config.js
Original file line number Diff line number Diff line change
@@ -1,72 +1,84 @@
const { getXApiKey } = require('./utils/x-api-key-settings.js');

const CONTRACT_NAME = process.env.CONTRACT_NAME;

function getConfig(env) {
let config;
switch (env) {

case 'production':
case 'mainnet':
return {
config = {
networkId: 'mainnet',
nodeUrl: 'https://rpc.mainnet.near.org',
nodeUrl: process.env.NEAR_CLI_MAINNET_RPC_SERVER_URL || 'https://rpc.mainnet.near.org',
contractName: CONTRACT_NAME,
walletUrl: 'https://wallet.near.org',
helperUrl: 'https://helper.mainnet.near.org',
helperAccount: 'near',
explorerUrl: 'https://explorer.mainnet.near.org',
};
break;
case 'development':
case 'testnet':
return {
config = {
networkId: 'testnet',
nodeUrl: 'https://rpc.testnet.near.org',
nodeUrl: process.env.NEAR_CLI_TESTNET_RPC_SERVER_URL || 'https://rpc.testnet.near.org',
contractName: CONTRACT_NAME,
walletUrl: 'https://wallet.testnet.near.org',
helperUrl: 'https://helper.testnet.near.org',
helperAccount: 'testnet',
explorerUrl: 'https://explorer.testnet.near.org',
};
break;
case 'betanet':
return {
config = {
networkId: 'betanet',
nodeUrl: 'https://rpc.betanet.near.org',
nodeUrl: process.env.NEAR_CLI_BETANET_RPC_SERVER_URL || 'https://rpc.betanet.near.org',
contractName: CONTRACT_NAME,
walletUrl: 'https://wallet.betanet.near.org',
helperUrl: 'https://helper.betanet.near.org',
helperAccount: 'betanet',
explorerUrl: 'https://explorer.betanet.near.org',
};
break;
case 'guildnet':
return {
config = {
networkId: 'guildnet',
nodeUrl: 'https://rpc.openshards.io',
nodeUrl: process.env.NEAR_CLI_GUILDNET_RPC_SERVER_URL || 'https://rpc.openshards.io',
contractName: CONTRACT_NAME,
walletUrl: 'https://wallet.openshards.io',
helperUrl: 'https://helper.openshards.io',
helperAccount: 'guildnet',
};
break;
case 'local':
case 'localnet':
return {
config = {
networkId: process.env.NEAR_CLI_LOCALNET_NETWORK_ID || 'local',
nodeUrl: process.env.NEAR_NODE_URL || 'http://localhost:3030',
nodeUrl: process.env.NEAR_CLI_LOCALNET_RPC_SERVER_URL || process.env.NEAR_NODE_URL || 'http://localhost:3030',
keyPath: process.env.NEAR_CLI_LOCALNET_KEY_PATH || `${process.env.HOME}/.near/validator_key.json`,
walletUrl: process.env.NEAR_WALLET_URL || 'http://localhost:4000/wallet',
contractName: CONTRACT_NAME,
helperUrl: process.env.NEAR_HELPER_URL || 'http://localhost:3000',
helperAccount: process.env.NEAR_HELPER_ACCOUNT || 'node0',
explorerUrl: process.env.NEAR_EXPLORER_URL || 'http://localhost:9001',
};
break;
case 'test':
case 'ci':
return {
config = {
networkId: 'shared-test',
nodeUrl: 'https://rpc.ci-testnet.near.org',
nodeUrl: process.env.NEAR_CLI_CI_RPC_SERVER_URL || 'https://rpc.ci-testnet.near.org',
contractName: CONTRACT_NAME,
masterAccount: 'test.near',
};
break;
default:
throw Error(`Unconfigured environment '${env}'. Can be configured in src/config.js.`);
}

// adding x-api-key for given RPC Server
config.headers = { 'x-api-key': getXApiKey(config.nodeUrl) };
return config;
}

module.exports = getConfig;
49 changes: 49 additions & 0 deletions test/unit/utils/x-api-key-settings.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
const { setXApiKey, getXApiKey } = require('../../../utils/x-api-key-settings.js');

const RPC_SERVER_URL_1 = 'https://test1.url.com';
const RPC_SERVER_URL_2 = 'https://test2.url.com';
const RPC_SERVER_URL_3 = 'https://test3.url.com';
const RPC_SERVER_API_KEY_1 = '1814c8b3-d7e1-4145-ba75-d6fc9787b27d';
const RPC_SERVER_API_KEY_2 = '2814c8b3-d7e1-4145-ba75-d6fc9787b27d';
const RPC_SERVER_API_KEY_3 = '3814c8b3-d7e1-4145-ba75-d6fc9787b27d';

const EMPTY_VALUES = [null, undefined, ''];

describe('x-api-key-settings tests', () => {
// set tests
test('set and get functionality works', async () => {
setXApiKey(RPC_SERVER_URL_1, RPC_SERVER_API_KEY_1);
setXApiKey(RPC_SERVER_URL_2, RPC_SERVER_API_KEY_2);
setXApiKey(RPC_SERVER_URL_3, RPC_SERVER_API_KEY_3);
const apiKey1FromConfig = getXApiKey(RPC_SERVER_URL_1);
const apiKey2FromConfig = getXApiKey(RPC_SERVER_URL_2);
const apiKey3FromConfig = getXApiKey(RPC_SERVER_URL_3);
expect(apiKey1FromConfig).toEqual(RPC_SERVER_API_KEY_1);
expect(apiKey2FromConfig).toEqual(RPC_SERVER_API_KEY_2);
expect(apiKey3FromConfig).toEqual(RPC_SERVER_API_KEY_3);
});

test('set API key for empty URL', async () => {
EMPTY_VALUES.map(val => {
expect(() => {
setXApiKey(val, RPC_SERVER_API_KEY_1);
}).toThrow('Empty value provided');
});
});

test('set empty API key', async () => {
EMPTY_VALUES.map(val => {
expect(() => {
setXApiKey(RPC_SERVER_URL_1, val);
}).toThrow('Empty value provided');
});
});

test('get API key for empty value', async () => {
EMPTY_VALUES.map(val => {
expect(() => {
getXApiKey(val);
}).toThrow('Empty value provided');
});
});
});
26 changes: 26 additions & 0 deletions utils/x-api-key-settings.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
const { saveShellSettings, getShellSettings } = require('./settings');

function setXApiKey(rpcServerUrl, xApiKey) {
if (!rpcServerUrl || !xApiKey) {
throw new Error('Empty value provided');
}
let shellSettings = getShellSettings();
if (!shellSettings.rpcServerApiKeys) {
shellSettings.rpcServerApiKeys = {};
}
shellSettings.rpcServerApiKeys[rpcServerUrl] = xApiKey;
saveShellSettings(shellSettings);
}

function getXApiKey(rpcServerUrl) {
if (!rpcServerUrl) {
throw new Error('Empty value provided');
}
const rpcServerApiKeys = getShellSettings().rpcServerApiKeys;
return rpcServerApiKeys ? rpcServerApiKeys[rpcServerUrl] : undefined;
}

module.exports = {
getXApiKey,
setXApiKey,
};

0 comments on commit fc4c835

Please sign in to comment.