2

So I encountered the following problem: I have an array with keys used to encrypt a string. A for loop goes through the array, encrypts the string with the current key and then pushes the encrypted string into a new array. Here the code:

var enc_gmessages = ['start'];

for(i = 0; i < pubkeys.length; i++) {
    var pubkey = pubkeys[i];

    if(pubkey != 'no' && pubkey != null) {
        var publicKey = openpgp.key.readArmored(pubkey);
        openpgp.encryptMessage(publicKey.keys, content).then(function(pgp_gmessage) {
            //string encrypted successfully
            console.log(pgp_gmessage);
            enc_gmessages.push(pgp_gmessage);
        }).catch(function(error) {
            console.log('error');
        });
    }
}
alert(enc_gmessages);

While the string gets encrypted successfully (and logged in the console) if there's a valid public key, the array only contains the 'start' element after the for loop. Can someone please point out what I'm doing wrong?

5
  • The encryption routine is asynchronous. The code uses a web worker (not sure what it does in Node). Thus the for loop finishes before anything has been encrypted. Commented Jan 7, 2016 at 16:18
  • you need to wrap this up in a function that returns a Promise. Commented Jan 7, 2016 at 16:20
  • what happens if you move alert(enc_gmessages); to the line immediately after your enc_gmessages.push(pgp_gmessage); ? Commented Jan 7, 2016 at 16:24
  • @Tokn there's already a console.log() call in there. Commented Jan 7, 2016 at 16:26
  • @Pointy I can't see it Commented Jan 7, 2016 at 16:26

2 Answers 2

3

You're trying to obtain a value from an asynchronous operation before it has completed.

That's not possible, so what you should do is create a new Promise whose eventual result will be the expected array of messages:

function getMessages(pubkeys) {

    // get an array of Promises for each valid key - each element is 
    // a promise that will be "resolved" with the encrypted message
    var promises = pubkeys.filter(function(pubkey) {
        return pubkey != null && pubkey != 'no';
    }).map(function(pubkey) {
        var publicKey = openpgp.key.readArmored(pubkey);
        return openpgp.encryptMessage(publicKey.keys, content);
    });

    // then once all are resolved, return a new promise that
    // is resolved with the desired array
    return Promise.all(promises).then(function(messages) {
        return ['start'].concat(messages);
    });
}

Although you could .catch after the Promise.all line, it would be more usual to catch any failures at the point this was invoked.

If the "start" element in the returned array was only there for debugging and isn't actually required, just replace the entire return block with return Promise.all(promises).

Sign up to request clarification or add additional context in comments.

Comments

0

I think the promises system is causing trouble here. You push elements into the array in the callback of each promises returned by openpgp.encryptMessage(...), so the loop ends before any action takes actually place.

2 Comments

given the OP's already using promises, this is not the way to wait for them all to finish. That's what Promise.all() is for.
This code has the same problem - that encryptionCompleted() function doesn't really do anything; the returned function is ignored.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.