safe current work

This commit is contained in:
clauspeterhuebner 2025-08-20 16:26:02 +02:00
parent 70455ff9e3
commit 6e5fb223d6
42 changed files with 322 additions and 168 deletions

View File

@ -3,7 +3,7 @@ import { GraphQLClient, gql } from 'graphql-request'
import { CONFIG } from '@/config'
import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const'
import { TransactionTypeId } from '@/graphql/enum/TransactionTypeId'
import { TransactionTypeId } from 'core/src/graphql/enum/TransactionTypeId'
import { LogError } from '@/server/LogError'
import { getLogger } from 'log4js'

View File

@ -4,7 +4,7 @@ import { randombytes_random } from 'sodium-native'
import { CONFIG } from '@/config'
import { AuthenticationClient as V1_0_AuthenticationClient } from '@/federation/client/1_0/AuthenticationClient'
import { ensureUrlEndsWithSlash } from '@/util/utilities'
import { ensureUrlEndsWithSlash } from 'core'
import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const'
import { encryptAndSign, OpenConnectionJwtPayloadType } from 'shared'

View File

@ -0,0 +1,48 @@
import { FederatedCommunity as DbFederatedCommunity } from 'database'
import { GraphQLClient } from 'graphql-request'
import { LogError } from '@/server/LogError'
import { ensureUrlEndsWithSlash } from 'core/src/util/utilities'
import { getLogger } from 'log4js'
import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const'
import { EncryptedTransferArgs } from 'core'
import { processDisburseJwtOnSenderCommunity as processDisburseJwtOnSenderCommunityQuery } from './query/processDisburseJwtOnSenderCommunity'
const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.federation.client.1_0.DisbursementClient`)
export class DisbursementClient {
dbCom: DbFederatedCommunity
endpoint: string
client: GraphQLClient
constructor(dbCom: DbFederatedCommunity) {
this.dbCom = dbCom
this.endpoint = ensureUrlEndsWithSlash(dbCom.endPoint).concat(dbCom.apiVersion).concat('/')
this.client = new GraphQLClient(this.endpoint, {
method: 'POST',
jsonSerializer: {
parse: JSON.parse,
stringify: JSON.stringify,
},
})
}
async sendDisburseJwtToSenderCommunity(args: EncryptedTransferArgs): Promise<string | null> {
logger.debug('sendDisburseJwtToSenderCommunity against endpoint=', this.endpoint)
try {
const { data } = await this.client.rawRequest<{ processDisburseJwtOnSenderCommunity: string }>(processDisburseJwtOnSenderCommunityQuery, { args })
const responseJwt = data?.processDisburseJwtOnSenderCommunity
if (responseJwt) {
logger.debug('received response jwt', responseJwt)
return responseJwt
}
} catch (err) {
const errmsg = `sendDisburseJwtToSenderCommunity failed for endpoint=${this.endpoint}, err=${err}`
logger.error(errmsg)
throw new Error(errmsg)
}
return null
}
}

View File

@ -4,7 +4,7 @@ import { GraphQLClient } from 'graphql-request'
import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const'
import { getPublicCommunityInfo } from '@/federation/client/1_0/query/getPublicCommunityInfo'
import { getPublicKey } from '@/federation/client/1_0/query/getPublicKey'
import { ensureUrlEndsWithSlash } from '@/util/utilities'
import { ensureUrlEndsWithSlash } from 'core/src/util/utilities'
import { getLogger } from 'log4js'
import { PublicCommunityInfoLoggingView } from './logging/PublicCommunityInfoLogging.view'

View File

@ -0,0 +1,7 @@
import { gql } from 'graphql-request'
export const processDisburseJwtOnSenderCommunity = gql`
mutation ($args: EncryptedTransferArgs!) {
processDisburseJwtOnSenderCommunity(data: $args)
}
`

View File

@ -0,0 +1,3 @@
import { DisbursementClient as V1_0_DisbursementClient } from '@/federation/client/1_0/DisbursementClient'
export class DisbursementClient extends V1_0_DisbursementClient {}

View File

@ -1,3 +0,0 @@
import { SendCoinsClient as V1_0_SendCoinsClient } from '@/federation/client/1_0/SendCoinsClient'
export class SendCoinsClient extends V1_0_SendCoinsClient {}

View File

@ -3,7 +3,7 @@ import { FederatedCommunity as DbFederatedCommunity } from 'database'
import { AuthenticationClient as V1_0_AuthenticationClient } from '@/federation/client/1_0/AuthenticationClient'
import { AuthenticationClient as V1_1_AuthenticationClient } from '@/federation/client/1_1/AuthenticationClient'
import { ApiVersionType } from '@/federation/enum/apiVersionType'
import { ApiVersionType } from 'core'
type AuthenticationClient = V1_0_AuthenticationClient | V1_1_AuthenticationClient

View File

@ -0,0 +1,58 @@
import { FederatedCommunity as DbFederatedCommunity } from 'database'
import { DisbursementClient as V1_0_DisbursementClient } from '@/federation/client/1_0/DisbursementClient'
import { DisbursementClient as V1_1_DisbursementClient } from '@/federation/client/1_1/DisbursementClient'
import { ApiVersionType } from 'core'
type DisbursementClient = V1_0_DisbursementClient | V1_1_DisbursementClient
interface DisbursementClientInstance {
id: number
client: DisbursementClient
}
export class DisbursementClientFactory {
private static instanceArray: DisbursementClientInstance[] = []
/**
* The Singleton's constructor should always be private to prevent direct
* construction calls with the `new` operator.
*/
private constructor() {}
private static createDisbursementClient = (dbCom: DbFederatedCommunity) => {
switch (dbCom.apiVersion) {
case ApiVersionType.V1_0:
return new V1_0_DisbursementClient(dbCom)
case ApiVersionType.V1_1:
return new V1_1_DisbursementClient(dbCom)
default:
return null
}
}
/**
* The static method that controls the access to the singleton instance.
*
* This implementation let you subclass the Singleton class while keeping
* just one instance of each subclass around.
*/
public static getInstance(dbCom: DbFederatedCommunity): DisbursementClient | null {
const instance = DisbursementClientFactory.instanceArray.find(
(instance) => instance.id === dbCom.id,
)
if (instance) {
return instance.client
}
const client = DisbursementClientFactory.createDisbursementClient(dbCom)
if (client) {
DisbursementClientFactory.instanceArray.push({
id: dbCom.id,
client,
} as DisbursementClientInstance)
}
return client
}
}

View File

@ -1,10 +1,8 @@
import { FederatedCommunity as DbFederatedCommunity } from 'database'
import { FederationClient as V1_0_FederationClient } from '@/federation/client/1_0/FederationClient'
import { FederationClient as V1_1_FederationClient } from '@/federation/client/1_1/FederationClient'
import { ApiVersionType } from '@/federation/enum/apiVersionType'
import { ensureUrlEndsWithSlash } from '@/util/utilities'
import { ApiVersionType, ensureUrlEndsWithSlash } from 'core'
type FederationClient = V1_0_FederationClient | V1_1_FederationClient

View File

@ -15,7 +15,7 @@ import { createKeyPair } from 'shared'
import { getLogger } from 'log4js'
import { startCommunityAuthentication } from './authenticateCommunities'
import { PublicCommunityInfoLoggingView } from './client/1_0/logging/PublicCommunityInfoLogging.view'
import { ApiVersionType } from './enum/apiVersionType'
import { ApiVersionType } from 'core'
const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.federation.validateCommunities`)

View File

@ -2,7 +2,7 @@ import { Transaction as dbTransaction } from 'database'
import { Decimal } from 'decimal.js-light'
import { Field, Int, ObjectType } from 'type-graphql'
import { TransactionTypeId } from '@enum/TransactionTypeId'
import { TransactionTypeId } from 'core/src/graphql/enum/TransactionTypeId'
import { Decay } from './Decay'
import { User } from './User'

View File

@ -16,11 +16,11 @@ import { Paginated } from '@arg/Paginated'
import { SearchContributionsFilterArgs } from '@arg/SearchContributionsFilterArgs'
import { ContributionStatus } from '@enum/ContributionStatus'
import { ContributionType } from '@enum/ContributionType'
import { TransactionTypeId } from '@enum/TransactionTypeId'
import { AdminUpdateContribution } from '@model/AdminUpdateContribution'
import { Contribution, ContributionListResult } from '@model/Contribution'
import { OpenCreation } from '@model/OpenCreation'
import { UnconfirmedContribution } from '@model/UnconfirmedContribution'
import { TransactionTypeId } from 'core'
import { RIGHTS } from '@/auth/RIGHTS'
import {
@ -43,8 +43,8 @@ import { UpdateUnconfirmedContributionContext } from '@/interactions/updateUncon
import { LogError } from '@/server/LogError'
import { Context, getClientTimezoneOffset, getUser } from '@/server/context'
import { TRANSACTIONS_LOCK } from '@/util/TRANSACTIONS_LOCK'
import { fullName } from 'core'
import { calculateDecay, Decay } from 'shared'
import { fullName } from '@/util/utilities'
import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const'
import { ContributionMessageType } from '@enum/ContributionMessageType'

View File

@ -6,22 +6,19 @@ import { TransactionLinkFilters } from '@arg/TransactionLinkFilters'
import { ContributionCycleType } from '@enum/ContributionCycleType'
import { ContributionStatus } from '@enum/ContributionStatus'
import { ContributionType } from '@enum/ContributionType'
import { TransactionTypeId } from '@enum/TransactionTypeId'
import { Community } from '@model/Community'
import { ContributionLink } from '@model/ContributionLink'
import { Decay } from '@model/Decay'
import { RedeemJwtLink } from '@model/RedeemJwtLink'
import { TransactionLink, TransactionLinkResult } from '@model/TransactionLink'
import { User } from '@model/User'
import { QueryLinkResult } from '@union/QueryLinkResult'
import { TransactionTypeId } from 'core'
import {
AppDatabase,
Contribution as DbContribution,
ContributionLink as DbContributionLink,
Transaction as DbTransaction,
AppDatabase, Community as DbCommunity, Contribution as DbContribution,
ContributionLink as DbContributionLink, FederatedCommunity as DbFederatedCommunity, Transaction as DbTransaction,
TransactionLink as DbTransactionLink,
User as DbUser,
getHomeCommunity,
getHomeCommunity
} from 'database'
import { Decimal } from 'decimal.js-light'
import { Arg, Args, Authorized, Ctx, Int, Mutation, Query, Resolver } from 'type-graphql'
@ -37,12 +34,16 @@ import { LogError } from '@/server/LogError'
import { Context, getClientTimezoneOffset, getUser } from '@/server/context'
import { TRANSACTIONS_LOCK } from '@/util/TRANSACTIONS_LOCK'
import { TRANSACTION_LINK_LOCK } from '@/util/TRANSACTION_LINK_LOCK'
import { fullName } from '@/util/utilities'
import { calculateBalance } from '@/util/validate'
import { fullName } from 'core'
import { calculateDecay, decode, DisburseJwtPayloadType, encode, encryptAndSign, RedeemJwtPayloadType, verify } from 'shared'
import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const'
import { DisbursementClient as V1_0_DisbursementClient } from '@/federation/client/1_0/DisbursementClient'
import { DisbursementClientFactory } from '@/federation/client/DisbursementClientFactory'
import { EncryptedTransferArgs } from 'core'
import { getLogger, Logger } from 'log4js'
import { randombytes_random } from 'sodium-native'
import { executeTransaction } from './TransactionResolver'
import {
getAuthenticatedCommunities,
@ -53,7 +54,7 @@ import { getLastTransaction } from './util/getLastTransaction'
import { sendTransactionsToDltConnector } from './util/sendTransactionsToDltConnector'
import { transactionLinkList } from './util/transactionLinkList'
const createLogger = () => getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.graphql.resolver.TransactionLinkResolver`)
const createLogger = (method: string) => getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.graphql.resolver.TransactionLinkResolver.${method}`)
// TODO: do not export, test it inside the resolver
export const transactionLinkCode = (date: Date): string => {
@ -148,9 +149,9 @@ export class TransactionLinkResolver {
@Authorized([RIGHTS.QUERY_TRANSACTION_LINK])
@Query(() => QueryLinkResult)
async queryTransactionLink(@Arg('code') code: string): Promise<typeof QueryLinkResult> {
const logger = createLogger()
logger.addContext('code', code.substring(0, 6))
logger.debug('TransactionLinkResolver.queryTransactionLink...')
const methodLogger = createLogger('queryTransactionLink')
methodLogger.addContext('code', code.substring(0, 6))
methodLogger.debug('queryTransactionLink...')
if (code.match(/^CL-/)) {
const contributionLink = await DbContributionLink.findOneOrFail({
where: { code: code.replace('CL-', '') },
@ -171,7 +172,7 @@ export class TransactionLinkResolver {
}
// normal redeem code
if (txLinkFound) {
logger.debug(
methodLogger.debug(
'TransactionLinkResolver.queryTransactionLink... normal redeem code found=',
txLinkFound,
)
@ -186,7 +187,7 @@ export class TransactionLinkResolver {
return new TransactionLink(dbTransactionLink, new User(user), redeemedBy, communities)
} else {
// redeem jwt-token
return await this.queryRedeemJwtLink(code, logger)
return await this.queryRedeemJwtLink(code, methodLogger)
}
}
}
@ -197,8 +198,8 @@ export class TransactionLinkResolver {
@Arg('code', () => String) code: string,
@Ctx() context: Context,
): Promise<boolean> {
const logger = createLogger()
logger.addContext('code', code.substring(0, 6))
const methodLogger = createLogger('redeemTransactionLink')
methodLogger.addContext('code', code.substring(0, 6))
const clientTimezoneOffset = getClientTimezoneOffset(context)
// const homeCom = await DbCommunity.findOneOrFail({ where: { foreign: false } })
const user = getUser(context)
@ -206,7 +207,7 @@ export class TransactionLinkResolver {
// acquire lock
const releaseLock = await TRANSACTIONS_LOCK.acquire()
try {
logger.info('redeem contribution link...')
methodLogger.info('redeem contribution link...')
const now = new Date()
const queryRunner = db.getDataSource().createQueryRunner()
await queryRunner.connect()
@ -221,7 +222,7 @@ export class TransactionLinkResolver {
if (!contributionLink) {
throw new LogError('No contribution link found to given code', code)
}
logger.info('...contribution link found with id', contributionLink.id)
methodLogger.info('...contribution link found with id', contributionLink.id)
if (new Date(contributionLink.validFrom).getTime() > now.getTime()) {
throw new LogError('Contribution link is not valid yet', contributionLink.validFrom)
}
@ -278,7 +279,7 @@ export class TransactionLinkResolver {
}
const creations = await getUserCreation(user.id, clientTimezoneOffset)
logger.info('open creations', creations)
methodLogger.info('open creations', creations)
validateContribution(creations, contributionLink.amount, now, clientTimezoneOffset)
const contribution = new DbContribution()
contribution.userId = user.id
@ -383,7 +384,7 @@ export class TransactionLinkResolver {
transactionLink.memo,
linkedUser,
user,
logger,
methodLogger,
transactionLink,
)
await EVENT_TRANSACTION_LINK_REDEEM(
@ -413,9 +414,9 @@ export class TransactionLinkResolver {
@Arg('alias', { nullable: true }) alias?: string,
@Arg('validUntil', { nullable: true }) validUntil?: string,
): Promise<string> {
const logger = createLogger()
logger.addContext('code', code.substring(0, 6))
logger.debug('TransactionLinkResolver.queryRedeemJwt... args=', {
const methodLogger = createLogger('createRedeemJwt')
methodLogger.addContext('code', code.substring(0, 6))
methodLogger.debug('args=', {
gradidoId,
senderCommunityUuid,
senderCommunityName,
@ -466,40 +467,80 @@ export class TransactionLinkResolver {
@Arg('validUntil', { nullable: true }) validUntil?: string,
@Arg('recipientAlias', { nullable: true }) recipientAlias?: string,
): Promise<boolean> {
const logger = createLogger()
logger.addContext('code', code.substring(0, 6))
logger.debug('TransactionLinkResolver.disburseTransactionLink... args=', {
senderGradidoId,
senderCommunityUuid,
recipientCommunityUuid,
recipientCommunityName,
recipientGradidoId,
recipientFirstName,
code,
amount,
memo,
validUntil,
const handshakeID = randombytes_random().toString()
const methodLogger = createLogger(`disburseTransactionLink`)
methodLogger.addContext('handshakeID', handshakeID)
if(methodLogger.isDebugEnabled()) {
methodLogger.debug('args=', {
senderGradidoId,
senderCommunityUuid,
recipientCommunityUuid,
recipientCommunityName,
recipientGradidoId,
recipientFirstName,
code,
amount,
memo,
validUntil,
recipientAlias,
})
const disburseJwt = await this.createDisburseJwt(
senderCommunityUuid,
senderGradidoId,
recipientCommunityUuid,
recipientCommunityName,
recipientGradidoId,
recipientFirstName,
code,
amount,
memo,
validUntil ?? '',
recipientAlias ?? '',
)
try {
logger.debug('TransactionLinkResolver.disburseTransactionLink... disburseJwt=', disburseJwt)
// now send the disburseJwt to the sender community to invoke a x-community-tx to disbures the redeemLink
// await sendDisburseJwtToSenderCommunity(context, disburseJwt)
} catch (e) {
throw new LogError('Disburse JWT was not sent successfully', e)
})
}
const senderCom = await DbCommunity.findOneBy({ communityUuid: senderCommunityUuid })
if (!senderCom) {
const errmsg = `Sender community not found with uuid=${senderCommunityUuid}`
methodLogger.error(errmsg)
throw new LogError(errmsg)
}
const senderFedCom = await DbFederatedCommunity.findOneBy({ publicKey: senderCom.publicKey })
if (!senderFedCom) {
const errmsg = `Sender federated community not found with publicKey=${senderCom.publicKey}`
methodLogger.error(errmsg)
throw new LogError(errmsg)
}
const recipientCom = await DbCommunity.findOneBy({ communityUuid: recipientCommunityUuid })
if (!recipientCom) {
const errmsg = `Recipient community not found with uuid=${recipientCommunityUuid}`
methodLogger.error(errmsg)
throw new LogError(errmsg)
}
const client = DisbursementClientFactory.getInstance(senderFedCom)
if (client instanceof V1_0_DisbursementClient) {
const disburseJwtPayload = new DisburseJwtPayloadType(
handshakeID,
senderCommunityUuid,
senderGradidoId,
recipientCommunityUuid,
recipientCommunityName,
recipientGradidoId,
recipientFirstName,
code,
amount,
memo,
validUntil!,
recipientAlias!,
)
if(methodLogger.isDebugEnabled()) {
methodLogger.debug('disburseJwtPayload=', disburseJwtPayload)
}
const jws = await encryptAndSign(disburseJwtPayload, recipientCom.privateJwtKey!, senderCom.publicJwtKey!)
if(methodLogger.isDebugEnabled()) {
methodLogger.debug('jws=', jws)
}
const args = new EncryptedTransferArgs()
args.publicKey = senderCom.publicKey.toString('hex')
args.jwt = jws
args.handshakeID = handshakeID
try {
// now send the disburseJwt to the sender community to invoke a x-community-tx to disbures the redeemLink
const result = await client.sendDisburseJwtToSenderCommunity(args)
if(methodLogger.isDebugEnabled()) {
methodLogger.debug('Disburse JWT was sent successfully with result=', result)
}
} catch (e) {
const errmsg = `Disburse JWT was not sent successfully with error=${e}`
methodLogger.error(errmsg)
throw new Error(errmsg)
}
}
return true
}
@ -653,56 +694,4 @@ export class TransactionLinkResolver {
)
}
}
async createDisburseJwt(
handshakeId: string,
senderCommunityUuid: string,
senderGradidoId: string,
recipientCommunityUuid: string,
recipientCommunityName: string,
recipientGradidoId: string,
recipientFirstName: string,
code: string,
amount: string,
memo: string,
validUntil: string,
recipientAlias: string,
): Promise<string> {
const logger = createLogger()
logger.addContext('code', code.substring(0, 6))
logger.debug('TransactionLinkResolver.createDisburseJwt... args=', {
handshakeId,
senderCommunityUuid,
senderGradidoId,
recipientCommunityUuid,
recipientCommunityName,
recipientGradidoId,
recipientFirstName,
code,
amount,
memo,
validUntil,
recipientAlias,
})
const disburseJwtPayload = new DisburseJwtPayloadType(
handshakeId,
senderCommunityUuid,
senderGradidoId,
recipientCommunityUuid,
recipientCommunityName,
recipientGradidoId,
recipientFirstName,
code,
amount,
memo,
validUntil,
recipientAlias,
)
const disburseJwt = await encryptAndSign(disburseJwtPayload, homeComB.privateJwtKey!, authCom.publicJwtKey!)
// TODO:encode/sign the jwt normally with the private key of the recipient community, but interims with uuid
logger.debug('TransactionLinkResolver.createDisburseJwt... disburseJwt=', disburseJwt)
// TODO: encrypt the payload with the public key of the target/sender community
return disburseJwt
}
}

View File

@ -16,9 +16,9 @@ import { cleanDB, testEnvironment } from '@test/helpers'
import { CONFIG } from '@/config'
import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const'
import { EventType } from '@/event/Events'
import { SendCoinsClient } from '@/federation/client/1_0/SendCoinsClient'
import { SendCoinsArgs } from '@/federation/client/1_0/model/SendCoinsArgs'
import { SendCoinsResult } from '@/federation/client/1_0/model/SendCoinsResult'
import { SendCoinsClient } from 'core/src/federation/client/1_0/SendCoinsClient'
import { SendCoinsArgs } from 'core/src/federation/client/1_0/model/SendCoinsArgs'
import { SendCoinsResult } from 'core/src/federation/client/1_0/model/SendCoinsResult'
import { userFactory } from '@/seeds/factory/user'
import {
confirmContribution,

View File

@ -2,7 +2,6 @@ import {
AppDatabase,
countOpenPendingTransactions,
Community as DbCommunity,
PendingTransaction as DbPendingTransaction,
Transaction as dbTransaction,
TransactionLink as dbTransactionLink,
User as dbUser,
@ -15,11 +14,11 @@ import { In, IsNull } from 'typeorm'
import { Paginated } from '@arg/Paginated'
import { TransactionSendArgs } from '@arg/TransactionSendArgs'
import { Order } from '@enum/Order'
import { PendingTransactionState, SendCoinsResponseJwtPayloadType } from 'shared'
import { TransactionTypeId } from '@enum/TransactionTypeId'
import { Transaction } from '@model/Transaction'
import { TransactionList } from '@model/TransactionList'
import { User } from '@model/User'
import { TransactionTypeId } from 'core/src/graphql/enum/TransactionTypeId'
import { SendCoinsResponseJwtPayloadType } from 'shared'
import { RIGHTS } from '@/auth/RIGHTS'
import { CONFIG } from '@/config'
@ -28,26 +27,25 @@ import {
sendTransactionReceivedEmail,
} from '@/emails/sendEmailVariants'
import { EVENT_TRANSACTION_RECEIVE, EVENT_TRANSACTION_SEND } from '@/event/Events'
import { SendCoinsResult } from '@/federation/client/1_0/model/SendCoinsResult'
import { LogError } from '@/server/LogError'
import { Context, getUser } from '@/server/context'
import { TRANSACTIONS_LOCK } from '@/util/TRANSACTIONS_LOCK'
import { communityUser } from '@/util/communityUser'
import { fullName } from '@/util/utilities'
import { calculateBalance } from '@/util/validate'
import { virtualDecayTransaction, virtualLinkTransaction } from '@/util/virtualTransactions'
import { fullName, SendCoinsResult } from 'core'
import { Logger, getLogger } from 'log4js'
import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const'
import {
processXComCommittingSendCoins,
processXComPendingSendCoins,
} from 'core'
import { getLogger, Logger } from 'log4js'
import { BalanceResolver } from './BalanceResolver'
import { GdtResolver } from './GdtResolver'
import { getCommunityByIdentifier, getCommunityName, isHomeCommunity } from './util/communities'
import { getLastTransaction } from './util/getLastTransaction'
import { getTransactionList } from './util/getTransactionList'
import {
processXComCommittingSendCoins,
processXComPendingSendCoins,
} from './util/processXComSendCoins'
import { sendTransactionsToDltConnector } from './util/sendTransactionsToDltConnector'
import { storeForeignUser } from './util/storeForeignUser'
import { transactionLinkSummary } from './util/transactionLinkSummary'

View File

@ -12,7 +12,7 @@ import { cleanDB, testEnvironment } from '@test/helpers'
import { i18n as localization } from '@test/testSetup'
import { CONFIG } from '@/config'
import { TransactionTypeId } from '@/graphql/enum/TransactionTypeId'
import { TransactionTypeId } from 'core'
import { creations } from '@/seeds/creation'
import { creationFactory } from '@/seeds/factory/creation'
import { userFactory } from '@/seeds/factory/user'

View File

@ -1,6 +1,6 @@
import { Community as DbCommunity, User as DbUser } from 'database'
import { SendCoinsResult } from '@/federation/client/1_0/model/SendCoinsResult'
import { SendCoinsResult } from 'core/src/federation/client/1_0/model/SendCoinsResult'
import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const'
import { getLogger } from 'log4js'

View File

@ -2,7 +2,7 @@ import { Transaction as dbTransaction } from 'database'
import { Decimal } from 'decimal.js-light'
import { RemoveOptions, SaveOptions } from 'typeorm'
import { TransactionTypeId } from '@enum/TransactionTypeId'
import { TransactionTypeId } from 'core/src/graphql/enum/TransactionTypeId'
import { Transaction } from '@model/Transaction'
import { User } from '@model/User'

View File

@ -192,6 +192,7 @@
"devDependencies": {
"@biomejs/biome": "2.0.0",
"@types/node": "^17.0.21",
"jest": "27.2.4",
"type-graphql": "^1.1.1",
"typescript": "^4.9.5",
},

View File

@ -27,6 +27,7 @@
"devDependencies": {
"@biomejs/biome": "2.0.0",
"@types/node": "^17.0.21",
"jest": "27.2.4",
"type-graphql": "^1.1.1",
"typescript": "^4.9.5"
},

View File

@ -1,7 +1,6 @@
import { FederatedCommunity as DbFederatedCommunity } from 'database'
import { GraphQLClient } from 'graphql-request'
import { LogError } from '@/server/LogError'
import { ensureUrlEndsWithSlash } from '@/util/utilities'
import { getLogger } from 'log4js'
@ -83,7 +82,9 @@ export class SendCoinsClient {
logger.debug(`settleSendCoins successful from endpoint=${this.endpoint}`)
return true
} catch (err) {
throw new LogError(`settleSendCoins failed for endpoint=${this.endpoint}`, err)
const errmsg = `settleSendCoins failed for endpoint=${this.endpoint}, err=${err}`
logger.error(errmsg)
throw new Error(errmsg)
}
}
@ -103,7 +104,9 @@ export class SendCoinsClient {
logger.debug(`revertSettledSendCoins successful from endpoint=${this.endpoint}`)
return true
} catch (err) {
throw new LogError(`revertSettledSendCoins failed for endpoint=${this.endpoint}`, err)
const errmsg = `revertSettledSendCoins failed for endpoint=${this.endpoint}, err=${err}`
logger.error(errmsg)
throw new Error(errmsg)
}
}
}

View File

@ -1,6 +1,6 @@
import { AbstractLoggingView } from 'database'
import { SendCoinsArgs } from '@/federation/client/1_0/model/SendCoinsArgs'
import { SendCoinsArgs } from 'core/src/federation/client/1_0/model/SendCoinsArgs'
export class SendCoinsArgsLoggingView extends AbstractLoggingView {
public constructor(private self: SendCoinsArgs) {

View File

@ -1,6 +1,6 @@
import { AbstractLoggingView } from 'database'
import { SendCoinsResult } from '@/federation/client/1_0/model/SendCoinsResult'
import { SendCoinsResult } from 'core/src/federation/client/1_0/model/SendCoinsResult'
export class SendCoinsResultLoggingView extends AbstractLoggingView {
public constructor(private self: SendCoinsResult) {

View File

@ -0,0 +1,3 @@
import { SendCoinsClient as V1_0_SendCoinsClient } from 'core/src/federation/client/1_0/SendCoinsClient'
export class SendCoinsClient extends V1_0_SendCoinsClient {}

View File

@ -1,9 +1,8 @@
import { FederatedCommunity as DbFederatedCommunity } from 'database'
import { SendCoinsClient as V1_0_SendCoinsClient } from '@/federation/client/1_0/SendCoinsClient'
import { SendCoinsClient as V1_1_SendCoinsClient } from '@/federation/client/1_1/SendCoinsClient'
import { ApiVersionType } from '@/federation/enum/apiVersionType'
import { SendCoinsClient as V1_0_SendCoinsClient } from '@federation/client/1_0/SendCoinsClient'
import { SendCoinsClient as V1_1_SendCoinsClient } from '@federation/client/1_1/SendCoinsClient'
import { ApiVersionType } from '@federation/enum/apiVersionType'
type SendCoinsClient = V1_0_SendCoinsClient | V1_1_SendCoinsClient

View File

@ -10,23 +10,22 @@ import {
} from 'database'
import { Decimal } from 'decimal.js-light'
import { CONFIG } from '@/config'
import { LOG4JS_BASE_CATEGORY_NAME } from '@config/const'
import { SendCoinsClient as V1_0_SendCoinsClient } from '@/federation/client/1_0/SendCoinsClient'
import { SendCoinsArgs } from '@/federation/client/1_0/model/SendCoinsArgs'
import { SendCoinsResult } from '@/federation/client/1_0/model/SendCoinsResult'
import { SendCoinsClientFactory } from '@/federation/client/SendCoinsClientFactory'
import { SendCoinsClient as V1_0_SendCoinsClient } from '@federation/client/1_0/SendCoinsClient'
import { SendCoinsArgs } from '@federation/client/1_0/model/SendCoinsArgs'
import { SendCoinsResult } from '@federation/client/1_0/model/SendCoinsResult'
import { SendCoinsClientFactory } from '@federation/client/SendCoinsClientFactory'
import { encryptAndSign, PendingTransactionState, SendCoinsJwtPayloadType, SendCoinsResponseJwtPayloadType, verifyAndDecrypt } from 'shared'
import { TransactionTypeId } from '@/graphql/enum/TransactionTypeId'
import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const'
import { LogError } from '@/server/LogError'
import { calculateSenderBalance } from '@/util/calculateSenderBalance'
import { fullName } from '@/util/utilities'
import { TransactionTypeId } from '@graphql/enum/TransactionTypeId'
import { LogError } from '@server/LogError'
import { calculateSenderBalance } from '@util/calculateSenderBalance'
import { fullName } from '@util/utilities'
import { getLogger } from 'log4js'
import { settlePendingSenderTransaction } from './settlePendingSenderTransaction'
import { SendCoinsArgsLoggingView } from '@/federation/client/1_0/logging/SendCoinsArgsLogging.view'
import { SendCoinsResultLoggingView } from '@/federation/client/1_0/logging/SendCoinsResultLogging.view'
import { settlePendingSenderTransaction } from '@graphql/resolver/util/settlePendingSenderTransaction'
import { SendCoinsArgsLoggingView } from '@federation/client/1_0/logging/SendCoinsArgsLogging.view'
import { SendCoinsResultLoggingView } from '@federation/client/1_0/logging/SendCoinsResultLogging.view'
import { EncryptedTransferArgs } from 'core'
import { randombytes_random } from 'sodium-native'

View File

@ -1,3 +1,17 @@
export * from './validation/user'
export * from './federation/client/1_0/logging/SendCoinsArgsLogging.view'
export * from './federation/client/1_0/logging/SendCoinsResultLogging.view'
export * from './federation/client/1_0/model/SendCoinsArgs'
export * from './federation/client/1_0/model/SendCoinsResult'
export * from './federation/client/1_0/query/revertSendCoins'
export * from './federation/client/1_0/query/revertSettledSendCoins'
export * from './federation/client/1_0/query/settleSendCoins'
export * from './federation/client/1_0/query/voteForSendCoins'
export * from './federation/client/SendCoinsClientFactory'
export * from './federation/enum/apiVersionType'
export * from './graphql/enum/TransactionTypeId'
export * from './graphql/logic/interpretEncryptedTransferArgs'
export * from './graphql/logic/processXComSendCoins'
export * from './graphql/model/EncryptedTransferArgs'
export * from './util/utilities'
export * from './validation/user'

View File

@ -44,8 +44,15 @@
/* Module Resolution Options */
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
// "baseUrl": ".", /* Base directory to resolve non-absolute module names. */
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
"baseUrl": ".", /* Base directory to resolve non-absolute module names. */
"paths": { /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
"@/*": ["src/*"],
"@config/*": ["src/config/*"],
"@federation/*": ["src/federation/*"],
"@graphql/*": ["src/graphql/*"],
"@util/*": ["src/util/*"],
"@validation/*": ["src/validation/*"],
},
// "rootDirs": [".", "../database"], /* List of root folders whose combined content represents the structure of the project at runtime. */
// "typeRoots": [], /* List of folders to include type definitions from. */
// "types": ["bun-types"], /* Type declaration files to be included in compilation. */

View File

@ -3,7 +3,7 @@ import { FederatedCommunity as DbFederatedCommunity } from 'database'
import { AuthenticationClient as V1_0_AuthenticationClient } from './1_0/AuthenticationClient'
import { AuthenticationClient as V1_1_AuthenticationClient } from './1_1/AuthenticationClient'
import { ApiVersionType } from './enum/ApiVersionType'
import { ApiVersionType } from 'core'
type AuthenticationClient = V1_0_AuthenticationClient | V1_1_AuthenticationClient

View File

@ -1,4 +0,0 @@
export enum ApiVersionType {
V1_0 = '1_0',
V1_1 = '1_1',
}

View File

@ -0,0 +1,33 @@
import { getLogger } from "log4js"
import { Arg, Mutation, Resolver } from "type-graphql"
import { LOG4JS_BASE_CATEGORY_NAME } from "@/config/const"
import { interpretEncryptedTransferArgs } from "core"
import { EncryptedTransferArgs } from "core"
import { DisburseJwtPayloadType } from "shared"
const createLogger = (method: string) => getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.graphql.api.1_0.resolver.DisbursementResolver.${method}`)
@Resolver()
export class DisbursementResolver {
@Mutation(() => String)
async processDisburseJwtOnSenderCommunity(
@Arg('data')
args: EncryptedTransferArgs,
): Promise<string> {
const methodLogger = createLogger(`processDisburseJwtOnSenderCommunity`)
methodLogger.addContext('handshakeID', args.handshakeID)
if(methodLogger.isDebugEnabled()) {
methodLogger.debug(`processDisburseJwtOnSenderCommunity() via apiVersion=1_0 ...`, args)
}
const authArgs = await interpretEncryptedTransferArgs(args) as DisburseJwtPayloadType
if (!authArgs) {
const errmsg = `invalid disbursement payload of requesting community with publicKey` + args.publicKey
methodLogger.error(errmsg)
throw new Error(errmsg)
}
if(methodLogger.isDebugEnabled()) {
methodLogger.debug(`processDisburseJwtOnSenderCommunity() via apiVersion=1_0 ...`, authArgs)
}
}
}