Request for api not working properly - javascript

I'm making a request but it doesn't seem to work. If I copy code into my browser it works good, but in my console it shows up this :
{
"status" : "success",
"data" : {
"error_message" : "API access enabled, but unable to verify two-factor authentication code. If you need help with this, please contact support#bitskins.com."
}
}
What am I doing wrong? It's based on two-factor authentication that as I said works good while printing the url itself and when i'm copying it into my browser.
var url = 'https://bitskins.com/api/v1/get_item_price/?api_key='+bitskins.apikey+'&code='+bitskins.code+'&names='+encodeURIComponent(items[i].market_hash_name)+'&delimiter=!END!';
console.log(url);
request(url, function (error, response, body) {
if (!error) {
console.log(body)
}
});
In case you want, here is my api key module to generating it (api key deleted for security)
var TOTP = require('onceler').TOTP;
//Create a TOTP object with your secret
var totp = new TOTP('deleted');
// print out a code that's valid right now
// console.log(totp.now());
var code = totp.now();
module.exports = {
code: code,
apikey: 'deleted'
}

Founder of BitSkins, Inc. here. You need to have the following:
1) Your API Key
2) Your Secure Access Secret
You see the Secret when you enable Secure Access. If you do not have this, just disable/re-enable Secure Access and note the Secret down. The TOTP code you generate is with that Secret. Generate the TOTP code right before every API call and you'll be fine.

I think it should work. For me it works fine.
var API_KEY = ''; //It is very important
var SECRET_KEY = ''; //It is very important
var totp = new TOTP(SECRET_KEY);
var code = totp.now();
var options = {
url: 'https://bitskins.com/api/v1/get_item_price',
form: {
'api_key': API_KEY,
'names': 'Tec-9%20%7C%20Sandstorm%20(Minimal%20Wear)',
'delimiter': '!END!',
'code': code
}
};
function callback(error, response, body) {
if (!error) {
var info = JSON.parse(body);
console.log(info);
}
}
request.post(options, callback);

What npm package do you use to create 2FA code? I'm using "onceler" from example but I think it creates wrond codes. Here is my code:
var API_KEY = ''; //correct key from settings page
var SECRET_KEY = ''; // correct key which I copied from form with QR code.
var totp = new TOTP("SECRET_KEY");
var code = totp.now();
This code doesn't equal code which I can see in my mobile device and with this code I get error message like in author's question. But if I put code from my mobile in programm code - it works fine. So what package should I use to get correct codes?

Related

Azure blob storage sas token generation using js

I have this function running in an azure function to get a sas token for a browser application to upload to azure blob storage:
var azure = require('azure-storage');
module.exports = function(context, req) {
if (req.body.container) {
// The following values can be used for permissions:
// "a" (Add), "r" (Read), "w" (Write), "d" (Delete), "l" (List)
// Concatenate multiple permissions, such as "rwa" = Read, Write, Add
context.res = generateSasToken(
context,
req.body.container,
req.body.blobName,
req.body.permissions
);
} else {
context.res = {
status: 400,
body: "Specify a value for 'container'"
};
}
context.done(null, context);
};
function generateSasToken(context, container, blobName, permissions) {
var connString = process.env.AzureWebJobsStorage;
var blobService = azure.createBlobService(connString);
// Create a SAS token that expires in an hour
// Set start time to five minutes ago to avoid clock skew.
var startDate = new Date();
startDate.setMinutes(startDate.getMinutes() - 5);
var expiryDate = new Date(startDate);
expiryDate.setMinutes(startDate.getMinutes() + 60);
permissions = azure.BlobUtilities.SharedAccessPermissions.READ +
azure.BlobUtilities.SharedAccessPermissions.WRITE +
azure.BlobUtilities.SharedAccessPermissions.DELETE +
azure.BlobUtilities.SharedAccessPermissions.LIST;
var sharedAccessPolicy = {
AccessPolicy: {
Permissions: permissions,
Start: startDate,
Expiry: expiryDate
}
};
var sasToken = blobService.generateSharedAccessSignature(
container,
blobName,
sharedAccessPolicy
);
context.log(sasToken);
return {
token: sasToken,
uri: blobService.getUrl(container, blobName, sasToken, true)
};
}
I am then calling this url in the client and I try and upload with this code:
const search = new URLSearchParams(`?${token}`);
const sig = encodeURIComponent(search.get('sig'));
const qs = `?sv=${search.get('sv')}&ss=b&srt=sco&sp=rwdlac&se=${search.get('sv')}&st=${search.get(
'st'
)}&spr=https&sig=${sig}`;
return `${url}/${containerName}/${filename}${qs}`;
Which generates a url like this:
https://mystorage.blob.core.windows.net/mycontainer/latest.png?sv=2018-03-28&ss=b&srt=sco&sp=rwdlac&se=2018-03-28&st=2019-01-30T19:11:10Z&spr=https&sig=g0sceq3EkiAQTvyaZ07C+C4SZQz9FaGTV4Zwq4HkAnc=
Which returns this error:
403 (Server failed to authenticate the request. Make sure the value of
Authorization header is formed correctly including the signature.)
If I generate the sas token from the azure portal it works, so the generated url looks like this:
https://mystorage.blob.core.windows.net/mycontainer/latest.png?sv=2018-03-28&ss=b&srt=sco&sp=rwdlac&se=2019-01-31T03:01:43Z&st=2019-01-30T19:01:43Z&spr=https&sig=ayE4gt%2FDfDzjv5DjMaD7AS%2F176Bi4Q6DWJNlnDzl%2FGc%3D
but my url looks like this:
https://mystorage.blob.core.windows.net/mycontainer/latest.png?sv=2018-03-28&ss=b&srt=sco&sp=rwdlac&se=2019-01-31T03:34:21Z&st=2019-01-30T19:34:21Z&spr=https&sig=Dx8Vm4XPnD1rn9uyzIAXZEfcdbWb0HjmOq%2BIq42Q%2FOM%3D
I have no idea what to do to get this working
Your Azure Function code is correct, and
var sasToken = blobService.generateSharedAccessSignature(
container,
blobName,
sharedAccessPolicy
);
is exactly the sasToken you need to upload blob. No need to process the token again(mishandle actually) as you have done in the 2nd code snippet.
It's expected that the sas token from the Azure portal(Account SAS) is different from the one generated in your code(Service SAS). Have a look at the doc.
To conclude,
Make sure the connection string belongs to the Storage you want to connect. You could avoid trouble and directly replace var connString = process.env.AzureWebJobsStorage; with var connString = "connectionStringGotFromPortal";
If 1 is confirmed, your Azure function code is correct and returns token as expected
{
token: sasToken,
uri: blobService.getUrl(container, blobName, sasToken, true)
};
Based on the 2nd code snippet you provide, you only need
return `${url}/${containerName}/${filename}?${token}`;
if the token is identical to what function returns.
The problem is that in your server-side code you're creating a Service SAS and then taking only signature portion of the code (sig) and creating an Account SAS on the client.
Since the parameters used to create token has now changed (in the original one, you didn't have parameters like ss, srt etc. but when you're creating your own URL, you're inserting these parameters), when you use the modified SAS URL you will get 403 error. This is happening because server again computes the signature based on the URL parameters and compare that with the signature passed in the URL. Since the two signatures won't match, you're getting the 403 error.
Since you're returning the SAS URL of the blob, there's no need for you to create the URL on the client. You can simply use the uri you're returning from your API layer on the client and use that to upload.
As Jerry Liu's answer explained your Azure function generates the correct token and already gives you the the correct uri to use which includes your blob name and token.
In your client side you can also use azure-sdk-for-js
// This is the response from your api with token and uri
const uri = response.uri;
const pipeline = StorageURL.newPipeline(new AnonymousCredential());
// Your uri already includes the full blob url with SAS signature
const blockBlobURL = BlockBlobURL.fromBlobURL(new BlobURL(uri, pipeline));
const uploadBlobResponse = await blockBlobURL.upload(
Aborter.none,
file,
file.size,
{ blobHTTPHeaders: { blobContentType: `${mime}; charset=utf-8`} }
);

AWS managing users via Cognito

I have used many services from AWS, some were easy, while some were a bit difficult. After 2 days of searching everywhere, I can say documentation for this service is misleading.
I have simple task to do. I want to change a user attribute in the Cognito pool. And to make things easy, I just need to change an Email, and thats it. Application is an Backoffice (Express/Node), where admins can change user's email.
After reading and reading, I am getting more confused. Apparently, the aws-sdk library, the one I am familiar with, has some Cognito API's that I could use. Getting a working example on how to use them, turned out to be a nightmare.
Then I found out there is a library, but only to be used on the client side. After some tweaks I got it running in Node.js. The tweak was to expose a fetch library in global Node.js namespace.
I was able to add a new user. But for all my intentions, I can't change any of the attributes (like email). The library wants me to provide Username (real user) and a password.
I do have a Username (in this case an email), but I don't have the password.
All I need to do is to connect to the service, and send new attribute for the user and thats it.
This is what I have so far (mainly hacked code samples, from variety of places), and I cant get it to work:
var poolData = {
UserPoolId : 'euXXXXXXX',
ClientId : 'XXXXXXXXXXXX'
};
var userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
Ok The above line makes a connection to the existing user pool.
Now if I were to do this:
var attributeList = [];
var dataEmail = {
Name : 'email',
Value : 'email#mydomain.com'
};
var dataPhoneNumber = {
Name : 'phone_number',
Value : '+15555555555'
};
var attributeEmail = new AmazonCognitoIdentity.CognitoUserAttribute(dataEmail);
var attributePhoneNumber = new AmazonCognitoIdentity.CognitoUserAttribute(dataPhoneNumber);
attributeList.push(attributeEmail);
attributeList.push(attributePhoneNumber);
userPool.signUp('username', 'password', attributeList, null, function(err, result){
if (err) {
alert(err.message || JSON.stringify(err));
return;
}
cognitoUser = result.user;
console.log('user name is ' + cognitoUser.getUsername());
});
I can see in AWS console that the user is being added. Great.
Now how to change the attributes of the existing user?
All of examples like this and this
Suggest the following:
Use case 8. Update user attributes for an authenticated user.
var attributeList = [];
var attribute = {
Name : 'nickname',
Value : 'joe'
};
var attribute = new AmazonCognitoIdentity.CognitoUserAttribute(attribute);
attributeList.push(attribute);
cognitoUser.updateAttributes(attributeList, function(err, result) {
if (err) {
alert(err.message || JSON.stringify(err));
return;
}
console.log('call result: ' + result);
});
The problem here is I cant authenticate the user. I can't know user's password, only his email. This is after all a simple Backoffice program, where I just need to change users email.
What can I do in this case?
To update the attributes of a Cognito User Pool-user as an admin, you should use adminUpdateUserAttributes function from the aws-sdk class CognitoIdentityServiceProvider.
let AWS = require('aws-sdk');
let cognitoISP = new AWS.CognitoIdentityServiceProvider({ region: 'your-region-here' });
function updateUserAttribute(name, value, username, userPoolId){
return new Promise((resolve, reject) => {
let params = {
UserAttributes: [
{
Name: name, // name of attribute
Value: value // the new attribute value
}
],
UserPoolId: userPoolId,
Username: username
};
cognitoISP.adminUpdateUserAttributes(params, (err, data) => err ? reject(err) : resolve(data));
});
}

Can't generate Google Analytics DataChart client side with Service Account Token (Invalid Credentials Error)

I'm trying to implement Google Analytics Graphs via their Javascript API, as the example on their site link.
But I keep getting "401 Invalid Credentials" each time I try to execute gapi.analytics.googleCharts.DataChart
I'm getting the access token server side (C#) using the following code with data from the JSON generated for the Service Account
var cred = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(clientId)
{
Scopes = new[] { AnalyticsReportingService.Scope.AnalyticsReadonly },
User = clientEmail,
ProjectId = "projectID"
}.FromPrivateKey(privateKey));
var token = cred.GetAccessTokenForRequestAsync(authURI);
token.Wait();
var result = token.Result;
return result;
or (using the full json string, see Note too)
GoogleCredential cred;
var gCred = GoogleCredential.FromJson(json).UnderlyingCredential as
ServiceAccountCredential;
var token = gCred.GetAccessTokenForRequestAsync("https://accounts.google.com/o/oauth2/auth");
return token.Result;
While on the client side
gapi.analytics.auth.authorize({
'serverAuth': {
'access_token': '{{ ACCESS_TOKEN_FROM_SERVICE_ACCOUNT }}'
}
});
goes through and using gapi.analytics.auth.isAuthorized() returns true using any of the server side functions but it fails when trying to call
var dataChart1 = new gapi.analytics.googleCharts.DataChart(queryJson);
dataChart1.execute();
returns 401 "Invalid Credentials", the server side query returns values just fine so I think the user permissions is not the issue
NOTE: Using the same code as the second one (generating the credential using the json string without casting as a ServiceAccountCredential) I can get data from the API server side
cred = gCred.CreateScoped(scopes);
using (var reportingService = new AnalyticsReportingService(new BaseClientService.Initializer
{
HttpClientInitializer = cred
}))
...
var getReportsRequest = new GetReportsRequest
{
ReportRequests = new List<ReportRequest> { reportRequest }
};
var batchRequest = reportingService.Reports.BatchGet(getReportsRequest);
var response = batchRequest.Execute(); //This returns a response object with all the data I need
If anyone has the same issue:
You need to use GoogleCredential.GetApplicationDefault() to create the Credential object, in the case of Analytics you should get something like this
var credential = GoogleCredential.GetApplicationDefault().CreateScoped(AnalyticsReportingService.Scope.AnalyticsReadonly);
This will get the json file from the Environment Variables on Windows, so you need to set GOOGLE_APPLICATION_CREDENTIALS with the path to the json as a System Variable.
Initialize the service and set the service variable
using (var reportingService = new AnalyticsReportingService(new BaseClientService.Initializer { HttpClientInitializer = credential }))
{
var serviceCredential = cred.UnderlyingCredential as ServiceAccountCredential;
}

AWS Cloudsearch NET or Javascript - Couldn't access to 2011-02-01 Domain for Seach Request

I'm taking my first steps on AWS Cloudsearch (I Need to use the developers tools for CloudSearch)
I Need to access to the following URL:
https://search-memtestsearch-ra5knmztzu6iq4ntytlxkntqty.us-east-1.cloudsearch.amazonaws.com/2011-02-01/search?bq=subjectfirstname:%27alex%27&return-fields=subjectlastname,subjectfirstname&results-type=json
But both APIs (NET & Javascript) try to access to:
https://search-memtestsearch-ra5knmztzu6iq4ntytlxkntqty.us-east-1.cloudsearch.amazonaws.com/2013-01-01/search?bq=subjectfirstname:%27alex%27&return-fields=subjectlastname,subjectfirstname&results-type=json
I don´t now how I could access to "/2011-02-01" domain instead of "/2013-01-01" domain...
I know that this is related to the version, but i donn´t know how i could access; also i can´t find examples for this.
I'm going crazy :)
This is the code that i use for NET:
String queryUrl = #"http://search-memtestsearch-ra5knmztzu6iq4ntytlxkntqty.us-east-1.cloudsearch.amazonaws.com";
AmazonCloudSearchDomainClient searchClient = new AmazonCloudSearchDomainClient(queryUrl);
SearchRequest searchRequest = new SearchRequest();
searchRequest.Query = .....
searchRequest.QueryParser =....
SearchResponse searchResponse = searchClient.Search(searchRequest);
And this is the one for Javascript:
var csd = new AWS.CloudSearchDomain({
endpoint: 'http://search-memtestsearch-ra5knmztzu6iq4ntytlxkntqty.us-east-1.cloudsearch.amazonaws.com',
apiVersion: '2011-02-01',
region: 'us-east-1'
});
var params = {...}
csd.search(params, function (err, data) {
if (err){ console.log(err, err.stack); // an error occurred
}else{console.log(data); // successful response
}});
Could anybody help me with one example?
Thanks in advance
Sebastian

Node.js Returning Null when Scraping HTML

I'm currently trying out some code which is meant to look for a specific torrent of Kickass Torrents as a proof of concept, but for some reason my simple code is failing to retun any value besides null, depsite the fact that I have confirmed that a torrent exists with the ID that I have in the program.
searchTerm = "photoshop"
var request = require("request"),
cheerio = require("cheerio"),
url = "https://kat.cr/usearch/" + searchTerm + "/";
request(url, function (error, response, body) {
if (!error) {
var $ = cheerio.load(body),
magnet = $("[data-id='233B2C174D5FEF9D6AFAA61D150EC0B6F821D6A9'] href").html();
console.log(magnet)
}
});
The main KickAssTorrents site, kat.cr, encrypts the data that is returned. Instead, you could use http://kickasstorrentseu.com, which doesn't encrypt what is returned

Categories