Skip to content

Commit

Permalink
Add grpc client tls certificate (#2715)
Browse files Browse the repository at this point in the history
  • Loading branch information
vctt94 committed Oct 16, 2020
1 parent 9ae70ad commit d60213a
Show file tree
Hide file tree
Showing 10 changed files with 80 additions and 30 deletions.
7 changes: 5 additions & 2 deletions app/actions/AccountMixerActions.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getAccountMixerService } from "wallet";
import { getAccountMixerService, getDcrwalletGrpcKeyCert } from "wallet";
import Promise from "promise";
import * as sel from "selectors";
import * as wallet from "wallet";
Expand All @@ -17,12 +17,15 @@ export const getAccountMixerServiceAttempt = () => (dispatch, getState) => {
const {
daemon: { walletName }
} = getState();
const grpcCertAndKey = getDcrwalletGrpcKeyCert();
dispatch({ type: GETACCOUNTMIXERSERVICE_ATTEMPT });
return getAccountMixerService(
sel.isTestNet(getState()),
walletName,
address,
port
port,
grpcCertAndKey,
grpcCertAndKey
)
.then((accountMixerService) =>
dispatch({ accountMixerService, type: GETACCOUNTMIXERSERVICE_SUCCESS })
Expand Down
14 changes: 9 additions & 5 deletions app/actions/ClientActions.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// @flow
import * as wallet from "wallet";
import { onAppReloadRequested, getDcrwalletGrpcKeyCert } from "wallet";
import * as sel from "selectors";
import eq from "lodash/fp/eq";
import {
Expand All @@ -20,7 +21,6 @@ import { getAccountMixerServiceAttempt } from "./AccountMixerActions";
import { checkLnWallet } from "./LNActions";
import { push as pushHistory, goBack } from "connected-react-router";
import { getWalletCfg, getGlobalCfg } from "config";
import { onAppReloadRequested } from "wallet";
import { clipboard } from "electron";
import { getStartupStats } from "./StatisticsActions";
import { getTokenAndInitialBatch } from "./GovernanceActions";
Expand Down Expand Up @@ -147,8 +147,9 @@ export const getWalletServiceAttempt = () => (dispatch, getState) => {
daemon: { walletName }
} = getState();
dispatch({ type: GETWALLETSERVICE_ATTEMPT });
const grpcCertAndKey = getDcrwalletGrpcKeyCert();
wallet
.getWalletService(sel.isTestNet(getState()), walletName, address, port)
.getWalletService(sel.isTestNet(getState()), walletName, address, port, grpcCertAndKey, grpcCertAndKey)
.then((walletService) =>
dispatch({ walletService, type: GETWALLETSERVICE_SUCCESS })
)
Expand All @@ -167,8 +168,9 @@ export const getTicketBuyerServiceAttempt = () => (dispatch, getState) => {
daemon: { walletName }
} = getState();
dispatch({ type: GETTICKETBUYERSERVICE_ATTEMPT });
const grpcCertAndKey = getDcrwalletGrpcKeyCert();
wallet
.getTicketBuyerService(sel.isTestNet(getState()), walletName, address, port)
.getTicketBuyerService(sel.isTestNet(getState()), walletName, address, port, grpcCertAndKey, grpcCertAndKey)
.then((ticketBuyerService) => {
dispatch({ ticketBuyerService, type: GETTICKETBUYERSERVICE_SUCCESS });
})
Expand Down Expand Up @@ -495,8 +497,9 @@ export const getAgendaServiceAttempt = () => (dispatch, getState) => {
daemon: { walletName }
} = getState();
dispatch({ type: GETAGENDASERVICE_ATTEMPT });
const grpcCertAndKey = getDcrwalletGrpcKeyCert();
wallet
.getAgendaService(sel.isTestNet(getState()), walletName, address, port)
.getAgendaService(sel.isTestNet(getState()), walletName, address, port, grpcCertAndKey, grpcCertAndKey)
.then((agendaService) => {
dispatch({ agendaService, type: GETAGENDASERVICE_SUCCESS });
setTimeout(() => {
Expand All @@ -518,8 +521,9 @@ export const getVotingServiceAttempt = () => (dispatch, getState) => {
daemon: { walletName }
} = getState();
dispatch({ type: GETVOTINGSERVICE_ATTEMPT });
const grpcCertAndKey = getDcrwalletGrpcKeyCert();
wallet
.getVotingService(sel.isTestNet(getState()), walletName, address, port)
.getVotingService(sel.isTestNet(getState()), walletName, address, port, grpcCertAndKey, grpcCertAndKey)
.then((votingService) =>
dispatch({ votingService, type: GETVOTINGSERVICE_SUCCESS })
)
Expand Down
7 changes: 5 additions & 2 deletions app/actions/VersionActions.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @flow
import { loaderRequest, getWalletSeedService } from "./WalletLoaderActions";
import { getVersionService, getVersionResponse } from "wallet";
import { getVersionService, getVersionResponse, getDcrwalletGrpcKeyCert } from "wallet";
import { push as pushHistory } from "connected-react-router";
import { ipcRenderer } from "electron";
import { isTestNet } from "selectors";
Expand All @@ -19,12 +19,15 @@ export const getVersionServiceAttempt = () => (dispatch, getState) =>
const {
daemon: { walletName }
} = getState();
const grpcCertAndKey = getDcrwalletGrpcKeyCert();
try {
const versionService = await getVersionService(
isTestNet(getState()),
walletName,
address,
port
port,
grpcCertAndKey,
grpcCertAndKey
);
dispatch({ versionService, type: GETVERSIONSERVICE_SUCCESS });
await dispatch(getWalletRPCVersionAttempt(versionService));
Expand Down
11 changes: 8 additions & 3 deletions app/actions/WalletLoaderActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import {
openWallet,
closeWallet,
getStakePoolInfo,
rescanPoint
rescanPoint,
getDcrwalletGrpcKeyCert
} from "wallet";
import * as wallet from "wallet";
import { rescanCancel, ticketBuyerCancel } from "./ControlActions";
Expand Down Expand Up @@ -47,11 +48,14 @@ export const loaderRequest = () => (dispatch, getState) =>
const {
daemon: { walletName }
} = getState();
const grpcCertAndKey = getDcrwalletGrpcKeyCert();
const request = {
isTestNet: isTestNet(getState()),
walletName,
address,
port
port,
cert: grpcCertAndKey,
key: grpcCertAndKey
};
dispatch({ request, type: LOADER_ATTEMPT });
try {
Expand Down Expand Up @@ -81,8 +85,9 @@ export const getWalletSeedService = () => (dispatch, getState) => {
daemon: { walletName }
} = getState();
dispatch({ type: GETWALLETSEEDSVC_ATTEMPT });
const grpcCertAndKey = getDcrwalletGrpcKeyCert();
return wallet
.getSeedService(isTestNet(getState()), walletName, address, port)
.getSeedService(isTestNet(getState()), walletName, address, port, grpcCertAndKey, grpcCertAndKey)
.then((seedService) => {
dispatch({ seedService, type: GETWALLETSEEDSVC_SUCCESS });
})
Expand Down
7 changes: 6 additions & 1 deletion app/main.development.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ import {
getSelectedWallet,
GetDcrlndPID,
GetDcrlndCreds,
dropDCRDSocket
dropDCRDSocket,
getDcrwalletGrpcKeyCert
} from "./main_dev/launch";
import {
getAvailableWallets,
Expand Down Expand Up @@ -479,6 +480,10 @@ ipcMain.on("get-dcrd-rpc-credentials", (event) => {
event.returnValue = getDcrdRpcCredentials();
});

ipcMain.on("get-dcrwallet-grpc-cert-key", (event) => {
event.returnValue = getDcrwalletGrpcKeyCert();
});

ipcMain.on("set-previous-wallet", (event, cfg) => {
previousWallet = cfg;
event.returnValue = true;
Expand Down
21 changes: 20 additions & 1 deletion app/main_dev/launch.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,11 @@ let dcrdPID, dcrwPID, dcrlndPID;
// windows-only stuff
let dcrwPipeRx, dcrwPipeTx, dcrdPipeRx, dcrwTxStream;

// general data that needs to keep consistency while decrediton is running.
let dcrwPort;
let rpcuser, rpcpass, rpccert, rpchost, rpcport;
let dcrlndCreds;
let dcrwalletGrpcKeyCert;

let dcrdSocket,
heightIsSynced,
Expand Down Expand Up @@ -95,6 +97,16 @@ export const setSelectedWallet = (w) => {

export const getSelectedWallet = () => selectedWallet;

export const getDcrwalletGrpcKeyCert = () => dcrwalletGrpcKeyCert;

export const setDcrwalletGrpcKeyCert = (grpcKeyCert) => {
if (!Buffer.isBuffer(grpcKeyCert)) {
logger.log("error", "Error getting grpc key and cert from dcrwallet, " +
"grpc key and cert value: " + grpcKeyCert);
}
dcrwalletGrpcKeyCert = grpcKeyCert;
};

export function closeDCRD() {
if (dcrdPID === -1) {
// process is not started by decrediton
Expand Down Expand Up @@ -533,8 +545,10 @@ export const launchDCRWallet = (
: "";
let args = [confFile];

// add needed dcrwallet flags
args.push("--gaplimit=" + cfg.get("gaplimit"));

args.push("--authtype=clientcert");
args.push("--issueclientcert");
const dcrwExe = getExecutablePath("dcrwallet", argv.custombinpath);
if (!fs.existsSync(dcrwExe)) {
logger.log(
Expand Down Expand Up @@ -565,6 +579,11 @@ export const launchDCRWallet = (
);
}
}
if (mtype === "issuedclientcertificate") {
logger.log("info", "wallet grpc cert registered");
// store dcrwallet grpc cert and key.
setDcrwalletGrpcKeyCert(payload);
}
});

if (os.platform() == "win32") {
Expand Down
33 changes: 21 additions & 12 deletions app/middleware/grpc/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ const getServiceClient = (clientClass) => (
walletPath,
address,
port,
grpcKey,
grpccert,
cb
) => {
const cert = getWalletCert(getWalletPath(isTestNet, walletPath));
Expand All @@ -20,19 +22,26 @@ const getServiceClient = (clientClass) => (
"Unable to load dcrwallet certificate. dcrwallet not running?"
);
}
const creds = grpc.credentials.createSsl(cert);
const client = new clientClass(address + ":" + port, creds);

const deadline = new Date();
const deadlineInSeconds = 30;
deadline.setSeconds(deadline.getSeconds() + deadlineInSeconds);
grpc.waitForClientReady(client, deadline, function (err) {
if (err) {
return cb(null, err);
} else {
return cb(client);
}
});
try {
// dcrwallet sends the key and cert on the same payload after starting.
// So we can use the same value for both of them.
const creds = grpc.credentials.createSsl(cert, grpcKey, grpccert);
const client = new clientClass(address + ":" + port, creds);

const deadline = new Date();
const deadlineInSeconds = 30;
deadline.setSeconds(deadline.getSeconds() + deadlineInSeconds);
grpc.waitForClientReady(client, deadline, function (err) {
if (err) {
return cb(null, err);
} else {
return cb(client);
}
});
} catch (err) {
return cb(null, err);
}
};

export const getWalletService = getServiceClient(services.WalletServiceClient);
Expand Down
2 changes: 2 additions & 0 deletions app/wallet/daemon.js
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,8 @@ export const getAvailableWallets = log(
logOptionNoResponseData()
);

export const getDcrwalletGrpcKeyCert = () => ipcRenderer.sendSync("get-dcrwallet-grpc-cert-key");

export const reloadAllowedExternalRequests = log(
() =>
Promise.resolve(ipcRenderer.sendSync("reload-allowed-external-request")),
Expand Down
4 changes: 2 additions & 2 deletions app/wallet/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ import {
} from "middleware/walletrpc/api_pb";

export const getLoader = log(
({ isTestNet, walletName, address, port }) =>
({ isTestNet, walletName, address, port, cert, key }) =>
new Promise((resolve, reject) =>
rpcLoader(isTestNet, walletName, address, port, (loader, error) =>
rpcLoader(isTestNet, walletName, address, port, cert, key, (loader, error) =>
error ? reject(error) : resolve(loader)
)
),
Expand Down
4 changes: 2 additions & 2 deletions app/wallet/version.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ const messages = require("../middleware/walletrpc/api_pb");
import { withLog as log } from "./index";

export const getVersionService = log(
(network, walletPath, address, port) =>
(network, walletPath, address, port, grpckey, grpccert) =>
new Promise((resolve, reject) =>
getService(network, walletPath, address, port, (versionService, error) =>
getService(network, walletPath, address, port, grpckey, grpccert, (versionService, error) =>
error ? reject(error) : resolve(versionService)
)
),
Expand Down

0 comments on commit d60213a

Please sign in to comment.