I am working in a proof of concept with a Node.js application and 'composer-client' npm module.
I have tried different commands such as adding a participant, adding an asset and performing a transaction and everything seems to work correctly.
However, when I try to issue a new identity I do not get the results that I expect. I execute my Node.js application with the following code:
var businessNetwork = new BusinessNetworkConnection();
return businessNetwork.connect('admin#tutorial-network')
.then(() => {
return businessNetwork.issueIdentity('org.acme.biznet.Trader#Trader_001', 'usr001')
})
.then((result) => {
console.log(`userID = ${result.userID}`);
console.log(`userSecret = ${result.userSecret}`);
})
.catch((error) => {
console.error(error);
});
Then, UserId and UserSecret are displayed at console log. After that, I try to do a ping to Business Network:
var businessNetwork = new BusinessNetworkConnection();
return businessNetwork.connect('usr001#tutorial-network')
.then(() => {
return businessNetwork.ping();
})
.then((result) => {
console.log(`participant = ${result.participant ? result.participant : '<no participant found>'}`);
})
.catch((error) => {
console.error(error);
});
However, I get the following error message:
{ Error: Card not found: usr001#tutorial-network
at IdCard.fromDirectory.catch.cause (/home/user.name/git_repositories/nodejs/first.blockchain.test/node_modules/composer-common/lib/cardstore/filesystemcardstore.js:73:27)
at <anonymous>
cause:
{ Error: Unable to read card directory: /home/user.name/.composer/cards/user001#tutorial-network
If I execute the command composer identity list -c admin#tutorial-network, I get the following output:
$class: org.hyperledger.composer.system.Identity
identityId: 9b49f67c262c0ae23e1e0c4a8dc61c4a12b5119df2b6a49fa2e02fa56b8818c3
name: usr001
issuer: 27c582d674ddf0f230854814b7cfd04553f3d0eac55e37d915386c614a5a1de9
certificate:
state: ISSUED
participant: resource:org.acme.biznet.Trader#Trader_001
But, I am not able to find the business card.
It works for me. I'm using composer 0.15.1.
var businessNetwork = new BusinessNetworkConnection();
return businessNetwork.connect('admin#carauction-network')
.then(() => {
return businessNetwork.ping();
})
.then((result) => {
console.log(`participant = ${result.participant ? result.participant : '<no participant found>'}`);
})
.catch((error) => {
console.error(error);
});
Output is like this
linux1#fabric:~/eventclient$ node event.js
participant = org.hyperledger.composer.system.NetworkAdmin#admin
You may need to import ID card to wallet ?
composer card import --file networkadmin.card
I had a similar issue late last week. Part of the upgrade instructions from V0.14 to V0.15 states that we have to delete the (if existing) ~/.composer, ~/.composer-connection-profiles and ~/.composer-credentials. I skipped that step on my first upgrade to v01.5 and encountered the error you are seeing. Went back and deleted those three folders, reinstalled the binaries and rechecked docker image status. Error went away and has not reappeared.
You named the new card user001, not user001##tutorial-network. Try connecting with just user001 as your connection card name.
I used the following command to create a card for the participant using the enrollment secret obtained from the javascript.
composer card create -u usr001 -s <enrollment_secret> -f usr001.card -n tutorial-network -p connection.json
You probably created the connection.json needed in some step before in the tutorial you are following. If this file is not available explicitly, you may get it from the composer wallet. In the current version, it can be located in /home/your_user/.composer/cards/. If you are only following the tutorial, any connection.json in this directory will do.
After that, you must add the credential created to the wallet using:
composer card import -f usr001.card
Your code for testing the issued identity is correct.
Related
I am in the process of upgrading an existing working Firebase Auth project to Identity Platform to benefit from the goodness of tenants.
I am currently testing this against the local emulator and am facing the following issues:
My users no longer show up in the emulator. I reckon, however, that
the behaviour is expected since I am creating users against a tenant
and no longer the default project users "pool"
The users do not show
up in the GCP console either. Yet, the getUserByEmail() method
in a Cloud Function returns the registered users. I therefore have no clue where these users are currently created...
Authenticating users via generateSignInWithEmailLink() works fine.
However, a few steps in the funnel after this, when using the await user?.getIdToken(true) method, I am getting the following error: Uncaught (in promise) FirebaseError: Firebase: Error (auth/invalid-refresh-token) and can't figure out why.
Interestingly, the user.getIdTokenResult() method works fine and does not yield any error.
My entire snippet:
const getCurrentUser = async (): Promise<Auth["currentUser"]> => {
return new Promise((resolve, reject) => {
const unsubscribe = onAuthStateChanged(
auth,
async (user) => {
if (user) {
if (document.referrer.includes("stripe")) {
// console.log({ user });
await user?.getIdToken(true);
console.log({ after: user });
}
state.isAuthenticated.value = true;
state.user.value = user;
try {
const { claims } = await user.getIdTokenResult();
state.claims.value = claims;
if (typeof claims.roles === "string") {
if (claims.active && claims.roles.includes("account_owner")) {
state.isActive.value = true;
}
}
} catch (e) {
console.log(e);
if (e instanceof Error) {
throw new Error();
}
}
}
unsubscribe();
resolve(user);
},
(e) => {
if (e instanceof Error) {
state.error.value = e.message;
logClientError(e as Error);
}
reject(e);
}
);
});
};
For reference, I am working with a Vue 3 / Vite repo.
Any suggestion would be welcome,
Thanks,
S.
Just a quick follow-up here for anyone looking for an answer to this.
I raised a bug report on the firebase-tools Github and:
Users not appearing in the Emulator UI: behaviour confirmed by the firebase team. The emulator does not not support multi-tenancy at the moment. In my experience, however, working with the emulator with multi-tenants, the basic functionalities seem to work: creating users, retrieving them. Impossible however to visualise them or export them.
Refresh token error: bug confirmed by the firebase team and in the process of being triaged. Will likely take some time before being fixed (if ever?). So for now, even if far from being ideal, I have added conditional checks to my code to skip the force refresh of the token on localhost. Instead, I log out and log back in with the users I am expecting to see some changes in the claims for, as this process does not error. Another solution would be to use an actual Firebase Auth instance and not the local emulator, but it feels a bit messy to combine localhost/emulator resources and actual ones, even with a dev account.
The GH issue: here.
When users sign up, they use Phone Auth. After using the app for a while, they are advised to link an (email & password) to their existing account.
The linking process fails because of the error (auth/requires-recent-login.) My code follows.
// The following generates the error: [auth/requires-recent-login] This operation is sensitive and requires recent authentication. Log in again before retrying this request.
const emailCredential = firebase.auth.EmailAuthProvider.credential(state.email, state.password);
const newCredential = await firebase.auth().currentUser.linkWithCredential(emailCredential);
To fix this error, I understand that I need to call reauthenticateWithCredential() before linking. However, I don't want to ask the user to log in again (receive & enter a verification code.) Is this at all possible?
I tried passing the result of currentUser.getIdToken(true) to PhoneAuthProvider.credential() I am not sure if this is right. Anyway, it generated an error (Cannot create PhoneAuthCredntial without either verificationProof, sessionInfo, temporary proof, or enrollment ID.).
My code follows.
// The following works:
const accessToken = await firebase.auth().currentUser.getIdToken(true);
// The following works:
const currentCredential = firebase.auth.PhoneAuthProvider.credential(accessToken);
// The following generates the error: Cannot create PhoneAuthCredential without either verificationProof, sessionInfo, temporary proof, or enrollment ID.
const abc = await firebase.auth().currentUser.reauthenticateWithCredential(currentCredential);
// The following is never reached:
const emailCredential = firebase.auth.EmailAuthProvider.credential(state.email, state.password);
const newCredential = await firebase.auth().currentUser.linkWithCredential(emailCredential);
Thank you for your effort and time to help me...
Important Information:
firebase.auth().currentUser.reauthenticateWithCredential(credential) requires the attribute credential
For users, who logged in using a Phone Number, I could not find a way to get this credential when required. By the way, it is possible to get it for users, who logged in using other providers, e.g. Facebook.
However, for users, who log in using a phone number, it is possible to get this credential during the login process. Check https://firebase.google.com/docs/auth/web/phone-auth.
So, I decided to save the credential for the user on their device during the login process. I am using Redux and Redux-Persist for that.
My code after fixing it.
// This is an extract from the login script:
firebase.auth().signInWithPhoneNumber(phoneNo)
.then(confirmResult => {
dispatch({ type: "PhoneNo_accepted", payload: { confirmResult: confirmResult } });
})
.catch(error => {
dispatch({ type: "display_message", payload: { messageText: `Phone Number Error: ${error.message}` } });
});
// Change#1. The following statement is a NEW step, which I added to get the credential during the login process.
const credential = firebase.auth.PhoneAuthProvider.credential(state.confirmResult.verificationId, state.codeInput);
state.confirmResult.confirm(state.codeInput)
.then( (user) => {
// Change#2. The following function would save the credential to the app's state, e.g. using Redux
_onAuthComplete(user, credential);
})
.catch( error => {
dispatch({ type: "display_message", payload: { messageText: `Verification Code Error: ${error.message}` } });
});
// // //
// This is an extract from the linking script:
// Change#3. props.credential is the credential, which was saved to the app's state.
await firebase.auth().currentUser.reauthenticateWithCredential(props.credential);
const emailCredential = firebase.auth.EmailAuthProvider.credential(state.email, state.password);
const newCredential = await firebase.auth().currentUser.linkWithCredential(emailCredential);
This is my first time trying to create a slack bot and I am following this template code to the word, I have not made any changes, and just remixed on glitch, copy-pasted the auth tokens correctly, things worked just fine.
That is until I made the #general channel restricted for Full Member users.
This is the error I see in the logs at glitch.
PostMessage Error: restricted_action
Is there an additional scope that I need to set, other than bot ?
Here is the workspace user permissions, I am the owner for this workspace.
Here is the code:
const postAnnouncementToChannel = (user, announcement) => {
const { title, details, channel } = announcement;
let announcementData = {
token: process.env.SLACK_ACCESS_TOKEN,
channel: channel,
text: `:loudspeaker: Announcement from: <#${user}>`,
attachments: JSON.stringify([
{
title: title,
text: details,
footer: 'DM me to make announcements.'
}
])
};
send(announcementData, user);
}
const send = async(data) => {
data.as_user = true; // send DM as a bot, not Slackbot
const result = await axios.post(`${apiUrl}/chat.postMessage`, qs.stringify(data))
try {
if(result.data.error) console.log(`PostMessage Error: ${result.data.error}`);
} catch(err) {
console.log(err);
}
}
Testing it via
https://api.slack.com/methods/chat.postMessage/test
using bot-token says
{
"ok": false,
"error": "restricted_action"
}
Testing this using xoxp-token gives this:-
{
"ok": false,
"error": "missing_scope",
"needed": "chat:write:user",
"provided": "identify,bot"
}
No. You are not missing any scopes. Its just that the user you used to auth your app can not post into the general channel. Apparently admins have restricted who can post messages in that channel, e.g. to admins only.
Either use a user that has posting rights for that channel to auth your app or switch to a different channel for your testing.
Bots are not full members so I had to use user token
xoxp-token
to post to chat.postmessage, with
as_user:false
and had to add a missing_scope that is
chat:write:user
And then I was able to make this work correctly.
Credit goes to #girliemac for helping out on this one.
https://github.com/slackapi/template-announcement-approvals/issues/6
Thanks
I am trying to issue a new identity to a participant, create a composer card and import it.
My base.cto file is
namespace com.algorythmix.base
participant Department identified by departmentId {
o String departmentId
}
My function to issue an identity
const initIdentities = () => {
return new Promise(async function(resolve, reject) {
try {
const businessNetworkConnection = new BusinessNetworkConnection();
await businessNetworkConnection.connect(adminCardName);
let departmentRegistry = await businessNetworkConnection.getParticipantRegistry(`${BASE_NS}.Department`);
let departmentOne = await departmentRegistry.get('departmentOne');
let deptOne = await businessNetworkConnection.issueIdentity(`${BASE_NS}.Department#${departmentOne.departmentId}`, 'departmentOne');
console.log(`userID = ${deptOne.userID}`);
console.log(`userSecret = ${deptOne.userSecret}`);
let departmentTwo = await departmentRegistry.get('departmentTwo');
let deptTwo = await businessNetworkConnection.issueIdentity(`${BASE_NS}.Department#${departmentTwo.departmentId}`, 'departmentTwo');
console.log(`userID = ${deptTwo.userID}`);
console.log(`userSecret = ${deptTwo.userSecret}`);
const adminConnection = new AdminConnection(); // { cardStore: $SOME_PATH_VARIABLE } to change def2ault card storage path
await adminConnection.connect(adminCardName); // Confirm this
console.log('connected');
const cardOne = new IdCard({
userName: 'departmentOne',
version: 1,
enrollmentSecret: deptOne.userSecret,
businessNetwork: 'chips'
}, connectionProfile);
const cardTwo = new IdCard({
userName: 'departmentTwo',
version: 1,
enrollmentSecret: deptTwo.userSecret,
businessNetwork: 'chips'
}, connectionProfile);
console.log('importing card one');
await adminConnection.importCard('departmentOne', cardOne);
await adminConnection.importCard('departmentTwo', cardTwo);
console.log('imported card two');
await businessNetworkConnection.disconnect();
await adminConnection.disconnect();
resolve();
} catch (e) {
reject(e);
};
});
};
Where adminCardName is the one generated when using composer network start command as per the basic tutorial provided here https://hyperledger.github.io/composer/latest/tutorials/deploy-to-fabric-single-org
And connectionProfile is taken from the above page as well. I have double checked the connection profile used by the admin#chips card and the one I have used is exactly the same.
Once I run the function, in composer card list, a card called departmentOne and departmentTwo is listed with the Business network shown as chips (as expected).
Now when I run composer network ping -c departmentOne, I get the error
Error: 2 UNKNOWN: error executing chaincode: transaction returned with failure: AccessException: Participant 'com.algorythmix.base.Department#departmentOne' does not have 'READ' access to resource 'org.hyperledger.composer.system.Network#chips#0.2.0'
Command failed
I have
1) Deleted permissions.acl which as per the documentation results in everyone getting full access
2) used following permissions.acl file
rule Default {
description: "Allow all participants access to all resources"
participant: "com.algorythmix.base.Department"
operation: ALL
resource: "org.hyperledger.composer.system.Network"
action: ALLOW
}
rule NetworkAdminUser {
description: "Grant business network administrators full access to user resources"
participant: "org.hyperledger.composer.system.NetworkAdmin"
operation: ALL
resource: "**"
action: ALLOW
}
rule NetworkAdminSystem {
description: "Grant business network administrators full access to system resources"
participant: "org.hyperledger.composer.system.NetworkAdmin"
operation: ALL
resource: "org.hyperledger.composer.system.**"
action: ALLOW
}
To specifically give the participant access to the network. I have also uploaded the .bna to composer-playground and it works over there as expected.
Can someone please guide me, as to what I am doing wrong?
Info:
Ubuntu - 16.0.4
Fabric - 1.1
Composer - 0.19.11
Node - 8.9.1
the error 'org.hyperledger.composer.system.Network#chips#0.2.0' suggests the underlying participant does not have the minimal READ access to the actual business network.
I would suggest a rule (rule 2) something like this:
rule ReadNetwork {
description: "Allow all participants to read network"
participant: "org.hyperledger.composer.system.Participant"
operation: READ
resource: "org.hyperledger.composer.system.Network"
action: ALLOW
}
I solved the same issue by changing the version in package.json file.
I am trying to use BusinessNetworkConnection for NodeJS, but how do I get the credentials from a deployed BNA on playground and save it in my server directory?
I am getting
2017-11-03T13:07:32.83-0400 [APP/PROC/WEB/0] ERR (node:62)
UnhandledPromiseRejectionWarning: Unhandled promise rejection
(rejection id: 1): Error: Error trying login and get user Context.
Error: Error trying to enroll user or load channel configuration.
Error: Enrollment failed with errors
[[{"code":400,"message":"Authorization failure"}]]
when I try using the code
const BusinessNetworkConnection = require("composer-client").BusinessNetworkConnection;
this.businessNetworkConnection = new BusinessNetworkConnection();
this.CONNECTION_PROFILE_NAME = "ibm-bc-org1";
this.businessNetworkIdentifier = "giveback";
this.businessNetworkConnection
.connect(
this.CONNECTION_PROFILE_NAME,
this.businessNetworkIdentifier,
"admin",
"adminpw"
)
.then(result => {
this.businessNetworkDefinition = result;
console.log("BusinessNetworkConnection: ", result);
})
I have a directory /home/vcap/app/.composer-connection-profiles/ibm-bc-org1 with a connection.json file that references /home/vcap/app/.composer-credentials/ibm-bc-org1 for my credentials. The code worked for composer#0.13.2 but now I moved over to composer#0.14.3. I removed the previous credentials and created a new playground etc, everything is fresh and clean.
There is a work around when something like this happens. Because I am trying to connect with the credentials that Composer created the with admin || adminpw. You can just define a new participant in your model file and then give that participant system permissions to query and listen for events that the Historian emits.
For example in your model.cto:
participant ServerAdmin identified by serverhash {
// ServerAdmin is a type of participant
o String serverhash
}
And in your permissions.acl add :
rule ServerAdminUser {
description: "Grant business network administrators full access to
user resources"
participant: "org.acme.sample.ServerAdmin"
operation: ALL
resource: "**"
action: ALLOW
}
rule ServerAdminSystem {
description: "Grant business network administrators full access to system resources"
participant: "org.acme.sample.ServerAdmin"
operation: ALL
resource: "org.hyperledger.composer.system.**"
action: ALLOW
}
Then after the network has been deployed by Composer on playground, you can add this participant VIA the REST API, and issue it a new identity. This will give you a User ID and User Secret with which you can use in BusinessNetworkConnection.connect()