Keystonejs, stop graphql to write the error and hints out - security

I am developing a JAMStack project using keystonejs 6 and nuxtjs. As we know, keystonejs uses prisma and graphql (I guess apollo) to serve CRUD (generic) actions on our data model. So it makes the apis (even graphql or rest) and the errors generated are also generated by keystonejs. Now the problem is when the client send a wrong request to keystonjs, then it will help the client to correct the query and gives hints on it. For example if I query the next request:
await fetch("https://host:port/api/graphql", {
"credentials": "include",
"headers": {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:94.0) Gecko/20100101 Firefox/94.0",
"Accept": "*/*",
"Accept-Language": "en-US,en;q=0.5",
"Content-Type": "application/json",
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-site"
},
"referrer": "https://host:port/",
"body": "{\"operationName\":null,\"variables\":{},\"query\":\"{\\n navigationMenus(where: {status: {not: {equals: \\\"invisible\\\"}}}) {\\n ida\\n title\\n pageURL\\n childrenCount\\n parent {\\n id\\n pageURL\\n __typename\\n }\\n __typename\\n }\\n}\\n\"}",
"method": "POST",
"mode": "cors"
});
as the field ida is not valid, is returns a bad request error with status code 400 (which is ok) and also helps the client with the following response:
errors [ {…} ]
0 Object { message: "Cannot query field \"ida\" on type \"NavigationMenu\". Did you mean \"id\"?", locations: […], extensions: {…} }
message "Cannot query field \"ida\" on type \"NavigationMenu\". Did you mean \"id\"?"
locations [ {…} ]
0 Object { line: 3, column: 5 }
line 3
column 5
extensions Object { code: "GRAPHQL_VALIDATION_FAILED" }
code "GRAPHQL_VALIDATION_FAILED"
So this will lead to some vulnerabilities since if I forget to make currect access controls on some fields, attacker may find field names with some tries and access to those data.
Although I can understand that this is not a very big issue, but is there a way to turn graphql hints off on production?

Keystone is build on top of Apollo and lets you pass additional config though to the Apollo server on start via the graphql.apolloConfig config option:
graphql.apolloConfig (default: undefined): Allows you to pass extra options into the ApolloServer constructor.
– Keystone 6: System Configuration API docs
This can be used to modify the Apollo error handling behaviour and replace it with your own. A simple example may look like this:
import { config } from '#keystone-next/keystone';
import { lists } from './schema';
import { ValidationError } from 'apollo-server-express';
import { GraphQLError } from 'graphql';
export default config({
db: {
provider: 'sqlite',
url: process.env.DATABASE_URL,
},
lists,
graphql: {
apolloConfig: {
formatError: (error: GraphQLError): any => {
if (error instanceof ValidationError) {
return new ValidationError('Invalid request.');
}
}
}
}
});
Any GraphQL queries that attempt to access non-existent field will then receive the response:
{
"errors": [
{
"message": "Invalid request.",
"extensions": {
"code": "GRAPHQL_VALIDATION_FAILED"
}
}
],
"data": null
}
The general problem of Apollo leaking data in this way is being tracked in the Apollo repo, eg: Validation errors can be used to get schema details #2247. It sounds like progress is being made.

Related

Shopify NodeJS: Error creating Metafields: error 422 "type can't be blank"

I'm trying to create metafields using the Shopify Admin REST API (with NodeJS).
This is a simplified version of the call I'm trying to make (see documentation):
const data = await client.post({
path: 'metafields',
data: {
"metafield": {
"namespace": "namespace123",
"key": "key123",
"value": 42,
"type": "number_integer"
}
},
type: DataType.JSON,
});
But I get this error:
HttpResponseError: Received an error response (422 Unprocessable Entity) from Shopify:
{
"type": [
"can't be blank"
]
}
I've checked that the type attributes are set properly:
The root-level type is set correctly to application/json, and data.metafield.type is set following the rules here.
I've also tried other types, but I get the same error.
Problem: I was using an old API version to initialize my Shopify Context:
Shopify.Context.initialize({
// ... other stuff ... //
API_VERSION: ApiVersion.October20,
});
None of my other API calls relied on old breaking behaviour, so updating my API version fixed the issue without too much hassle:
Shopify.Context.initialize({
// ... other stuff ... //
API_VERSION: ApiVersion.January22,
});

amazon product advertising api node js sdk request throtteling issue

I am getting this error in response when calling amazon product advertising api from nodejs sdk.
Error calling PA-API 5.0!
Printing Full Error Object:
{
"status": 429,
"response": {
"req": {
"method": "POST",
"url": "https://webservices.amazon.com/paapi5/getitems",
"data": {
"ItemIds": [
"B075LRK2QK"
],
"PartnerTag": "raassnabct-21",
"PartnerType": "Associates",
"Condition": "New",
"Resources": [
"Images.Primary.Medium"
]
},
"headers": {
"user-agent": "paapi5-nodejs-sdk/1.0.0",
"authorization": "AWS4-HMAC-SHA256 Credential=MY_KEY/20191215/us-east-1/ProductAdvertisingAPI/aws4_request, SignedHeaders=content-encoding;content-type;host;x-amz-date;x-amz-target, Signature=030b9f07a2336302a6d8855e216e602589960bf919dc9e700daac6155dcce1a2",
"content-encoding": "amz-1.0",
"content-type": "application/json; charset=utf-8",
"host": "webservices.amazon.com",
"x-amz-target": "com.amazon.paapi5.v1.ProductAdvertisingAPIv1.GetItems",
"x-amz-date": "20191215T111055Z",
"accept": "application/json"
}
},
"header": {
"server": "Server",
"date": "Sun, 15 Dec 2019 11:10:54 GMT",
"content-type": "application/json",
"content-length": "193",
"connection": "close",
"x-amzn-requestid": "0ada8ea0-944f-47a2-bbef-acc0f5d984a9",
"vary": "Accept-Encoding,X-Amzn-CDN-Cache,X-Amzn-AX-Treatment,User-Agent",
"content-encoding": "gzip",
"x-amz-rid": "JTD0DAVWEB1CMXK1F5BW"
},
"status": 429,
"text": "{\"__type\":\"com.amazon.paapi5#TooManyRequestsException\",\"Errors\":[{\"Code\":\"TooManyRequests\",\"Message\":\"The request was denied due to request throttling. Please verify the number of requests made per second to the Amazon Product Advertising API.\"}]}"
}
}
Status Code: 429
Error Object: "{\"__type\":\"com.amazon.paapi5#TooManyRequestsException\",\"Errors\":[{\"Code\":\"TooManyRequests\",\"Message\":\"The request was denied due to request throttling. Please verify the number of requests made per second to the Amazon Product Advertising API.\"}]}"
And the code is
var ProductAdvertisingAPIv1 = require('./src/index');
var defaultClient = ProductAdvertisingAPIv1.ApiClient.instance;
defaultClient.accessKey = 'accessKey';
defaultClient.secretKey = 'secretKey';
defaultClient.host = 'webservices.amazon.com';
defaultClient.region = 'us-east-1';
var api = new ProductAdvertisingAPIv1.DefaultApi();
var getItemsRequest = new ProductAdvertisingAPIv1.GetItemsRequest();
getItemsRequest['PartnerTag'] = 'raassnacbt-21';
getItemsRequest['PartnerType'] = 'Associates';
getItemsRequest['ItemIds'] = ['B075LRK2QK'];
getItemsRequest['Condition'] = 'New';
getItemsRequest['Resources'] = ['Images.Primary.Medium', 'ItemInfo.Title', 'Offers.Listings.Price'];
function parseResponse(itemsResponseList) {
var mappedResponse = {};
for (var i in itemsResponseList) {
mappedResponse[itemsResponseList[i]['ASIN']] = itemsResponseList[i];
}
return mappedResponse;
}
try {
api.getItems(getItemsRequest, callback);
} catch (ex) {
console.log("Exception: " + ex);
}
I am getting "too many requests" error even when making just one. also tried to run this on server just in case it had something to do with localhost. there is no manual modification, it is just the sdk code with my credentials. any idea what might be the issue?
This is a very common problem people face while using Amazon product API. Amazon works on a very different algorithm. It allocates API threshold/ usage limit based on the commission you have earned through amazon. Once your allocated limit is exhausted, you will receive such errors.
To fix this, ask your friend to buy through your affiliate link. You will get some threshold.
Old topic, but maybe can be useful. I realized this error is also shown when authentication failed. So it is necessary to take into account that associate IDs are only active in a concrete region and also that new generated API Keys can take until 72h to be really active, so check these points if necessary apart from the quota stuff the other users mentioned.

queryStringParameters in mock-server

I have the following url:
http://10.11.100.163:1080/v1/publish/?category=conf&product=UFED_INFIELD&serial=123&productGUIDs%5B0%5D%5Bproduct%5D=GLOBAL&productGUIDs%5B0%5D%5Bguid%5D=undefinedblabla&productGUIDs%5B1%5D%5Bproduct%5D=UFED_INFIELD&productGUIDs%5B1%5D%5Bguid%5D=undefinedblabla
As you can see there are several parameters that are formed by two names, like "productGUIDs%5B0%5D%5Bproduct%5D=GLOBAL" and this is equal to "productGUIDs[0][product]=GLOBAL"
now in the expectation file on the mock-server I am trying to create the request but without success until now.
this is what I wrote in the expectation file:
await mockServerClient(process.env.mockServerAddress , process.env.mockServerPort).setDefaultHeaders(defaultResponseHeaders, []).mockAnyResponse({
"httpRequest":{
"method": "GET",
"path": "/v1/publish",
"queryStringParameters": {
"category":["conf"],
"product":["UFED_INFIELD"],
"serial":["123"],
"productGUIDs%5B0%5D%5Bproduct%5D" : ["GLOBAL"],
"productGUIDs%5B0%5D%5Bguid%5D" : ["undefinedblabla"],
"productGUIDs%5B1%5D%5Bproduct%5D" : ["UFED_INFIELD"],
"productGUIDs%5B1%5D%5Bguid%5D" : ["undefinedblabla"],
}
},
when sending the request (GET) with POSTMAN, I get 404, means, the mock-server does not recognize the request.
any advice of how to write the query string parameters in the expectation file will be really appreaciated
The correct queryStringParameters syntax is an array of objects with name/values keys, like this:
"queryStringParameters": [
{
"name": "category",
"values": ["conf"]
},
{
"name": "product",
"values": ["UFED_INFIELD"]
},
{
"name": "productGUIDs%5B0%5D%5Bproduct%5D",
"values": ["GLOBAL"]
}
]
Here an example of an expectation in a file.yaml for a POST request with queryStringParameters. To adapt it to the GET method just delete the body and change "POST" by "GET" :
times:
remainingTimes: 1
unlimited: false
httpRequest:
method: POST
path: /accounts/login
queryStringParameters:
urlparameter1: 'value1'
body:
type: PARAMETERS
parameters:
username: myusername
password: mypassword
httpResponse:
body: {
"access_token": "e55etg9c-167e-4841-b0r3-y8fe5d1t7568",
"token_type": "bearer",
"redirectUrl": "/menu/clothes"
}
statusCode: 200
reasonPhrase: OK
The indexation is very important in the .yaml file, so be careful to have the good format for each element, otherwise it won't work.
You can find here the documentation to do expectations :
https://www.mock-server.com/mock_server/creating_expectations.html#button_match_request_by_negative_priority
Maybe you'll find your answer in the example "match request by path parameter and query parameter" in the link above.

HTTP request / Service bus - application/x-www-form-urlencoded not supported error

I've got a really simple Logic app:
HTTP request (works as end-point web hook for Slack)
Send request from Slack (URI) to Service Bus queue
I haven't made any changes in Logic App but Send message action suddenly started reporting this error:
Decoding as string is not supported for content envelope of type
'application/x-www-form-urlencoded'.
Send message is defined like that:
"Send_message": {
"inputs": {
"body": {
"Label": "#{triggerBody()}"
},
...
I see only difference in request outputs:
BEFORE
Headers
{
"Accept": "*/*",
"User-Agent": "Slackbot,1.0,(+https://api.slack.com/robots)",
"Content-Type": "application/x-www-form-urlencoded"
...
}
Body
{
"$content-type": "application/x-www-form-urlencoded",
"$content": "dG9r..."
}
NOW
Headers
{
"Accept": "*/*",
"User-Agent": "Slackbot,1.0,(+https://api.slack.com/robots)",
"Content-Type": "application/x-www-form-urlencoded"
...
}
Body
{
"$content-type": "application/x-www-form-urlencoded",
"$content": "dG9r...",
"$formdata": [
{
"key": "token",
"value": "..."
},
{
"key": "team_id",
"value": "..."
},
{
"key": "trigger_word",
"value": "!"
},
...
]
}
$formdata is now a part of the output of Request as JSON array consisting of all query parameters.
Does anyone have any ideas? I would greatly appreciate any help to make it work again.
Edit: West Europe fixed and working
Yes, in the effort to have native support for x-www-form-urlencoded data in the runtime there was a bug that was recently released. We are rolling back and patching now. Can you send me an email so we can target your region for a fix, and share a workaround? Apologies in advance - as a general rule we never want to ship anything that will break existing logic apps. In this case adding some new metadata around form-data no longer allowed people to stringify x-www-form-urlencoded data (which is what you are doing here).

Insert event with Google Calendar API in Chrome Extension keeps failing

I'm having trouble getting the format right for a chrome extension using the Google Calendar API. I have an OAuth2 access token (which is valid, I can test that with tokenInfo), but am having trouble. I'm using a proprietary framework to build the extension, which complicates things, but maybe you could help me find out what information I'm missing:
var eventParams = e.data,
request = {
'method' : 'POST',
'async' : true,
'url': 'https://www.googleapis.com/calendar/v3/calendars/'+CAL_ID + '/events',
'headers': {
'Authorization' : TOKEN
},
'params': eventParams
};
My token looks like this:
{↵ "issued_to": "831101123055-874tukfvuvkma6s0l7m70iqlc3lirnkc.apps.googleusercontent.com",↵ "audience": "831101123055-874tukfvuvkma6s0l7m70iqlc3lirnkc.apps.googleusercontent.com",↵ "scope": "https://www.googleapis.com/auth/calendar",↵ "expires_in": 3600,↵ "access_type": "offline"↵}
The error I'm getting is:
{
"error": {
"errors": [
{
"domain": "usageLimits",
"reason": "dailyLimitExceededUnreg",
"message": "Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup.",
"extendedHelp": "https://code.google.com/apis/console"
}
],
"code": 403,
"message": "Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup."
}
}
I'm not really sure why that's the case, because my request is authenticated. Am I not passing the token correctly? Someone has suggested that I need to include an API key, but my understanding is that API keys are only for apps requiring public access and don't need access to user data, and that OAuth2 takes the place of an API key.
I'd appreciate any help you guys can offer! Thank you!
Turns out the error was kind of anomalous, the problem turned out to be with the data type. The correct syntax was:
var eventParams = e.data,
request = {
'method' : 'POST',
'async' : true,
'url': 'https://www.googleapis.com/calendar/v3/calendars/' + CAL_ID + '/events',
'headers': {
'Authorization' : TOKEN_TYPE+' '+ TOKEN,
'Content-Type': 'application/json'
},
'contentType': 'json',
'params': JSON.stringify(eventParams)
};
Please make sure that you have calendar API enabled in the developers console:
https://console.developers.google.com

Resources