chore: 🔧 improve logging

This commit is contained in:
AP 2020-05-23 14:46:47 +02:00
parent 7d7ef5697f
commit 414c20f053
9 changed files with 76 additions and 45 deletions

View file

@ -7,6 +7,7 @@ import {
CLIENT_ACCOUNT, CLIENT_ACCOUNT,
} from 'src/context/AccountContext'; } from 'src/context/AccountContext';
import { ContextType } from 'api/types/apiTypes'; import { ContextType } from 'api/types/apiTypes';
import { logger } from './logger';
const { serverRuntimeConfig } = getConfig(); const { serverRuntimeConfig } = getConfig();
const { nodeEnv } = serverRuntimeConfig; const { nodeEnv } = serverRuntimeConfig;
@ -35,24 +36,32 @@ export const getCorrectAuth = (
): LndAuthType => { ): LndAuthType => {
if (auth.type === SERVER_ACCOUNT) { if (auth.type === SERVER_ACCOUNT) {
const { account } = context; const { account } = context;
if (!account || account.id !== auth.id) if (!account) {
throw new Error('This account is not authenticated'); logger.debug('Account not available in request');
throw new Error('AccountNotAuthenticated');
const foundAccount = context.accounts.find(a => a.id === account.id); }
if (!foundAccount) throw new Error('This account does not exist'); if (account.id !== auth.id) {
logger.debug(
`Account (${account.id}) in cookie different to requested account (${auth.id})`
);
throw new Error('AccountNotAuthenticated');
}
return account; return account;
} }
if (auth.type === SSO_ACCOUNT) { if (auth.type === SSO_ACCOUNT) {
if (!context.ssoVerified) if (!context.ssoVerified) {
throw new Error('This account is not authenticated'); logger.debug('SSO Account is not verified');
throw new Error('AccountNotAuthenticated');
}
return { ...context.sso }; return { ...context.sso };
} }
if (auth.type === CLIENT_ACCOUNT) { if (auth.type === CLIENT_ACCOUNT) {
const { host, macaroon, cert } = auth; const { host, macaroon, cert } = auth;
return { host, macaroon, cert }; return { host, macaroon, cert };
} }
throw new Error('This account type does not exist'); throw new Error('AccountTypeDoesNotExist');
}; };
export const getAuthLnd = (auth: LndAuthType) => { export const getAuthLnd = (auth: LndAuthType) => {

View file

@ -2,9 +2,7 @@ import { createLogger, format, transports } from 'winston';
import getConfig from 'next/config'; import getConfig from 'next/config';
const { serverRuntimeConfig } = getConfig(); const { serverRuntimeConfig } = getConfig();
const { logLevel, nodeEnv } = serverRuntimeConfig; const { logLevel } = serverRuntimeConfig;
const level = nodeEnv === 'development' ? 'debug' : logLevel;
const combinedFormat = const combinedFormat =
// nodeEnv === 'development' ? // nodeEnv === 'development' ?
@ -33,7 +31,7 @@ const combinedFormat =
// ); // );
export const logger = createLogger({ export const logger = createLogger({
level, level: logLevel,
format: combinedFormat, format: combinedFormat,
transports: [new transports.Console()], transports: [new transports.Console()],
}); });

View file

@ -3,6 +3,7 @@ import jwt from 'jsonwebtoken';
import CryptoJS from 'crypto-js'; import CryptoJS from 'crypto-js';
import { ContextType } from 'api/types/apiTypes'; import { ContextType } from 'api/types/apiTypes';
import AES from 'crypto-js/aes'; import AES from 'crypto-js/aes';
import { logger } from 'api/helpers/logger';
import { requestLimiter } from '../../../helpers/rateLimiter'; import { requestLimiter } from '../../../helpers/rateLimiter';
export const getSessionToken = { export const getSessionToken = {
@ -17,11 +18,15 @@ export const getSessionToken = {
const account = context.accounts.find(a => a.id === params.id) || null; const account = context.accounts.find(a => a.id === params.id) || null;
if (!account) return null; if (!account) {
logger.debug(`Account ${params.id} not found`);
return null;
}
try { try {
const bytes = AES.decrypt(account.macaroon, params.password); const bytes = AES.decrypt(account.macaroon, params.password);
const decrypted = bytes.toString(CryptoJS.enc.Utf8); const decrypted = bytes.toString(CryptoJS.enc.Utf8);
logger.debug(`Correct password for account ${params.id}`);
const token = jwt.sign( const token = jwt.sign(
{ {
id: params.id, id: params.id,
@ -33,7 +38,7 @@ export const getSessionToken = {
); );
return AES.encrypt(token, secret).toString(); return AES.encrypt(token, secret).toString();
} catch (error) { } catch (error) {
throw new Error('Wrong password'); throw new Error('WrongPasswordForLogin');
} }
}, },
}; };

View file

@ -1,12 +1,8 @@
import { getWalletInfo, getClosedChannels } from 'ln-service'; import { getWalletInfo, getClosedChannels } from 'ln-service';
import { ContextType } from 'api/types/apiTypes'; import { ContextType } from 'api/types/apiTypes';
import { logger } from '../../../helpers/logger'; import { to } from 'api/helpers/async';
import { requestLimiter } from '../../../helpers/rateLimiter'; import { requestLimiter } from '../../../helpers/rateLimiter';
import { import { getAuthLnd, getCorrectAuth } from '../../../helpers/helpers';
getAuthLnd,
getErrorMsg,
getCorrectAuth,
} from '../../../helpers/helpers';
import { defaultParams } from '../../../helpers/defaultProps'; import { defaultParams } from '../../../helpers/defaultProps';
import { NodeInfoType } from '../../types/QueryType'; import { NodeInfoType } from '../../types/QueryType';
@ -36,20 +32,21 @@ export const getNodeInfo = {
const auth = getCorrectAuth(params.auth, context); const auth = getCorrectAuth(params.auth, context);
const lnd = getAuthLnd(auth); const lnd = getAuthLnd(auth);
try { const info = await to(
const info: NodeInfoProps = await getWalletInfo({ getWalletInfo({
lnd, lnd,
}); })
const closedChannels: { channels: [] } = await getClosedChannels({ );
const closedChannels = await to(
getClosedChannels({
lnd, lnd,
}); })
return { );
...info,
closed_channels_count: closedChannels.channels.length, return {
}; ...info,
} catch (error) { closed_channels_count: closedChannels?.channels?.length || 0,
logger.error('Error getting node info: %o', error); };
throw new Error(getErrorMsg(error));
}
}, },
}; };

View file

@ -43,6 +43,7 @@ const apolloServer = new ApolloServer({
let ssoVerified = false; let ssoVerified = false;
if (req?.cookies?.SSOAuth) { if (req?.cookies?.SSOAuth) {
logger.silly('SSOAuth cookie found in request');
try { try {
jwt.verify(req.cookies.SSOAuth, secret); jwt.verify(req.cookies.SSOAuth, secret);
ssoVerified = true; ssoVerified = true;
@ -53,6 +54,7 @@ const apolloServer = new ApolloServer({
let account = null; let account = null;
if (req?.cookies?.AccountAuth) { if (req?.cookies?.AccountAuth) {
logger.silly('AccountAuth cookie found in request');
try { try {
const bytes = AES.decrypt(req.cookies.AccountAuth, secret); const bytes = AES.decrypt(req.cookies.AccountAuth, secret);
const decrypted = bytes.toString(CryptoJS.enc.Utf8); const decrypted = bytes.toString(CryptoJS.enc.Utf8);

View file

@ -3,6 +3,7 @@ import { toast } from 'react-toastify';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { useAccountState } from 'src/context/AccountContext'; import { useAccountState } from 'src/context/AccountContext';
import { useGetMessagesQuery } from 'src/graphql/queries/__generated__/getMessages.generated'; import { useGetMessagesQuery } from 'src/graphql/queries/__generated__/getMessages.generated';
import { useStatusState } from 'src/context/StatusContext';
import { useChatState, useChatDispatch } from '../../context/ChatContext'; import { useChatState, useChatDispatch } from '../../context/ChatContext';
import { getErrorContent } from '../../utils/error'; import { getErrorContent } from '../../utils/error';
import { useConfigState } from '../../context/ConfigContext'; import { useConfigState } from '../../context/ConfigContext';
@ -12,6 +13,7 @@ export const ChatFetcher = () => {
const { chatPollingSpeed } = useConfigState(); const { chatPollingSpeed } = useConfigState();
const { connected } = useStatusState();
const { auth } = useAccountState(); const { auth } = useAccountState();
const { pathname } = useRouter(); const { pathname } = useRouter();
const { lastChat, chats, sentChats, initialized } = useChatState(); const { lastChat, chats, sentChats, initialized } = useChatState();
@ -20,7 +22,7 @@ export const ChatFetcher = () => {
const noChatsAvailable = chats.length <= 0 && sentChats.length <= 0; const noChatsAvailable = chats.length <= 0 && sentChats.length <= 0;
const { data, loading, error } = useGetMessagesQuery({ const { data, loading, error } = useGetMessagesQuery({
skip: !auth || initialized || noChatsAvailable, skip: !auth || initialized || noChatsAvailable || !connected,
pollInterval: chatPollingSpeed, pollInterval: chatPollingSpeed,
fetchPolicy: 'network-only', fetchPolicy: 'network-only',
variables: { auth, initialize: !noChatsAvailable }, variables: { auth, initialize: !noChatsAvailable },
@ -28,7 +30,7 @@ export const ChatFetcher = () => {
}); });
React.useEffect(() => { React.useEffect(() => {
if (data?.getMessages?.messages) { if (data && data.getMessages?.messages) {
const messages = [...data.getMessages.messages]; const messages = [...data.getMessages.messages];
let index = -1; let index = -1;

View file

@ -3,7 +3,7 @@ import { useRouter } from 'next/router';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import { useAccountState } from 'src/context/AccountContext'; import { useAccountState } from 'src/context/AccountContext';
import { useGetNodeInfoQuery } from 'src/graphql/queries/__generated__/getNodeInfo.generated'; import { useGetNodeInfoQuery } from 'src/graphql/queries/__generated__/getNodeInfo.generated';
import { useStatusDispatch } from '../../context/StatusContext'; import { useStatusDispatch, useStatusState } from '../../context/StatusContext';
import { appendBasePath } from '../../utils/basePath'; import { appendBasePath } from '../../utils/basePath';
export const StatusCheck = () => { export const StatusCheck = () => {
@ -11,9 +11,10 @@ export const StatusCheck = () => {
const { push } = useRouter(); const { push } = useRouter();
const { account, auth } = useAccountState(); const { account, auth } = useAccountState();
const { connected } = useStatusState();
const { data, loading, error, stopPolling } = useGetNodeInfoQuery({ const { data, loading, error, stopPolling } = useGetNodeInfoQuery({
skip: !auth, skip: !auth || !connected,
fetchPolicy: 'network-only', fetchPolicy: 'network-only',
variables: { auth }, variables: { auth },
pollInterval: 10000, pollInterval: 10000,
@ -55,7 +56,7 @@ export const StatusCheck = () => {
dispatch({ type: 'connected', state }); dispatch({ type: 'connected', state });
} }
}, [data, dispatch, error, loading, push, account]); }, [data, dispatch, error, loading, push, account, stopPolling]);
return null; return null;
}; };

View file

@ -10,6 +10,12 @@ const getMessage = error => {
return 'Did not find a possible route.'; return 'Did not find a possible route.';
case 'SendPaymentFail': case 'SendPaymentFail':
return 'Failed to send this payments.'; return 'Failed to send this payments.';
case 'AccountNotAuthenticated':
return 'This account is not authenticated.';
case 'AccountTypeDoesNotExist':
return 'This account does not exist.';
case 'WrongPasswordForLogin':
return 'Wrong password provided.';
default: default:
return error; return error;
} }

View file

@ -14,6 +14,7 @@ import Cookies from 'js-cookie';
import { useGetCanConnectLazyQuery } from 'src/graphql/queries/__generated__/getNodeInfo.generated'; import { useGetCanConnectLazyQuery } from 'src/graphql/queries/__generated__/getNodeInfo.generated';
import { useGetSessionTokenLazyQuery } from 'src/graphql/queries/__generated__/getSessionToken.generated'; import { useGetSessionTokenLazyQuery } from 'src/graphql/queries/__generated__/getSessionToken.generated';
import { getAuthFromAccount } from 'src/context/helpers/context'; import { getAuthFromAccount } from 'src/context/helpers/context';
import { getErrorContent } from 'src/utils/error';
import { SingleLine, Sub4Title, Card } from '../../components/generic/Styled'; import { SingleLine, Sub4Title, Card } from '../../components/generic/Styled';
import { getAuthObj } from '../../utils/auth'; import { getAuthObj } from '../../utils/auth';
import { ColorButton } from '../../components/buttons/colorButton/ColorButton'; import { ColorButton } from '../../components/buttons/colorButton/ColorButton';
@ -43,8 +44,8 @@ export const SessionLogin = () => {
const [getCanConnect, { data, loading }] = useGetCanConnectLazyQuery({ const [getCanConnect, { data, loading }] = useGetCanConnectLazyQuery({
fetchPolicy: 'network-only', fetchPolicy: 'network-only',
onError: () => { onError: err => {
toast.error('Unable to connect to this node'); toast.error(getErrorContent(err));
dispatch({ type: 'disconnected' }); dispatch({ type: 'disconnected' });
}, },
}); });
@ -54,14 +55,14 @@ export const SessionLogin = () => {
{ data: sData, loading: sLoading }, { data: sData, loading: sLoading },
] = useGetSessionTokenLazyQuery({ ] = useGetSessionTokenLazyQuery({
fetchPolicy: 'network-only', fetchPolicy: 'network-only',
onError: () => { onError: err => {
toast.error('Wrong password'); toast.error(getErrorContent(err));
dispatch({ type: 'disconnected' }); dispatch({ type: 'disconnected' });
}, },
}); });
useEffect(() => { useEffect(() => {
if (!sLoading && sData?.getSessionToken) { if (!sLoading && sData && sData.getSessionToken) {
Cookies.set('AccountAuth', sData.getSessionToken, { Cookies.set('AccountAuth', sData.getSessionToken, {
sameSite: 'strict', sameSite: 'strict',
}); });
@ -74,11 +75,21 @@ export const SessionLogin = () => {
}, [sLoading, sData, push, getCanConnect, account]); }, [sLoading, sData, push, getCanConnect, account]);
useEffect(() => { useEffect(() => {
if (!loading && data?.getNodeInfo && account.type === SERVER_ACCOUNT) { if (
!loading &&
data &&
data.getNodeInfo &&
account.type === SERVER_ACCOUNT
) {
dispatch({ type: 'connected' }); dispatch({ type: 'connected' });
push(appendBasePath('/home')); push(appendBasePath('/home'));
} }
if (!loading && data?.getNodeInfo && account.type === CLIENT_ACCOUNT) { if (
!loading &&
data &&
data.getNodeInfo &&
account.type === CLIENT_ACCOUNT
) {
const bytes = CryptoJS.AES.decrypt(account.admin, pass); const bytes = CryptoJS.AES.decrypt(account.admin, pass);
const decrypted = bytes.toString(CryptoJS.enc.Utf8); const decrypted = bytes.toString(CryptoJS.enc.Utf8);