Skip to content

Commit

Permalink
fix: Fix wallet association for same address - MEED-2318 (#394)
Browse files Browse the repository at this point in the history
Prior to this change, two users wa able to use the same address for
their Wallet. This change ensures to not have such a possible wallet
association by adding a proper Alert message when doing so.
In addition, this change will fix Mail Notification Footer creation with
missing 'COMPANY_LINK' variable.
In addition, this change will ensure to delete nonce of dropped
transactions (New feature used to replace/resend transactions) to ensure
to not have a not recognized nonce in blockchain.
  • Loading branch information
boubaker authored Jul 26, 2023
1 parent 7b58e38 commit 3ea4eb5
Show file tree
Hide file tree
Showing 23 changed files with 104 additions and 32 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* This file is part of the Meeds project (https://meeds.io/).
*
* Copyright (C) 2020 - 2023 Meeds Association [email protected]
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.exoplatform.wallet.model;

public class AddressAlreadyInUseException extends RuntimeException {

private static final long serialVersionUID = -6892231101205805806L;

}
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ public Response saveWalletBackupState(@Parameter(description = "wallet technical
@ApiResponse(responseCode = "200", description = "Request fulfilled"),
@ApiResponse(responseCode = "400", description = "Invalid query input"),
@ApiResponse(responseCode = "401", description = "Unauthorized operation"),
@ApiResponse(responseCode = "409", description = "Conflicted operation"),
@ApiResponse(responseCode = "500", description = "Internal server error") })
public Response saveWallet(@Parameter(description = "wallet details to save", required = true) Wallet wallet) {
if (wallet == null) {
Expand All @@ -324,6 +325,11 @@ public Response saveWallet(@Parameter(description = "wallet details to save", re
accountService.saveWalletAddress(storedWallet, currentUserId);
return Response.ok(storedWallet.getPassPhrase()).build();
}
} catch (AddressAlreadyInUseException e) {
LOG.warn("User '{}' is attempting to add a wallet address {} that is already in use",
currentUserId,
wallet.getAddress());
return Response.status(HTTPStatus.CONFLICT).build();
} catch (IllegalAccessException e) {
LOG.warn("User '{}' is not allowed to save wallet {}", currentUserId, wallet, e);
return Response.status(HTTPStatus.UNAUTHORIZED).build();
Expand Down Expand Up @@ -383,6 +389,12 @@ public Response saveWalletProvider(@Parameter(description = "New Wallet provider
accountService.switchWalletProvider(currentUserIdentityId, provider, address, rawMessage, signedMessage);
}
return Response.noContent().build();
} catch (AddressAlreadyInUseException e) {
LOG.warn("User '{}' is attempting to add a wallet address {} that is already in use",
currentUserIdentityId,
address,
e);
return Response.status(HTTPStatus.CONFLICT).build();
} catch (Exception e) {
LOG.warn("Unknown error occurred while switching identity '{}' wallet provider to '{}' ",
currentUserIdentityId,
Expand Down
4 changes: 2 additions & 2 deletions wallet-reward-services/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
</dependency>
<dependency>
<groupId>org.exoplatform.social</groupId>
<artifactId>social-component-core</artifactId>
<artifactId>social-component-notification</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
Expand All @@ -57,7 +57,7 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
<!-- Test dependencies -->
<dependency>
<groupId>org.exoplatform.social</groupId>
<artifactId>social-component-core</artifactId>
<artifactId>social-component-notification</artifactId>
<scope>test</scope>
<type>test-jar</type>
</dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import org.exoplatform.container.component.RequestLifeCycle;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.exoplatform.social.notification.plugin.SocialNotificationUtils;
import org.exoplatform.wallet.model.reward.RewardSettings;
import org.exoplatform.wallet.reward.service.RewardSettingsService;
import org.exoplatform.webui.utils.TimeConvertUtils;
Expand Down Expand Up @@ -89,6 +90,7 @@ protected MessageInfo makeMessage(NotificationContext ctx) {
templateContext.put("READ", Boolean.parseBoolean(notificationRead) ? "read" : "unread");

setLastModifiedDate(notification, language, templateContext);
SocialNotificationUtils.addFooterAndFirstName(notification.getTo(), templateContext);

String body = TemplateUtils.processGroovy(templateContext);
if (templateContext.getException() != null) {
Expand Down
4 changes: 2 additions & 2 deletions wallet-services/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
</dependency>
<dependency>
<groupId>org.exoplatform.social</groupId>
<artifactId>social-component-core</artifactId>
<artifactId>social-component-notification</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
Expand Down Expand Up @@ -92,7 +92,7 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
<!-- Test dependencies -->
<dependency>
<groupId>org.exoplatform.social</groupId>
<artifactId>social-component-core</artifactId>
<artifactId>social-component-notification</artifactId>
<type>test-jar</type>
<scope>test</scope>
</dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,7 @@ public void boostAdminTransactions() {
}
transactionDetail.setPending(false);
transactionDetail.setDropped(true);
transactionDetail.setNonce(0);
transactionService.saveTransactionDetail(transactionDetail, true);
} catch (Exception e) {
LOG.warn("Can't boost transaction {} with the new one {}",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,11 @@ public WalletEntity findByAddress(String address) {
return resultList == null || resultList.isEmpty() ? null : resultList.get(0);
}

public List<WalletEntity> findListByAddress(String address) {
TypedQuery<WalletEntity> query = getEntityManager().createNamedQuery("Wallet.findByAddress",
WalletEntity.class);
query.setParameter("address", StringUtils.lowerCase(address));
return query.getResultList();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.exoplatform.social.core.service.LinkProvider;
import org.exoplatform.social.notification.plugin.SocialNotificationUtils;
import org.exoplatform.wallet.model.WalletType;
import org.exoplatform.webui.utils.TimeConvertUtils;

Expand Down Expand Up @@ -99,9 +100,10 @@ protected MessageInfo makeMessage(NotificationContext ctx) {
templateContext.put("MESSAGE", message);
templateContext.put("AVATAR", avatar != null ? avatar : LinkProvider.PROFILE_DEFAULT_AVATAR_URL);
templateContext.put("NOTIFICATION_ID", notification.getId());
templateContext.put("READ", Boolean.valueOf(notificationRead) ? "read" : "unread");
templateContext.put("READ", Boolean.parseBoolean(notificationRead) ? "read" : "unread");
templateContext.put("FUNDS_REQUEST_SENT", Boolean.valueOf(fundRequestSent));
setLastModifiedDate(notification, language, templateContext);
SocialNotificationUtils.addFooterAndFirstName(notification.getTo(), templateContext);

String body = TemplateUtils.processGroovy(templateContext);
// binding the exception throws by processing template
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.exoplatform.social.core.service.LinkProvider;
import org.exoplatform.social.notification.plugin.SocialNotificationUtils;
import org.exoplatform.wallet.model.WalletType;
import org.exoplatform.webui.utils.TimeConvertUtils;

Expand Down Expand Up @@ -96,13 +97,14 @@ protected MessageInfo makeMessage(NotificationContext ctx) {
templateContext.put("SYMBOL", symbol);
templateContext.put("CONTRACT_ADDRESS", contractAddress == null ? "" : contractAddress);
templateContext.put("NOTIFICATION_ID", notification.getId());
templateContext.put("READ", Boolean.valueOf(notificationRead) ? "read" : "unread");
templateContext.put("READ", Boolean.parseBoolean(notificationRead) ? "read" : "unread");
templateContext.put("MESSAGE", message);
templateContext.put("HASH", hash);

String absoluteMyWalletLink = getWalletLink(receiverType, receiver);
templateContext.put("BASE_URL", absoluteMyWalletLink);
setLastUpdateDate(notification, language, templateContext);
SocialNotificationUtils.addFooterAndFirstName(notification.getTo(), templateContext);

String body = TemplateUtils.processGroovy(templateContext);
// binding the exception throws by processing template
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,7 @@ public void cancelTransactionsWithSameNonce(TransactionDetail replacingTransacti
transactions.forEach(replacedTransaction -> {
replacedTransaction.setDropped(true);
replacedTransaction.setPending(false);
replacedTransaction.setNonce(0);
saveTransactionDetail(replacedTransaction, true);
broadcastTransactionReplacedEvent(replacedTransaction, replacingTransaction);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.util.*;
import java.util.stream.Collectors;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import org.exoplatform.commons.api.persistence.ExoTransactional;
Expand Down Expand Up @@ -143,9 +144,19 @@ public void retrieveWalletBlockchainState(Wallet wallet, String contractAddress)
* @param wallet wallet details to save
* @param isNew whether this is a new wallet association or not
* @return saved wallet entity
* @throws AddressAlreadyInUseException when the address is already used by another wallet
*/
public Wallet saveWallet(Wallet wallet, boolean isNew) {
public Wallet saveWallet(Wallet wallet, boolean isNew) throws AddressAlreadyInUseException {
WalletEntity walletEntity = toEntity(wallet);
if (StringUtils.isNotBlank(wallet.getAddress())) {
List<WalletEntity> walletEntities = walletAccountDAO.findListByAddress(wallet.getAddress());
if (CollectionUtils.isNotEmpty(walletEntities)
&& walletEntities.stream()
.anyMatch(w -> w.getId() != wallet.getTechnicalId()
&& w.getInitializationState() != WalletState.DELETED)) {
throw new AddressAlreadyInUseException();
}
}
if (isNew) {
walletEntity = walletAccountDAO.create(walletEntity);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public Wallet saveWalletBackupState(long identityId, boolean backupState) {
}

@Override
public Wallet saveWallet(Wallet wallet, boolean isNew) {
public Wallet saveWallet(Wallet wallet, boolean isNew) throws AddressAlreadyInUseException {
String oldAddress = null;
if (!isNew) {
// Retrieve old wallet address
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -477,3 +477,4 @@ exoplatform.wallet.message.followTransaction={0} link to follow your transaction

wallet.mainCurrency=Matic
wallet.mainCurrencySymbol=Matic
wallet.addressAlreadyInUse=Address already in use by another wallet
Original file line number Diff line number Diff line change
Expand Up @@ -140,29 +140,35 @@ public void onEvent(Event<Object, Object> event) throws Exception {
storedTransactionDetail = walletTransactionService.getTransactionByHash(transactionDetail.getHash());
assertFalse(storedTransactionDetail.isPending());
assertFalse(storedTransactionDetail.isSucceeded());
assertEquals(0, storedTransactionDetail.getNonce());
assertFalse(listenerInvoked.get());

storedTransactionDetail.setPending(true);
storedTransactionDetail.setNonce(storedTransactionDetailReplacement.getNonce());
walletTransactionService.saveTransactionDetail(storedTransactionDetail, true);
errorReplacingTransaction = storedTransactionDetailReplacement.clone();
errorReplacingTransaction.setContractAmount(5000);
walletTransactionService.cancelTransactionsWithSameNonce(errorReplacingTransaction);
storedTransactionDetail = walletTransactionService.getTransactionByHash(transactionDetail.getHash());
assertFalse(storedTransactionDetail.isPending());
assertFalse(storedTransactionDetail.isSucceeded());
assertEquals(0, storedTransactionDetail.getNonce());
assertFalse(listenerInvoked.get());

storedTransactionDetail.setPending(true);
storedTransactionDetail.setNonce(storedTransactionDetailReplacement.getNonce());
walletTransactionService.saveTransactionDetail(storedTransactionDetail, true);
errorReplacingTransaction = storedTransactionDetailReplacement.clone();
errorReplacingTransaction.setContractAddress("another address");
walletTransactionService.cancelTransactionsWithSameNonce(errorReplacingTransaction);
storedTransactionDetail = walletTransactionService.getTransactionByHash(transactionDetail.getHash());
assertFalse(storedTransactionDetail.isPending());
assertFalse(storedTransactionDetail.isSucceeded());
assertEquals(0, storedTransactionDetail.getNonce());
assertFalse(listenerInvoked.get());

storedTransactionDetail.setPending(true);
storedTransactionDetail.setNonce(storedTransactionDetailReplacement.getNonce());
walletTransactionService.saveTransactionDetail(storedTransactionDetail, true);
walletTransactionService.cancelTransactionsWithSameNonce(storedTransactionDetailReplacement);
assertTrue(listenerInvoked.get());
Expand Down
3 changes: 3 additions & 0 deletions wallet-webapps/src/main/webapp/WEB-INF/gatein-resources.xml
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,9 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
<depends>
<module>eXoVueI18n</module>
</depends>
<depends>
<module>commonVueComponents</module>
</depends>
<depends>
<module>jquery</module>
<as>$</as>
Expand Down
11 changes: 4 additions & 7 deletions wallet-webapps/src/main/webapp/vue-app/wallet-app/spaceWallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,17 @@
import SpaceWalletApp from './components/SpaceWalletApp.vue';
import './initComponents.js';

Vue.use(Vuetify);
Vue.use(WalletCommon);

const vuetify = new Vuetify(eXo.env.portal.vuetifyPreset);

const lang = (eXo && eXo.env && eXo.env.portal && eXo.env.portal.language) || 'en';
const url = `${eXo.env.portal.context}/${eXo.env.portal.rest}/i18n/bundle/locale.addon.Wallet-${lang}.json`;

export function init() {
exoi18n.loadLanguageAsync(lang, url).then(i18n => {
new Vue({
Vue.createApp({
render: (h) => h(SpaceWalletApp),
i18n,
vuetify,
}).$mount('#SpaceWalletApp');
vuetify: Vue.prototype.vuetifyOptions,
i18n
}, '#SpaceWalletApp', 'Space Wallet Application');
});
}
11 changes: 4 additions & 7 deletions wallet-webapps/src/main/webapp/vue-app/wallet-app/wallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,20 @@
import WalletApp from './components/WalletApp.vue';
import './initComponents.js';

Vue.use(Vuetify);
Vue.use(WalletCommon);

const vuetify = new Vuetify(eXo.env.portal.vuetifyPreset);

const lang = (eXo && eXo.env && eXo.env.portal && eXo.env.portal.language) || 'en';
const url = `${eXo.env.portal.context}/${eXo.env.portal.rest}/i18n/bundle/locale.addon.Wallet-${lang}.json`;

export function init(generatedToken) {
exoi18n.loadLanguageAsync(lang, url).then(i18n => {
new Vue({
Vue.createApp({
data: () => ({
generatedToken,
}),
render: (h) => h(WalletApp),
i18n,
vuetify,
}).$mount('#WalletApp');
vuetify: Vue.prototype.vuetifyOptions,
i18n
}, '#WalletApp', 'User Wallet Application');
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-->
<template>
<v-flex class="transactionsList">
<v-flex class="transactionsList text-start">
<v-card class="card--flex-toolbar" flat>
<div v-if="error && !loading" class="alert alert-error">
<i class="uiIconError"></i>{{ error }}
Expand Down Expand Up @@ -361,7 +361,7 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
<v-list-item-content>
{{ $t('exoplatform.wallet.label.transactionMessage') }}
</v-list-item-content>
<v-list-item-content class="align-end text-end paragraph text-truncate">
<v-list-item-content class="align-end text-start paragraph">
{{ item.message }}
</v-list-item-content>
</v-list-item>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,11 @@ export default {
window.walletSettings.wallet.address = selectedAddress;
window.walletSettings.wallet.provider = 'METAMASK';
})
.catch(() => {
.catch(e => {
this.savingMetamaskAddress = false;
if (String(e).includes('wallet.addressConflict')) {
this.$root.$emit('alert-message', this.$t('wallet.addressAlreadyInUse'), 'error');
}
});
},
retrieveAddress() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,11 @@ export function switchProvider(provider, address, rawMessage, signedMessage) {
body: new URLSearchParams(formData).toString(),
}).then(resp => {
if (!resp || !resp.ok) {
throw new Error('Error saving new provider label');
if (resp.status === 409) {
throw new Error('wallet.addressConflict');
} else {
throw new Error('Error saving new provider label');
}
}
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,9 +174,12 @@ export default {
this.$root.$emit('wallet-settings-provider-changed', 'METAMASK');
this.savingMetamaskAddress = false;
})
.catch(() => {
.catch(e => {
this.$root.$emit('wallet-settings-provider-changing', window.walletSettings.wallet.provider);
this.savingMetamaskAddress = false;
if (String(e).includes('wallet.addressConflict')) {
this.$root.$emit('alert-message', this.$t('wallet.addressAlreadyInUse'), 'error');
}
});
},
retrieveAddress() {
Expand Down
Loading

0 comments on commit 3ea4eb5

Please sign in to comment.