how do I create a signature for the executeAllowanceTransfer function in safe modules AllowanceModule? - ethereum

I am trying to create a signature that is accepted by the executeAllowanceTransfer function. I can't workout how to generate a signature that is approved in the allowance as I keep getting the return error message of "expectedDelegate == signer && delegates[address(safe)][uint48(signer)].delegate == signer"
Allowance module can be found here: https://github.com/safe-global/safe-modules/blob/47e2b486b0b31d97bab7648a3f76de9038c6e67b/allowances/contracts/AlowanceModule.sol
I've tried to send a signature generated by passing transferHash into signer.signMessage via ethers.

use 0x as signature parameter
const executeTxResponse = await allowanceContract?.executeAllowanceTransfer('0xB91...B032E', '0x66...aF2, '0x345...Df5A', '1000000000000000000', '0x0000..0000', '0', '0x445...F404', '0x')

Related

yubihsm2 signatures are invalid when signing ETH transactions

I am trying to figure out how to get this yubihsm2 to work with signing eth transactions. I have been using the python lib and so far i have had some basic setup. Below is an abbreviation of what i have
web3_endpoint = ''
web3 = Web3(HTTPProvider(web3_endpoint))
hsm = YubiHsm.connect("http://localhost:12345")
session = hsm.create_session_derived(1, "password")
key = session.get_object(1,OBJECT.ASYMMETRIC_KEY)
#key = AsymmetricKey.generate(session, 1, "EC Key", 1, CAPABILITY.SIGN_ECDSA, ALGORITHM.EC_K256)
pub_key = key.get_public_key()
#raw_pub = pub_key.public_bytes(
# encoding=serialization.Encoding.DER,
# format=serialization.PublicFormat.SubjectPublicKeyInfo
# )
raw_pub = pub_key.public_bytes(
encoding=serialization.Encoding.X962,
format=serialization.PublicFormat.UncompressedPoint
)
print ("Public key (Uncompressed):\n",binascii.b2a_hex(raw_pub))
unindexPub = raw_pub[1:]
public_key_hash = Web3.keccak(unindexPub)
address_bytes = public_key_hash[-20:]
address = address_bytes.hex()
print(address)
Now so far i can consistently get the same public key and it looks correct. I then get the same public key each time. When i say correct, the formatting looks correct and is the correct number of bytes.
1). should i be using the commented out public key formatting or the uncompressed X962 encoding that i have above.
From there, this is where things get a bit weird
transaction = {
'to': Web3.toChecksumAddress('0x785AB1daE1b0Ee3f2412aCF55e4153A9517b07e1'),
'gas': 21000,
'gasPrice': Web3.toWei(5, 'gwei'),
'value': 1,
'nonce': 1,
'chainId': 4,
}
serializable_transaction = serializable_unsigned_transaction_from_dict(transaction)
transaction_hash = serializable_transaction.hash()
print(transaction_hash.hex())
# sign the transaction hash and calculate v value
signature = key.sign_ecdsa(transaction_hash,hashes.SHA3_256())
r, s = ecdsa.util.sigdecode_der(signature, ecdsa.SECP256k1.generator.order())
print("r: "+str(r)+"\ns: "+str(s))
v = 28
# encode the transaction along with the full signature and send it
encoded_transaction = encode_transaction(serializable_transaction, vrs=(v, r, s))
web3.eth.sendRawTransaction(encoded_transaction)
I am settings v to 28.. i also test it with 27.. I could use the correct amount with the chainid.. but it's not necessary right from the perspective of trying to get a valid signature (recoverable to get the same public key each time). Sometimes i am getting the error "invalid sender" and other times i am getting the error "insufficient gas." If i take the signature output and use a javascript lib to try to find the public key, each time i am getting a different public key. But i keep consistently generating the same public key from the yubihsm2 in this python app.
I have also commented out in sign_ecdsa the hashing function as i am passing in the data already hashed (in order to use keccak256).
Is there something i am missing? Why are these transactions not signing correctly for eth?
i am getting some of those serialization helpers from enter link description here
helper serialization functions
Thanks

Filter out empty address in web3.js

How to detect empty address that has initial value of 0x0000000000000000000000000000000000000000 in web3.js?
What I'm doing now is:
if (address !== '0x0000000000000000000000000000000000000000') {
...
}
Is there any simpler way to filter out empty addresses or a helper method in web3 that can create this value(like address(0) in Solidity)? It's quite bothering to count(or type) exact number of all that 0s.
Aside from #smarx's way: web3.toBigNumber(address).isZero()
You can use a simple regex, which is shorter:
const emptyAddress = /^0x0+$/.test(address);
You could also use OpenZeppelin's Test Helpers.
They have a constant called ZERO_ADDRESS which equals to zero address you mentioned.
More Info Here
Usage
First, you need to install:
npm install #openzeppelin/test-helpers
In JS file:
const constants = require('#openzeppelin/test-helpers');
console.log(constants.ZERO_ADDRESS);

Sequelize findAll query returning incorrect results

I'm using Passport, Nodemailer, Sequelize, and Express to handle verification of user accounts who have signed up via email to the app.
To test this feature, I use Mailinator accounts to sign up, and send the email (along with a query string containing the user email and a uniquely-determined verification code) to the specified Mailinator address using Nodemailer. I then open the email in Nodemailer, click on the verification link, which updates the verification flag in the database and verifies the user.
This process works as I expect it to for exactly one user who signs up via email. When a second user signs up, the verification email is sent just as before with the username and unique verification codes in the query string, but this time, multiple users are being returned from the User.findAll query through Sequelize when the link is clicked. My query is intended to findAll possible matches of both email addresses and verification codes (since each user can only sign on with one email address and verification codes are unique), but for some reason the query is returning all matches from that query.
Here is some code for reference:
/* Sending the emails */
emails.sendActivationEmail = function(user){
const qso = {username: user.username, activationCode: user.activationCode};
const qs = querystring.stringify(qso);
const from = new helper.Email(<myEmailAddress#email.com>);
const to = new helper.Email(user.username);
const subject = 'Welcome to My Site!';
const content = new helper.Content('text/html', "<p> Thanks for signing up " +
"for our psych study, please <a href=\"http://localhost:7000/users/validate/account?" +
qs + "\">confirm your email</a></p>");
const mail = new helper.Mail(from, subject, to, content);
sendMail(mail); //invokes SendGrid mail helper function
}
/* Function invoked when user clicks on verification link in email */
emails.validateUserAccount = function(req, res){
const url = parseUrl(req.url);
const query = querystring.parse(url.query);
db.User.findAll({where: query}).then(function(matches){
if(matches.length !== 1){
res.send('error: multiple users found');
}
else{
db.User.update({
isVerified : true
},
{
where: {
username: matches[0].username
}
});
req.session.user = matches[0];
res.redirect('/');
}
}).catch(function(err){
console.error(err);
res.send(err);
});
}
Console statements in the validateUserAccount() function reveal that the query is exactly as I expect ({username: <emailAddress>, activationCode: <uniqueCode>}). However, console.log statements made in the first line after the findAll query is executed reveal that all users are being returned from the query, which should be impossible if the WHERE query is being passed in correctly, which it looks like it is from the logged statements. Why is User.findAll returning incorrect results from my query?
The problem here is that you are using the return value of querystring.parse()
As denoted in the Node docs:
Note: The object returned by the querystring.parse() method does not prototypically extend from the JavaScript Object. This means that the typical Object methods such as obj.toString(), obj.hasOwnProperty(), and others are not defined and will not work.
It's likely the where clause expects an actual JS Object.
Further, as #doublesharp mentioned, you probably want to be fetching one row and validating it, as opposed to findAlling the rows and then filtering through. Also, you should take advantage of callbacks. You're writing blocking code right now.

How get the current user's own email address or check entered, using Exchange Web Services (EWS)?

I have to work with external Exchange server. How can I get the own email address or check address entered by the user (that he introduced exactly own address), using EWS?
Email address is not the same as username.
The best solution at this moment.
You can use ConvertId with a generic address and Exchange will then return the PrimarySMTP for that mailbox eg.
Folder Inbox = Folder.Bind(service, WellKnownFolderName.Inbox);
AlternateId aiAlternateid = new AlternateId(IdFormat.EwsId, Inbox.Id.UniqueId, "mailbox#domain.com");
AlternateIdBase aiResponse = service.ConvertId(aiAlternateid, IdFormat.EwsId);
Console.WriteLine(((AlternateId)aiResponse).Mailbox);
You might have some luck with the method ResolveName. Using this method you can search the Global Address List for the user. And by using a simple if else to see if any results were returned. This method does resolve ambiguous names so be sure to check the result carefully
Example:
NameResolutionCollection coll = service.ResolveName("Johnson", folders, ResolveNameSearchLocation.DirectoryOnly, false);
foreach (NameResolution nameRes in coll)
{
Console.WriteLine("Contact name: " + nameRes.Mailbox.Name);
Console.WriteLine("Contact e-mail address: " + nameRes.Mailbox.Address);
Console.WriteLine("Mailbox type: " + nameRes.Mailbox.MailboxType);
}
If you want to read more about it: https://msdn.microsoft.com/en-us/library/microsoft.exchange.webservices.data.exchangeservice.resolvename(v=exchg.80).aspx
Based on iCode4U's Answer, if your service uses default credentials (from the logged user), then this might get what you need:
String address = service.ResolveName(Environment.UserName)(0).Mailbox.Address;
EDIT: If one can't trust the uniqueness of the results brought by the query above, then it is better to use something like this (this would work in my organization, where usernames are also email identifiers, but each one must tweak it to fit his own scenario):
string address = Service.ResolveName(Environment.UserName).Select(
a => a.Mailbox.Address).FirstOrDefault(
b => b.StartsWith(Environment.UserName + "#",
StringComparison.InvariantCultureIgnoreCase));
We use this function loaded in the user PowerShell profile.
Function CurrentUserPrimarySmtpAddress()
{
<#
.SYSNOPSIS
Attempt to retrieve the current user's primary SMTP address.
.DESCRIPTION
Attempt to retrieve the current user's primary SMTP address.
.NOTES
Author: David Barrett
Date Created: 08NOV2016
.LINK
https://gallery.technet.microsoft.com/office/PowerShellEWS-Update-items-48c3dcfc
.EXAMPLE
$PrimarySmtpAddress = CurrentUserPrimarySmtpAddress
#>
$searcher = [adsisearcher]"(samaccountname=$env:USERNAME)"
$result = $searcher.FindOne()
if ($result -ne $null)
{
return $result.Properties["mail"]
}
return $null
}

Why can't I compute a correct HMAC signature?

I am trying to compute an HMAC signature in Google Apps Script, but the documentation isn't 100% clear on how I need to pass in the parameters, and I have been unable to get the expected output.
To determine if I am getting correct output, I am comparing the result against known-good PHP code. That code is:
$key = "a2V5"; # this is "key" base64-encoded
$value = "test";
$result = base64_encode(hash_hmac('sha512', $value, base64_decode($key), true));
My code in Google Apps Script is:
key = "a2V5"; // this is "key" base64-encoded
value = "test";
result = Utilities.base64Encode(Utilities.computeHmacSignature(Utilities.MacAlgorithm.HMAC_SHA_512, value, Utilities.base64Decode(key)));
The output I expected to receive was:
KHoPuJp/vfpbVThjaRjlN6W4MGXk/zMSaLeqoRXd4EepsPT7W4KGCPwLYyfxAFX3Y3sFjp4Nu55piQGj5t1GHA==
But what I got instead was:
mGXJ3X/nH5ZIFUAPtf1PsViY50pD3cfU7J8w2KAIEAqrAgZ3dpKcuy5V1yvH4/C5n1C9rFFsKc2JKHTwUqPscQ==
What did I screw up here?
I reviewed your code and there is one thing which caught my eye:
Utilities.base64Decode(key) method returns Byte[]
Utilities.computeHmacSignature(macAlgorithm, value, key) accepts 3 parameters. value and key are of type string.
Maybe this is the issue. Why don't you try something like the following and check results then:
key = "a2V5"; // this is "key" base64-encoded
clearKey = "key";
value = "test";
result = Utilities.base64Encode(Utilities.computeHmacSignature(Utilities.MacAlgorithm.HMAC_SHA_512, value, clearKey));
I check Google Apps Script here.