Skip to content

Commit

Permalink
Merge pull request #173 from dappnode/v0.2.8
Browse files Browse the repository at this point in the history
v0.2.8 Release
  • Loading branch information
eduadiez authored Jan 23, 2021
2 parents a021ebf + 7668c9a commit f9a8743
Show file tree
Hide file tree
Showing 28 changed files with 154 additions and 330 deletions.
15 changes: 15 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
name: Build test
on:
push:
pull_request:

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: npx @dappnode/dappnodesdk github-action build
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PINATA_API_KEY: ${{ secrets.PINATA_API_KEY }}
PINATA_SECRET_API_KEY: ${{ secrets.PINATA_SECRET_API_KEY }}
8 changes: 0 additions & 8 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,6 @@ jobs:
- run: yarn test
- run: yarn test:int

build-test:
runs-on: ubuntu-16.04
name: Build test
steps:
- name: Checkout
uses: actions/checkout@v2
- run: docker-compose build

release:
name: Release
runs-on: ubuntu-latest
Expand Down
7 changes: 6 additions & 1 deletion build/bin/ovpn_genconfig
Original file line number Diff line number Diff line change
Expand Up @@ -304,8 +304,13 @@ set -u
# fi

# Save the current OVPN_ vars to the ovpn_env.sh file

# Clean file to not concatenate config
# Syntax `true > $PATH` deletes the contents of $PATH without deleting the file
true > $OVPN_ENV

(set | grep '^OVPN_') | while read -r var; do
echo "declare -x $var" >>"$OVPN_ENV"
echo "declare -x $var" >> "$OVPN_ENV"
done

conf=${OPENVPN:-}/openvpn.conf
Expand Down
4 changes: 2 additions & 2 deletions build/bin/ovpn_getclient
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ remote-cert-tls server
remote $OVPN_HOSTNAME $OVPN_PORT $OVPN_PROTO"

if [ -n "$OVPN_INTERNAL_IP" ]; then
echo "remote $OVPN_INTERNAL_IP $OVPN_PORT $OVPN_PROTO"
if [ -n "$DAPPNODE_INTERNAL_IP" ]; then
echo "remote $DAPPNODE_INTERNAL_IP $OVPN_PORT $OVPN_PROTO"
fi
if [ "$OVPN_PROTO" == "udp6" ]; then
echo "remote $OVPN_HOSTNAME $OVPN_PORT udp"
Expand Down
14 changes: 7 additions & 7 deletions build/src/src/api/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ export interface Routes {
*/
addDevice: (kwargs: { id: string }) => Promise<void>;

/**
* Returns the credentials file (.ovpn) for device `id`
* @param id "new-device"
*/
getCredFile({ id }: { id: string }): Promise<string>;

/**
* Creates a new OpenVPN credentials file, encrypted.
* The filename is the (16 chars short) result of hashing the generated salt in the db,
Expand Down Expand Up @@ -43,12 +49,6 @@ export interface Routes {
*/
resetDevice: (kwargs: { id: string }) => Promise<void>;

/**
* Gives/removes admin rights to the provided device id.
* @param id Device id name
*/
toggleAdmin: (kwargs: { id: string }) => Promise<void>;

/**
* Returns a list of the existing devices, with the admin property
*/
Expand All @@ -57,12 +57,12 @@ export interface Routes {

export const routesData: { [P in keyof Routes]: {} } = {
addDevice: {},
getCredFile: {},
getDeviceCredentials: {},
getMasterAdminCred: {},
getStatus: {},
removeDevice: {},
resetDevice: {},
toggleAdmin: {},
listDevices: {}
};

Expand Down
9 changes: 9 additions & 0 deletions build/src/src/calls/getCredFile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { getClient } from "../openvpn";

/**
* Returns the credentials file (.ovpn) for device `id`
* @param id "new-device"
*/
export async function getCredFile({ id }: { id: string }): Promise<string> {
return await getClient(id);
}
14 changes: 7 additions & 7 deletions build/src/src/calls/getMasterAdminCred.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { addDevice } from "./addDevice";
import { toggleAdmin } from "./toggleAdmin";
import { MASTER_ADMIN_NAME } from "../params";
import { MAIN_ADMIN_NAME } from "../params";
import { logs } from "../logs";
import { getDeviceCredentials } from "./getDeviceCredentials";
import { VpnDeviceCredentials } from "../types";
Expand All @@ -15,14 +14,15 @@ import { listDevices } from "./listDevices";
export async function getMasterAdminCred(): Promise<VpnDeviceCredentials> {
try {
const devices = await listDevices();
if (!devices.find(d => d.id === MASTER_ADMIN_NAME)) {
await addDevice({ id: MASTER_ADMIN_NAME });
await toggleAdmin({ id: MASTER_ADMIN_NAME });
if (devices.find(d => d.id === MAIN_ADMIN_NAME)) {
logs.info(`User ${MAIN_ADMIN_NAME} already exists`);
} else {
await addDevice({ id: MAIN_ADMIN_NAME });
}
} catch (e) {
if (!e.message.includes("exist"))
logs.error(`Error creating ${MASTER_ADMIN_NAME} device`, e);
logs.error(`Error creating ${MAIN_ADMIN_NAME} device`, e);
}

return await getDeviceCredentials({ id: MASTER_ADMIN_NAME });
return await getDeviceCredentials({ id: MAIN_ADMIN_NAME });
}
2 changes: 1 addition & 1 deletion build/src/src/calls/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
export * from "./addDevice";
export * from "./getCredFile";
export * from "./getDeviceCredentials";
export * from "./getMasterAdminCred";
export * from "./getStatus";
export * from "./getVersionData";
export * from "./listDevices";
export * from "./removeDevice";
export * from "./resetDevice";
export * from "./toggleAdmin";
16 changes: 3 additions & 13 deletions build/src/src/calls/listDevices.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,13 @@
import { getUserList, getCCD } from "../openvpn";
import { VpnDevice, OpenVpnCCDItem } from "../types";
import { getUserList } from "../openvpn";
import { VpnDevice } from "../types";

/**
* Returns a list of the existing devices, with the admin property
*/
export async function listDevices(): Promise<VpnDevice[]> {
const userList = await getUserList();
const ccd = getCCD();

const ccdById = ccd.reduce(
(byId, device) => {
return { ...byId, [device.cn]: device };
},
{} as { [id: string]: OpenVpnCCDItem }
);

return userList.map(user => ({
id: user,
admin: Boolean(ccdById[user]),
ip: (ccdById[user] || {}).ip || ""
id: user
}));
}
11 changes: 7 additions & 4 deletions build/src/src/calls/removeDevice.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import { getUserList, getCCD, removeClient } from "../openvpn";
import { getUserList, removeClient } from "../openvpn";
import { MAIN_ADMIN_NAME } from "../params";

export const REMOVE_MAIN_ADMIN_ERROR = "Cannot remove the main admin user";

/**
* Removes the device with the provided id, if exists.
* @param id "new-device"
*/
export async function removeDevice({ id }: { id: string }): Promise<void> {
const deviceArray = await getUserList();
const ccdArray = getCCD();

if (ccdArray.find(c => c.cn === id))
throw Error("You cannot remove an admin user");
if (id === MAIN_ADMIN_NAME) {
throw Error(REMOVE_MAIN_ADMIN_ERROR);
}

if (!deviceArray.includes(id)) {
throw Error(`Device name not found: ${id}`);
Expand Down
25 changes: 0 additions & 25 deletions build/src/src/calls/toggleAdmin.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,26 @@ import {
GLOBAL_ENVS_KEYS,
GLOBAL_ENVS,
NO_HOSTNAME_RETURNED_ERROR
} from "./params";
import { isDomain } from "./utils/domain";
import { logs } from "./logs";
} from "../params";
import { isDomain } from "../utils/domain";

/**
* Polls the DAPPMANAGER to get the necessary config variables to start
* Polls the DAPPMANAGER to get the HOSTNAME (domain or IP) necessary to start
* the VPN config. If available, fetches the ENVs from process.env
* It throws an error after about 15 min of retries. The error should cause
* the main process to crash and be restarted by it's parent manager (i.e. docker)
*/
export async function pollDappnodeConfig({
export async function fetchHostname({
onRetry
}: {
onRetry: (errorMsg: string, retryCount: number) => void;
}): Promise<{
hostname: string;
internalIp: string;
}> {
}): Promise<string> {
// If ENVs are already available, do not poll
const hostnameFromEnv = process.env[GLOBAL_ENVS.HOSTNAME];
const internalIpFromEnv = process.env[GLOBAL_ENVS.INTERNAL_IP];
if (hostnameFromEnv && internalIpFromEnv)
return { hostname: hostnameFromEnv, internalIp: internalIpFromEnv };
const hostNameFromEnv = process.env[GLOBAL_ENVS.HOSTNAME];
if (hostNameFromEnv) return hostNameFromEnv;

// Add async-retry in case the DAPPMANAGER returns an 200 code with empty hostname
const hostname = await retry(
return await retry(
() =>
got(GLOBAL_ENVS_KEYS.HOSTNAME, {
throwHttpErrors: true,
Expand Down Expand Up @@ -61,18 +55,6 @@ export async function pollDappnodeConfig({
}
);

// internal IP is an optional feature for when NAT-Loopback is off
try {
const internalIp = await got(GLOBAL_ENVS_KEYS.INTERNAL_IP, {
throwHttpErrors: true,
prefixUrl: dappmanagerApiUrlGlobalEnvs
})
.text()
.then(res => res.trim());

return { hostname, internalIp };
} catch (e) {
logs.warn(`Error getting internal IP from DAPPMANAGER`, e);
return { hostname, internalIp: "" };
}
// internal IP not fetched here, it is an optional feature
// for when NAT-Loopback is off
}
29 changes: 29 additions & 0 deletions build/src/src/dappmanager/fetchInternalIp.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import ip from "ip";
import got from "got";
import { logs } from "../logs";
import { dappmanagerApiUrlGlobalEnvs, GLOBAL_ENVS_KEYS } from "../params";
import { config } from "../config";

export async function getInternalIpCached(): Promise<string> {
// internal IP is an optional feature for when NAT-Loopback is off
try {
const internalIp = await got(GLOBAL_ENVS_KEYS.INTERNAL_IP, {
throwHttpErrors: true,
prefixUrl: dappmanagerApiUrlGlobalEnvs
})
.text()
.then(res => res.trim());

if (!ip.isV4Format(internalIp))
throw Error(`Invalid internalIp returned: ${internalIp}`);

config.internalIp = internalIp;

return internalIp;
} catch (e) {
logs.warn("Error getting internal IP from DAPPMANAGER", e);

if (!config.internalIp) throw e;
return config.internalIp;
}
}
14 changes: 6 additions & 8 deletions build/src/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { startHttpApi } from "./api";
import { getMasterAdminCred } from "./calls";
import { printGitData } from "./utils/gitData";
import { startCredentialsWebserver } from "./credentials";
import { API_PORT, OPENVPN_CRED_PORT, MASTER_ADMIN_NAME } from "./params";
import { pollDappnodeConfig } from "./pollDappnodeConfig";
import { API_PORT, OPENVPN_CRED_PORT, MAIN_ADMIN_NAME } from "./params";
import { fetchHostname } from "./dappmanager/fetchHostname";
import { initalizeOpenVpnConfig, openvpnBinary } from "./openvpn";
import { config } from "./config";
import { startCredentialsService } from "./credentials";
Expand All @@ -25,7 +25,7 @@ startCredentialsService();
(async function startVpnClient(): Promise<void> {
try {
config.vpnStatus = { status: "FETCHING_CONFIG" };
const { hostname, internalIp } = await pollDappnodeConfig({
const hostname = await fetchHostname({
onRetry: (errorMsg, retryCount) => {
config.vpnStatus = {
status: "FETCHING_CONFIG_ERROR",
Expand All @@ -36,16 +36,14 @@ startCredentialsService();
}
});
config.hostname = hostname;
config.internalIp = internalIp;

logs.info("Initializing OpenVPN config", { hostname, internalIp });
logs.info(`Initializing OpenVPN config, hostname: ${config.hostname}`);
config.vpnStatus = { status: "INITIALIZING" };
await initalizeOpenVpnConfig({ hostname, internalIp });
await initalizeOpenVpnConfig(config.hostname);

try {
await getMasterAdminCred();
} catch (e) {
logs.error(`Error creating ${MASTER_ADMIN_NAME} device`, e);
logs.error(`Error creating ${MAIN_ADMIN_NAME} device`, e);
}

config.vpnStatus = { status: "READY" };
Expand Down
Loading

0 comments on commit f9a8743

Please sign in to comment.