Error Trace activating invitation


#1
TypeError: First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.
    at fromObject (index.js:326)
    at from (index.js:142)
    at Function.Buffer.from (index.js:155)
    at getPublicKeyFromPrivate (keys.js:41)
    at signECDSA (encryption.js:210)
    at GroupMembership._callee7$ (model.js:formatted:509)
    at tryCatch (runtime.js:62)
    at Generator.invoke [as _invoke] (runtime.js:288)
    at Generator.prototype.(:3000/anonymous function) [as next] (webpack-internal:///./node_modules/@babel/runtime/node_modules/regenerator-runtime/runtime.js:114:21)
    at asyncGeneratorStep (asyncToGenerator.js:3)
    at _next (asyncToGenerator.js:25)
    at eval (asyncToGenerator.js:32)
    at new Promise (<anonymous>)
    at GroupMembership.eval (asyncToGenerator.js:21)
    at GroupMembership.sign (model.js:formatted:523)
    at _callee3$ (model.js:formatted:308)
    at tryCatch (runtime.js:62)
    at Generator.invoke [as _invoke] (runtime.js:288)
    at Generator.prototype.(:3000/anonymous function) [as next] (webpack-internal:///./node_modules/@babel/runtime/node_modules/regenerator-runtime/runtime.js:114:21)
    at asyncGeneratorStep (asyncToGenerator.js:3)
    at _next (asyncToGenerator.js:25)
    at eval (asyncToGenerator.js:32)
    at new Promise (<anonymous>)
    at eval (asyncToGenerator.js:21)
    at eval (model.js:formatted:344)
    at new Promise (<anonymous>)
    at GroupMembership._callee4$ (model.js:formatted:284)
    at tryCatch (runtime.js:62)
    at Generator.invoke [as _invoke] (runtime.js:288)
    at Generator.prototype.(:3000/anonymous function) [as next] (webpack-internal:///./node_modules/@babel/runtime/node_modules/regenerator-runtime/runtime.js:114:21)
    at asyncGeneratorStep (asyncToGenerator.js:3)
    at _next (asyncToGenerator.js:25)
    at eval (asyncToGenerator.js:32)
    at new Promise (<anonymous>)
    at GroupMembership.eval (asyncToGenerator.js:21)
    at GroupMembership.save (model.js:formatted:358)
    at GroupInvitation._callee$ (group-invitation.js:152)
    at tryCatch (runtime.js:62)
    at Generator.invoke [as _invoke] (runtime.js:288)
    at Generator.prototype.(:3000/anonymous function) [as next] (webpack-internal:///./node_modules/@babel/runtime/node_modules/regenerator-runtime/runtime.js:114:21)
    at asyncGeneratorStep (asyncToGenerator.js:3)
    at _next (asyncToGenerator.js:25)
    at eval (asyncToGenerator.js:32)
    at new Promise (<anonymous>)
    at GroupInvitation.eval (asyncToGenerator.js:21)
    at GroupInvitation.activate (group-invitation.js:170)
    at ActivateInvitation._callee$ (ActivateInvitation.jsx:29)
    at tryCatch (runtime.js:62)
    at Generator.invoke [as _invoke] (runtime.js:288)
    at Generator.prototype.(:3000/anonymous function) [as next] (webpack-internal:///./node_modules/@babel/runtime/node_modules/regenerator-runtime/runtime.js:114:21)

code snippet:

...
handleSignIn = (e) =>  {
    if (isSignInPending()) {
      console.log('zero')
      (async () => {
        console.log('one')
        await handlePendingSignIn();
      })();
      (async () => {
        console.log('two')
        await User.createWithCurrentUser();
        console.log('three')
      })();
    } else {
      e.preventDefault();
      const origin = window.location.origin
      redirectToSignIn(origin, origin + '/manifest.json', ['store_write', 'publish_data'])
    }
  }

  handleSignOut(e) {
    e.preventDefault();
    signUserOut(window.location.origin);
  }

  oneTime = () => {
    (async () => {
      console.log('ya yeet')
      await User.createWithCurrentUser();
      console.log('ya yeet2')
    })();
  }

  render() {
    if (isUserSignedIn()) {
      this.oneTime()
    }
...

#2

I think you may have some issues with the way you’re writing asynchronous javascript. I may be mistaken, but the error is probably because the handlePendingSignIn() call is not finished before you call User.createWithCurrentUser().

This might help you:

handlePendingSignIn = async (e) => {
  if (isSignInPending()) {
    await handlePendingSignIn();
    await User.createWithCurrentUser();
  } else {
    e.preventDefault();
    const { origin } = window.location;
    redirectToSignIn(origin, origin + '/manifest.json', ['store_write', 'publish_data']);
  }
}


#3

I’ve completely replaced my code with yours above. I’m getting the same error.

I do have the following keys in local storage:

0: "GROUP_MEMBERSHIPS_STORAGE_KEY"
1: "blockstack"
2: "blockstack-gaia-hub-config"
3: "blockstack-transit-private-key"
4: "echo-reply-feztatc5a"

#4

Are you sure that the code snippet you provided is what is causing the error? The backtrace refers to GroupMembership, but that is nowhere in your code.


#5

Also, I’ve just now published 0.1.6 of radiks, which contains some fixes to GroupMembership functionality. That may fix your issues. I meant to publish the npm version earlier this week, but it appears that I only published to Github, and not npm. Sorry about that! Upgrading may help your issue.


#6

@hank
0.1.6 is the version that I’m working with. I’m doing the following

onst group = new UserGroup({ name: 'records-health-' + blockstack.loadUserData().profile.name }); 
        console.log(group);

        (async () => {
            await group.create();
            const invitation = await group.makeGroupMembership(this.state.usernameToInvite);
            console.log(invitation._id); // the ID used to later activate an invitation

#7

Hey @robert,

I think the name attribute of the UserGroup needs to be fixed – i.e. should not include the user’s name. The documentation for it doesn’t do that, for example. cc @hank


#8

I don’t think the name of the group is a problem. However, what may be happening is that you can’t make an invitation for someone who hasn’t signed in to your app. The reason is because you aren’t able to know their public key in order to create the invitation. Is that the case?


#9

I don’t believe so, because all of our members have signed into the app at least once.


#10

I see. If you could possibly send me your code in it’s current state, I can try debugging first thing in the morning. It’s hard for me to debug from these code samples, because I can’t see how the rest of the code is working. I’m hstove on Github or you can email me - {myfirstname}@blockstack.com . I’m sorry that you’re running into these issues!


#11

I can add you to the github and I’ll make a branch for you: ‘hank’

Also, I was looking for a use of this in lettermesh or graphite but it looks like they don’t use radiks.


#12

Also, slightly off topic but I’m trying get my own private key so that I can decrypt files that have been encrypted with my public key. How can I do that?

FYI we had to pivot from the UserGroups stuff since we couldn’t get it to work–we’re using the get/put api’s now with additional logic.
ccing you guys now cause we’re on a time crunch now @hank @jude


#13

Totally understood about the time crunch. I’m looking at the branch you made for me, and it looks like you’ve already took out the Radiks-related code that hooks up to the UI. I’m not sure how you hooked that in before, but I’m not able to figure it out.

You can always get your private key by running:

import { loadUserData } from 'blockstack'

const { appPrivateKey } = loadUserData();

#14

@hank

How can I get the User’s private key and not app’s private key?


#15

In Blockstack, you only have access to a user’s app private key. We do not expose their “master” private key for security reasons. If you want to implement sharing functionality in your app, I recommend you do the following:

  1. When user A logs in, get their app private key, and convert it to a public key using the blockstack.js getPublicKeyFromPrivate function.
  2. Save this public key as something like publickey.txt, unencrypted.
  3. When user B wants to share with user A, fetch publickey.txt from that user.
  4. Encrypt user B’s health records with the public key of user A.
  5. When user A wants to decrypt that shared file, they can just decrypt it with their app private key.

Hope that helps.


#16

Thanks Hank, that totally helped out.

In terms of hooking up the radiks server, this is what I did:
I ran radiks-server after installing it globally with npm. Afterward, this is where the activate function is being called–it seemed like this was the area that we couldn’t quite debug.
https://github.com/Altrum/TreeHacks/blob/hank/my-app/src/views/ActivateInvitation.jsx

Finally, the other source of trouble came from https://github.com/Altrum/TreeHacks/blob/hank/my-app/src/components/Collab.jsx
where we sometimes got a cant access -1 of null error.

I hope this can help you guys out


#17

@hank I am facing the same issue but intermittently even after changing the code as you advised.
I think the function handlePendingSignIn() is throwing the error.


#18

Can you further describe the error that is happening here? Can you be more specific about the exact user flow that causes this? Could you attach any backtraces?

Thanks!


#19

Thanks for your quick reply.

What happens is that the user/developer can be working normally and signed in, may be working on some feature that is not related with signing into blockstack then the app stops getting the user data from blockstack.
Resetting the browser and creating new blockstack ids doesn’t work.
This issue happens intermittently.

This is a snippet of the relevant code:

class App extends Component {

componentWillMount = async () => {
const userSession = new UserSession({ appConfig });
radiks.configure({
apiServer: API_URL,
userSession
});

if (!userSession.isUserSignedIn() && userSession.isSignInPending()) {
  // the function handlePendingSignIn() returns the error:
  // Uncaught (in promise) TypeError: First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object. */
  const userData = await userSession.handlePendingSignIn();
  if (!userData.username) {
    throw new Error("This app requires a username");
  }
}

This is what’s inside the GROUP_MEMBERSHIPS_STORAGE_KEY:

{
“userGroups”:{

},
“signingKeys”:{

},
“personal”:{
“_id”:{
“iv”:“8af5d6c66570125eaf7b2a5e79f8ac90”,
“ephemeralPK”:“0209dab99bbe1661bbf188dd6493c651c1915ffb98d1f303937934b9743ad7c991”,
“cipherText”:“c6bcd955357bdebb42334a2acf7a46144418f7a3069715db26ea2266ce5f4b977301cde4fb0e40c493423b6f9a4bec1b”,
“mac”:“fd0c733f4a25afc87df0f1ae3e7131559ce3c11748e5692129a112ea23603d58”,
“wasString”:true
},
“updatable”:false,
“radiksType”:“SigningKey”
}
}

Is this a problem caused by the client getting encrypted data?

I am not sure how can I get more helpful details. Can you please advise about how to get backtraces?


#20

I also noticed that in a working app this is the values inside GROUP_MEMBERSHIPS_STORAGE_KEY:
{

“userGroups”:{

},

“signingKeys”:{

},

“personal”:{

  "updatable":false,

  "_id":"b4e4bf083f16-4eed-a437-4062cd9494df",

  "radiksType":"SigningKey",

  "publicKey":"0303600a45a3948996aea8e5405ca7aa092e60ea09fe087b46192126e7d5f2a0cf",

  "privateKey":MY_PRIVATE_KEY,

  "createdAt":1554206551774,

  "updatedAt":1554206551774

}

}

does that mean that when the application is not working that the keys are not properly set in the local storage?