Why do sender and minter should be same on minting NFT? - rust

I am developing NFT marketplace with terra and I use CW721.
And I noticed on mint function if the sender and minter is not equal it returns "Unauthorized" error.
I can ignore this condition but is this required?
pub fn mint(
&self,
deps: DepsMut,
_env: Env,
info: MessageInfo,
msg: MintMsg<T>,
) -> Result<Response<C>, ContractError> {
let minter = self.minter.load(deps.storage)?;
if info.sender != minter {
return Err(ContractError::Unauthorized {});
}
...
}
In Javascript with Terra.js I sent request with my wallet address.
But if the sender and minter must be same, I have to send request with minter's wallet address.
And that means NFT creator should know the password of minter's wallet.
What's the difference between token_uri and image url?
I think they are same.

Related

Authenticating to MS Graph without user interaction (Rust)

I have a Java application using the Microsoft Graph SDK to read from Azure AD. I am supposed to translate that application to Rust. In Java, i use code similar to this:
import com.azure.identity.ClientSecretCredentialBuilder;
import com.azure.identity.TokenCachePersistenceOptions;
import com.microsoft.graph.authentication.TokenCredentialAuthProvider;
import com.microsoft.graph.requests.GraphServiceClient;
import java.util.List;
public class GraphSdkClient {
public static void testApplicationClient() {
TokenCachePersistenceOptions options = new TokenCachePersistenceOptions()
.setName("ILM-Demo")
.setUnencryptedStorageAllowed(false);
ClientSecretCredentialBuilder builder = new ClientSecretCredentialBuilder()
.clientId("<MyClientId>")
.tenantId("<MyTenantId>")
.clientSecret("<MyClientSecret>")
.tokenCachePersistenceOptions(options);
TokenCredentialAuthProvider provider = new TokenCredentialAuthProvider(
List.of("Calendars.Read", "Calendars.ReadBasic.All"),
builder.build()
);
GraphServiceClient<?> client = GraphServiceClient
.builder()
.authenticationProvider(provider)
.buildClient();
client.me().calendar().calendarView().buildRequest().get();
}
}
It authenticates as an application, using only the client secret. The permission was given half a year ago and as long as the three values from the ClientSecretCredentialBuilder are correct, it works perfectly fine. Now i tried using a similar conecpt in Rust, taken from the graph-rs-sdk crate:
#[cfg(test)]
mod test {
use graph_rs_sdk::oauth::OAuth;
use warp::Filter;
use crate::{CLIENT_ID, CLIENT_SECRET, TENANT_ID};
use serde::{Deserialize, Serialize};
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct ClientCredentialsResponse {
admin_consent: bool,
tenant: String,
}
#[tokio::test]
async fn ut_client_credentials() {
let query = warp::query::<ClientCredentialsResponse>()
.map(Some)
.or_else(|_| async {
Ok::<(Option<ClientCredentialsResponse>,), std::convert::Infallible>((None,))
});
let routes = warp::get()
.and(warp::path("redirect"))
.and(query)
.and_then(handle_redirect);
// Get the oauth client and request a browser sign in
let mut oauth = get_oauth_client();
let mut request = oauth.build_async().client_credentials();
request.browser_authorization().open().unwrap();
warp::serve(routes).run(([127, 0, 0, 1], 8300)).await;
}
async fn handle_redirect(client_credential_option: Option<ClientCredentialsResponse>)
-> Result<Box<dyn warp::Reply>, warp::Rejection> {
match client_credential_option {
Some(client_credential_response) => {
// Print out for debugging purposes.
println!("{:#?}", client_credential_response);
// Request an access token.
request_access_token().await;
// Generic login page response.
Ok(Box::new(
"Successfully Logged In! You can close your browser.",
))
}
None => Err(warp::reject()),
}
}
async fn request_access_token() {
let mut oauth = get_oauth_client();
let mut request = oauth.build_async().client_credentials();
let access_token = request.access_token().send().await.unwrap();
println!("{:#?}", access_token);
oauth.access_token(access_token);
}
fn get_oauth_client() -> OAuth {
let mut oauth = OAuth::new();
oauth
.client_id(CLIENT_ID)
.client_secret(CLIENT_SECRET)
.tenant_id(TENANT_ID)
.add_scope("https://graph.microsoft.com/User.Invite.All")
.redirect_uri("http://localhost:8300/redirect")
// .authorize_url("https://login.microsoftonline.com/common/adminconsent")
.access_token_url("https://login.microsoftonline.com/common/oauth2/v2.0/token");
oauth
}
}
Note that i commented out the authorize url. If this url exits, a browser window opens, requesting an admin to log in. This must not happen. When it is commented out, it sends the request directly to <tenantId>/oauth2/v2.0/authorize instead of <tenantId>/oauth2/v2.0/adminconsent, which is what i want, it instead complains: AADSTS900144: The request body must contain the following parameter: 'scope'.. The scope is given though.
I already tried fiddling with urls for hours and also tried every other authentication concept in the crate, but it doesn't seem to work without interaction, which is not possible in my use case. Does someone know how to achieve that? (All permissions are granted as application permissions, not deligated)
Edit request: Please create and add the tag "graph-rs-sdk". I cannot create it myself but knowing the crate being used would be useful.

Deep email validator only validates #gmail addresses?

Today I am facing the issue of deep-email-validator in node.js.
I want to validate e-mail-adresses with #gmail, #icloud, etc.. but if I enter a #iCloud address it shows that the email adress isn't valid although it is valid. What is the problem here?
My code (index.js):
async function isEmailValid(email) {
return validate(email)
}
const {valid} = await isEmailValid(req.body.eMail_adress);
if (valid == true){
console.log("Email is valid");
}

How to reply with an image with discord bot

I'm new to rust and as a practice project I'm building a bot using Serenity to handle the interactions with Discord. The bot should be able to reply to a message with an image. I can get the bot to post the image on the channel using CreateMessage like this:
let f = [(&tokio::fs::File::open("image.png").await?, "image.png")];
return match msg.channel_id.send_message(&context.http, |m| {
m.content(replied_message.author);
m.files(f);
return m;
}).await {
Ok(_) => Ok(()),
Err(why) => Err(CommandError::from(why)),
};
Unfortunately this method doesn't work with reply, which wants a content that implements std::fmt::Display. I could use MessageBuilder, but it constructs a string and I don't know how to add the image to that, unless I add an URL. The image is an image::DynamicImage instance and serving it from another service is unpractical to say the least.
How can I use message.reply_ping(&context.http, &reply) to send an image?
You can use the send_message() approach like in your existing code, with some small additions.
CreateMessage has a reference_message() method you can use to set the message to reply to. And it has the allowed_mentions() method to configure pings:
match msg
.channel_id
.send_message(&context.http, |m| {
// Reply to the given message
m.reference_message(&replied_message);
// Ping the replied user
m.allowed_mentions(|am| {
am.replied_user(true);
am
});
// Attach image
m.files(f);
m
})
.await
{
// ...
}

Slack bot fails to send message to restricted general channel via chat.postMessage

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

Access Facebook Messenger User Profile API in DialogFlow

I'm building a cross-platform chatbot in Google's DialogFlow. I'd like to access the Facebook User Profile API to learn the user's first name.
I'm struggling to find advice on how (or if) I can make this happen.
https://developers.facebook.com/docs/messenger-platform/identity/user-profile/
Has anybody here achieved this?
I did that for one of my bots yesterday, you need 2 things, first the Page Token and second is the psid which is Page scope user ID.
On dialogflow, you will receive the request block with psid as sender id. You can find it at:
agent.originalRequest.payload.data.sender.id
This psid needs to be passed to api get request at
/$psid?fields=first_name with your page Token as accessToken to get the first name in response.
You need to make a call to Facebook Graph API in order to get user's profile.
Facebook offers some SDKs for this, but their official JavaScript SDK is more intended to be on a web client, not on a server. They mention some 3rd party Node.js libraries on that link. I'm particularly using fbgraph (at the time of writing, it's the only one that seems to be "kind of" maintained).
So, you need a Page Token to make the calls. While developing, you can get one from here:
https://developers.facebook.com/apps/<your app id>/messenger/settings/
Here's some example code:
const { promisify } = require('util');
let graph = require('fbgraph'); // facebook graph library
const fbGraph = {
get: promisify(graph.get)
}
graph.setAccessToken(FACEBOOK_PAGE_TOKEN); // <--- your facebook page token
graph.setVersion("3.2");
// gets profile from facebook
// user must have initiated contact for sender id to be available
// returns: facebook profile object, if any
async function getFacebookProfile(agent) {
let ctx = agent.context.get('generic');
let fbSenderID = ctx ? ctx.parameters.facebook_sender_id : undefined;
let payload;
console.log('FACEBOOK SENDER ID: ' + fbSenderID);
if ( fbSenderID ) {
try { payload = await fbGraph.get(fbSenderID) }
catch (err) { console.warn( err ) }
}
return payload;
}
Notice you don't always have access to the sender id, and in case you do, you don't always have access to the profile. For some fields like email, you need to request special permissions. Regular fields like name and profile picture are usually available if the user is the one who initiates the conversation. More info here.
Hope it helps.
Edit
Promise instead of async:
function getFacebookProfile(agent) {
return new Promise( (resolve, reject) => {
let ctx = agent.context.get('generic');
let fbSenderID = ctx ? ctx.parameters.facebook_sender_id : undefined;
console.log('FACEBOOK SENDER ID: ' + fbSenderID);
fbGraph.get( fbSenderID )
.then( payload => {
console.log('all fine: ' + payload);
resolve( payload );
})
.catch( err => {
console.warn( err );
reject( err );
});
});
}

Resources