Possible to create token and metadata in one transaction? - metaplex

Am I correct in saying that it's not possible to mint(create) an spl token and token metadata in the one transaction ?
Here is me cerating the mpl token metadata for a previously cerated spl token:
const createMetadataTx = new CreateMetadataV2(
{ feePayer: this.appTreasPair.publicKey },
{
metadata,
metadataData: new DataV2({
uri: `${host}/token_type/${token_type.token_type_id}/metadata`,
name: token_type.name,
symbol: token_type.symbol,
sellerFeeBasisPoints: 100,
creators: null,
collection: null,
uses: null,
tokenStandard: TokenStandard.FungibleAsset,
}),
updateAuthority: this.appTreasPair.publicKey,
mint: new web3.PublicKey(token_type.token_address),
mintAuthority: this.appTreasPair.publicKey,
}
);
const connection = solanaUtils.getConnection(token_type.cluster);
const transaction = new web3.Transaction();
console.log("creating metadata")
transaction.add(createMetadataTx)
const sig = await web3.sendAndConfirmTransaction(connection, transaction, [this.appTreasPair], {
skipPreflight: skipPreflight
})
the mint field needs the address of the spl token which I can only get if I do the spl token creation in an initial separate transaction

It is possible. E.g. candy machine is creating a SPL token and then assign metadata to it.
If you want a NFT: https://solanacookbook.com/references/nfts.html#mint-the-nft
If you rather want a standard SPL token the current method is create the SPL Token and then add it to the Solana Token list https://github.com/solana-labs/token-list (a better solution is WIP)

Related

unable to use validate jwt in APIM for managed Identity token

We have a validate jwt policy in APIM to validate jwt token. we are generating token from our function app using the azure.identity library. till now we were using system assigned identity for generating the token using the below method.
var tokenCredential = new DefaultAzureCredential();
var accessToken = await tokenCredential.GetTokenAsync(
new TokenRequestContext(scopes: new string[] { "https://management.azure.com" + "/.default" }) { });
token is generated successfully. and we are able to successfully validate the token in the policy. below is the APIM xml policy.
<validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Invalid or Expired token" require-expiration-time="true" require-signed-tokens="true">
<openid-config url="https://login.microsoftonline.com/tenantid/v2.0/.well-known/openid-configuration" />
<audiences>
<audience>https://management.azure.com</audience>
</audiences>
<issuers>
<issuer>https://sts.windows.net/tenantid/</issuer>
</issuers>
<required-claims>
<claim name="oid" match="any">
<value>objectid of the managed identity/system assigned</value>
</claim>
</required-claims>
</validate-jwt>
now we have assigned the user managed identity and assigned the identity to the function app with the below code I am able to generate the token but in APIM it was throwing weird error.
var azureServiceTokenProvider = new ManagedIdentityCredential(clientId: "client-id-of-managed-identity-id");
accessToken = await azureServiceTokenProvider.GetTokenAsync(new Azure.Core.TokenRequestContext(new[] { "https://management.azure.com" + "/.default" }));
APIM is telling
"JWT Validation Failed: IDX10501: Signature validation failed. Unable to match key: \nkid: ''.\nExceptions caught:\n ''.
any idea on how to overcome this ?
I have updated my code to use DefaultAzureCredential instead of ManagedIdentityCredential and it started working.
var credential = new DefaultAzureCredential(new DefaultAzureCredentialOptions
{ ManagedIdentityClientId = "managed_identity_clinet_id" });
AccessToken accessToken = await credential.GetTokenAsync(
new TokenRequestContext(scopes: new string[] { "https://management.azure.com" + "/.default" }) { });
I passed the client ID of the managed Identity and able to proceed with the generated token.

jwt acess_token and refresh_token mechanism: axios : How to keep checking for the access_token is working

I am using JWT token based authentication system. i.e djangorestframework-simplejwt in my backend
Now I am using reactj and axios as frontend:
After providing username and pass to the login api, I got access_token and refresh_token which I stored in the localstorage
Now I am trying to connect to an api using access_token.
I get Token invalid or expired
Example I am trying to change password using this api and provide access_token
const url = "dj-rest-auth/password/change/";
const auth = {
headers: {
Authorization: "Bearer " + localStorage.getItem("access_token"),
Accept: "application/json",
"Content-Type": "application/json",
},
};
const data = {
old_password: old_password,
new_password1: new_password1,
new_password2: new_password2,
};
const promise = axios.post(url, data, auth);
promise
.then((res) => {
console.log(res)
})
.catch((err) => {
if (err.response) {
console.log(`${err.response.status} :: ${err.response.statusText}`)
console.log(err.response.data)
}
})
I can do another api call using refresh_token to get access_token when i get an err.
But sometimes, the err can be due to network error or something else. Then even i try to get access_token using refresh_token, it will just get into a loop.
HOw to do this the right way
If you are using Django as the backend, I would suggest using dj-rest-auth for JWT token authentication. dj-rest-auth requires "djangorestframework-simplejwt" for token management.
It is recommended to store access token and refresh token in httponly cookie so that it is not accessed by javascript.
Add JWTtokenAuthentication as authentication classes in settings.py.
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'dj_rest_auth.jwt_auth.JWTCookieAuthentication'
]
}
Add the below configuration too in settings.py
REST_SESSION_LOGIN = False
SITE_ID=1
REST_USE_JWT = True
JWT_AUTH_COOKIE = 'access-token' #any name
JWT_AUTH_REFRESH_COOKIE = 'refresh_token' #any name
JWT_AUTH_SECURE = True
CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_ALLOW_ALL = True
There is an open issue with dj-rest-auth, that requires the below code to be implemented in your back-end Github issue: https://github.com/iMerica/dj-rest-auth/issues/97. As workaround suggested, you have to create a file middleware.py and paste below code.
import json
from django.utils.deprecation import MiddlewareMixin
from yourapp.settings import JWT_AUTH_REFRESH_COOKIE # from settings.py
class MoveJWTRefreshCookieIntoTheBody(MiddlewareMixin):
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
response = self.get_response(request)
return response
def process_view(self, request, view_func, *view_args, **view_kwargs):
if request.path == '/token/refresh/' and JWT_AUTH_REFRESH_COOKIE in request.COOKIES:
if request.body != b'':
data = json.loads(request.body)
data['refresh'] = request.COOKIES[JWT_AUTH_REFRESH_COOKIE]
request._body = json.dumps(data).encode('utf-8')
else:
print("The incoming request body must be set to an empty object.")
return None
By now, your back-end will be successfully generating access token and refresh token. Even your back-end will be capable of refreshing access token using refresh token.
Front-End:
By default, access token and refresh tokens are stored in httponly cookie, so you don't need to worry about that part.
Axios can be used to make call to login-end point to get tokens. Make sure you use "withCredentials" and "Headers" in your request.
Response will be tokens, by default it will be stored in httponly cookie, since we are using dj-rest-auth. For all the consecutive requests, httponly cookie will be included, if tokens are valid, user will be provided access. IF token is expired, you need to make call to refresh endpoint to get new access token.
Since you are in development mode, you have to have same domain for both BE and FE, different ports.You can start django-server using below command and make sure your FE is also running in localhost
python manage.py runserver localhost:8080
dj-rest-auth : https://dj-rest-auth.readthedocs.io/en/latest/index.html

How can I register a Client through an express REST API in Hyperledger fabric

I want to register a user of the application through a REST API. I have already enrolled the admin and a user through the enrollAdmin.js and registerUser.js function but I want to call these functions through the node SDK and register users dynamically with there username (UUID) so that it's completly anonymous.
As the username I want to create a unique UUID and save that in the world state but also save that UUID on an off-chain database together with the personal information like password and name so that I can associate the personal information with the UUID.
Right know I'm confused by all the different steps I have to do to register a new user:
In what order do I have to enroll and register the user and should they all be defined in the express API or in chaincode?
This is my first approach of creating the REST Api and till now I have only defined the layout, the connection profile and wallet.
I would appreciate if somebody could help me implement the registration process in the express REST API so that an Identity for the UUID gets saved in the world state.
Thanks in advance.
server.js
'use strict';
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
// Setting for Hyperledger Fabric
const { Wallets, FileSystemWallet, Gateway } = require('fabric-network');
const path = require('path');
const fs = require('fs');
const channelName = 'mychannel';
const mspOrg1 = 'Org1MSP';
const walletPath = path.join(__dirname, '..', 'wallet');
const ccpPath = path.resolve(__dirname, '..', 'connection-org1.json');
//register
app.post('/api/register', async function (req, res) {
try{
// Create a new file system based wallet for managing identities.
const walletPath = path.join(process.cwd(), 'wallet');
const wallet = new FileSystemWallet(walletPath);
console.log(`Wallet path: ${walletPath}`);
} catch (error) {
}
});
//login
app.post('/api/login', async function (req, res) {
try{
// Create a new file system based wallet for managing identities.
const walletPath = path.join(process.cwd(), 'wallet');
const wallet = new FileSystemWallet(walletPath);
console.log(`Wallet path: ${walletPath}`);
} catch (error) {
}
});
app.listen(3000, ()=>{
console.log("***********************************");
console.log("API server listening at localhost:3000");
console.log("***********************************");
});
The process of how you want it to be is simple. In the middle, the off-chain database is used as a mapping table. I wrote only the core process logic.
/api/v1/register
validation check
Validate that the user's id is unique, that the required information value is missing, that the regular expression is correct, and that there is no wrong information.
generate random UUID
Create a random, unique uuid first. npm/uuid
const UUID = uuid.v4();
register/enroll user to fabric-ca
Perform the registration process as a user of the fabric. The information that goes into this process is UUID, and the user's information will not be stored in the blockchain.
fabricUser is a newly created class, and returns the result after fabric user registration and enroll process are performed by the Enroll method.
enrollment = await fabricUser.Enroll(UUID);
await wallet.put(enrollment);
insert to database
While saving the user information in the database, map it by storing the UUID created above.
The database was created as an example, assuming mongodb.
db.collection('User').insertOne({
'uuid': UUID,
'user_id': <input_user_id>,
...
});
/api/v1/login
The login process is as follows.
I don't know what authentication/authentication method you want to use, so I'll assume a token authentication method based on auth 2.0.
Verify the validity of the necessary information required for login and whether there is any incorrect information.
get UUID
generateAuthToken is a new function that generates JWT.
let res = await db.collection("User").findOne({'user_id': `<input_user_id>` });
return generateAuthToken(res.uuid);
/api/v1/invoke
Fabric resource request process is as follows.
Token validation and resource authorization check
get userName from token
getPayload is a function that gets the payload value located at the 1st index from the token.
const rawPayload = getPayload(token);
const jsonPayload = JSON.parse(rawPayload);
return jsonPayload
get wallet & invoke chaincode
The fabricChaincode is a function that wraps the invoke process of fabric-sdk. It is a function that executes invoke by inputting identity, chaincode information, and parameters, and returns a result.
const user = await db.collection("User").findOne({'user_id': jsonPayload.user_id });
const fabricIdentity = await wallet.get(user.uuid);
const res = fabricChaincode.invoke(fabricIdentity, `<your_chaincode_info>`, `<input_chaincode_params>`)
return res;
[EDIT]
Add it for your understanding.
fabricUser.js
/*
* Copyright IBM Corp. All Rights Reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
'use strict';
const { Wallets } = require('fabric-network');
const FabricCAServices = require('fabric-ca-client');
const fs = require('fs');
const path = require('path');
async function Enroll(user_id) {
try {
// load the network configuration
const ccpPath = path.resolve(__dirname, '..', '..', 'test-network', 'organizations', 'peerOrganizations', 'org1.example.com', 'connection-org1.json');
const ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8'));
// Create a new CA client for interacting with the CA.
const caURL = ccp.certificateAuthorities['ca.org1.example.com'].url;
const ca = new FabricCAServices(caURL);
// Create a new file system based wallet for managing identities.
const walletPath = path.join(process.cwd(), 'wallet');
const wallet = await Wallets.newFileSystemWallet(walletPath);
console.log(`Wallet path: ${walletPath}`);
// Check to see if we've already enrolled the user.
const userIdentity = await wallet.get(user_id);
if (userIdentity) {
console.log(`An identity for the user ${user_id} already exists in the wallet`);
return;
}
// Check to see if we've already enrolled the admin user.
const adminIdentity = await wallet.get('admin');
if (!adminIdentity) {
console.log('An identity for the admin user "admin" does not exist in the wallet');
console.log('Run the enrollAdmin.js application before retrying');
return;
}
// build a user object for authenticating with the CA
const provider = wallet.getProviderRegistry().getProvider(adminIdentity.type);
const adminUser = await provider.getUserContext(adminIdentity, 'admin');
// Register the user, enroll the user, and import the new identity into the wallet.
const secret = await ca.register({
affiliation: 'org1.department1',
enrollmentID: user_id,
role: 'client'
}, adminUser);
const enrollment = await ca.enroll({
enrollmentID: user_id,
enrollmentSecret: secret
});
const x509Identity = {
credentials: {
certificate: enrollment.certificate,
privateKey: enrollment.key.toBytes(),
},
mspId: 'Org1MSP',
type: 'X.509',
};
await wallet.put(user_id, x509Identity);
console.log(`Successfully registered and enrolled admin user ${user_id} and imported it into the wallet`);
} catch (error) {
console.error(`Failed to register user ${user_id}: ${error}`);
process.exit(1);
}
}
module.exports = {
Enroll
}
api.js
const uuid = require('uuid');
const fabricUser = require('./fabricUser);
const UUID = uuid.v4();
let res = await fabricUser.Enroll(UUID);
console.log(res);

Using Axios as an Alternative to request in nodejs

I am building a flutter application that requires oauth 1 authorization for one of the third party services I am using. Because flutter oauth 1 package is restricted I decided to use the oauth 1 package that npm provides. This is the code that is used to access the user generated access token from the site.
I previously used request to make a call to the api endpoint first, to access the token and secondly to use the token recieved to make another call to a different resource endpoint
How can I use axios to make the same request, emphasis on the fact that each request needs a hmac-sha1 signed signature in the header.
Thank you.
consumer: {
key: CONSUMER KEY,
secret: CONSUMER SECRET,
},
signature_method: 'HMAC-SHA1',
hash_function(base_string, key) {
return crypto
.createHmac('sha1', key)
.update(base_string)
.digest('base64')
},
})
const request_data = {
url: 'https://www.instapaper.com/api/1/oauth/access_token/',
method: 'POST',
data: { x_auth_username : USERNAME , x_auth_password : PASSWORD , x_auth_mode : 'client_auth' },
}
request(
{
url: request_data.url,
form: request_data.data,
method: request_data.method,
headers: oauth.toHeader(oauth.authorize(request_data)),
},
function(error, response, body) {
// Process your data here
console.log(error);
console.log(response);
console.log(body);
}
)
Finally found the answer for this link to the issue created on github
https://github.com/axios/axios/issues/2771

403 on Google Action push notification request

I'm trying to perform a push notification for Google Actions Intent.
Thus far, I've followed the instructions here: https://developers.google.com/actions/assistant/updates/notifications#send_notifications
This is my resulting code:
const {google} = require('googleapis');
var request = require('request');
const key = require('./bot.json');
module.exports = async function (context, myQueueItem) {
context.log('JavaScript queue trigger function processed work item', myQueueItem);
let jwtClient = new google.auth.JWT(
key.client_email, null, key.private_key,
['https://www.googleapis.com/auth/actions.fulfillment.conversation'],
null
);
jwtClient.authorize((err, tokens) => {
// code to retrieve target userId and intent
let notif = {
userNotification: {
title: [message],
},
target: {
userId:[obtained from permission request],
intent: [name of intent],
// Expects a IETF BCP-47 language code (i.e. en-US)
locale: 'en-US'
},
};
request.post('https://actions.googleapis.com/v2/conversations:send', {
'auth': {
'bearer': tokens.access_token,
},
'json': true,
'body': {'customPushMessage': notif},
}, (err, httpResponse, body) => {
console.log(body);
console.log(httpResponse.statusCode + ': ' + httpResponse.statusMessage);
});
});
};
//module.exports(console, "Test");
This results in a 403 from the notification service. Is this because of the user id, intent name or jwtoken that was generated?
Following are the steps we need to check before sending the push notification
Check your Google permission settings
In order to test the Action, you need to enable the necessary permissions.
Go to the ‘Activity Controls' page (https://myaccount.google.com/activitycontrols).
Sign in with your Google account, if you have not already done so.
Ensure that the following permissions are enabled:
a.Web & App Activity
b.Device Information
c.Voice & Audio Activity
2.Target intent name should be added into the Implicit invocation field.
with enabled push notification.
3.use the same email id in your google assistant which you had used for login in GCP.