CalDav sync-token expiry - httpwebrequest

In a previous question, I asked about syncing data with a DaviCal server. I ended up concluding that there was a bug on DaviCal as when querying a CalDav server with an invalid sync token, the server should return an error but, instead, it returns the whole set of events on the server.
So I started looking for an alternative CalDav server. I use SabreDav. I followed their very handy tutorial here.
On there it says:
Caveats
Note that a server is free to 'forget' any sync-tokens that have been previously issued. In this case it may be needed to do a full-sync again.
In case the supplied sync-token is not recognized by the server, a HTTP error is emitted. SabreDAV emits a 403.
That looks promising : exactly what I need !
So what I do is getting my sync-token which is http://sabre.io/ns/sync/15.
I then submit my REPORT query as follows (maybe that's where I do things wrong?!)
string syncToken = "http://sabre.io/ns/sync/15";
string body = " <d:sync-collection xmlns:d=\"DAV:\"> " +
" <d:sync-token>" + syncToken + "</d:sync-token> " +
" <d:sync-level>1</d:sync-level> " +
" <d:prop> " +
" <d:getetag/> " +
" </d:prop> " +
" </d:sync-collection> ";
Request = (HttpWebRequest)HttpWebRequest.Create("http://my.sabredav.com/calendars/example/home/");
Request.Credentials = new NetworkCredential("my_user", "my_pwd");
Request.Method = "REPORT";
Request.ContentType = "application/xml";
// set the body of the request...
Request.ContentLength = body.Length;
using (Stream reqStream = Request.GetRequestStream()) {
// Write the string to the destination as a text file.
byte[] encodedBody = Encoding.UTF8.GetBytes(body);
reqStream.Write(encodedBody, 0, encodedBody.Length);
reqStream.Close();
}
// Send the method request and get the response from the server.
Response = (HttpWebResponse)Request.GetResponse();
So when I send the request using the valid sync-token http://sabre.io/ns/sync/15 I just got, I get an empty response:
<?xml version="1.0"?>
<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.or /ns/">
<d:sync-token>http://sabre.io/ns/sync/15</d:sync-token>
</d:multistatus>
So far so good.
If I use a previous sync-token that I know was valid at some point (http://sabre.io/ns/sync/14 in this case - by chance it is the previous number...) I get changes as expected:
<?xml version="1.0"?>
<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/">
<d:response>
<d:href>/calendarserver.php/calendars/admin/default/23b351ee-7677-46e3-b5c5-5263e8fca351.ics</d:href>
<d:propstat>
<d:prop>
<d:getetag>"8d8d122a66625ca990252fae652cd2e5"</d:getetag>
</d:prop>
<d:status>HTTP/1.1 200 OK</d:status>
</d:propstat>
</d:response>
<d:sync-token>http://sabre.io/ns/sync/15</d:sync-token>
</d:multistatus>
But the issue is, that if I use a RANDOM sync token that I definitely know has never been issued: http://sabre.io/ns/sync/1234312231344324
I get the SAME answer as when I was using the latest (current) token:
<?xml version="1.0"?>
<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/">
<d:sync-token>http://sabre.io/ns/sync/15</d:sync-token>
</d:multistatus>
SabreDav says it's supposed to throw an error 403, but clearly, it's not what I get here... However, if I use INVALID sync-token format, say token1234, I do indeed get an error 403...
So the question is: HOW can I make sure my sync-token is still valid ? So, if the token is valid and nothing is returned, I know my local cache is up to date or, in case the sync-token is INVALID, I need to do full sync!

This is indeed a bug in sabre/dav. Feel free to open a bug report so it's on our radar. It's never been a major concern, as 'well behaved clients' would never supply a sync-token that was never issued by us.
The reason it's happening, is because the digit is simply an ever increasing record id in our database. To fetch all the changes a simple sql query with a > is done.
If you explicitly want to test invalid tokens in your client, I would recommend to simply supply a sync-token with a completely different format (something that doesn't start with http://sabre.io/ns/sync).

Related

How to troubleshoot issues related to requests and responses from ws loaded in SM

I am working on an integration between Microfocus Service Manager and Remedy. In order to troubleshoot issues related to requests and responses from SM to Remedy is needed to print or send that information to a log. I have tried using a debug -RTM:3 flag in my testing port configuration, but unfortunately there is a lot of information in my log since it writes every step performed by the tool. After that, I set the -debughttp flag in my port, but it only writes inputs/outputs from external resources.
Here is what I have done:
Load Remedy customer's endpoint with WSDL2JS utility.
Invoke the endpoint with a SL.
Perform a request to the endpoint.
Get an undefined response.
Check logs written by -RTM and -debughttp without success.
Is there any way to check what’s happening with my requests or with my customer’s reponses?
You can get the content of your requests and responses using the sl created by WSDL2JS only adding a piece of code within it.
For your requests, look for this part of the code (about line 129):
this.resultXML = doSOAPRequest( this.location, soapOp.SOAPAction, result.xml,
this.user, this.password,
this.connectTimeOut, this.sendTimeOut, this.recvTimeOut,
this.attachments, this.acceptfastinfoset );
Add the following code below:
//Print your request
print(result.xml)
//Send your xml request to a internal log called integration_debug.log in your app server
writeFile("../logs/integration_debug.log","a","\n");
writeFile("../logs/integration_debug.log","a","######### REQUEST INFO XML######\n");
writeFile("../logs/integration_debug.log","a",system.functions.tod()
+ "\n"
+ result.xml
+ "\n"
+ "\n");
For your customer’s responses, look for this part of the code:
if ( soapOp.responseObj == "null" ) // one-way MEP ?
{
return null;
}
var resultObj = new Object();
resultObj.responseObj = soapOp.responseObj;
Add the following code below:
//Print your customer response
print(this.resultXML.getDocumentElement())
//Send your xml response to a internal log called integration_debug.log in your app server
writeFile("../logs/integration_debug.log","a","\n");
writeFile("../logs/integration_debug.log","a","######### RESPONSE INFO XML#######\n");
writeFile("../logs/integration_debug.log","a",system.functions.tod()
+ "\n"
+ this.resultXML.getDocumentElement()
+ "\n"
+ "\n");
As a reference you can check the following picture to identify where inserting your code:
Hopefully, that can be helpful for your troubleshooting.

Format this GET request in VB.NET code behind?

I am trying a "GET" method to request a count of activities from the Accelo API here:
https://api.accelo.com/docs/?http#count-activities
And although i've used a very similar POST method to successfully get the access token using an authentication method, I cannot for the life of me figure out how to get the count of activities. The API says to use "GET" and past the access token as "bearer..." and I've also tried doing a post and getting the stream first, tried sending in some data and accessing the "list activities" endpoint instead...nothing is working. everything I do returns the error "400. Bad Request."
I've tried passing data in a query string format directly in the URI, and tried passing no data since its a GET function. It looks to me like I'm following the API exactly.
Dim data2 = Nothing ' Encoding.UTF8.GetBytes(jsonstring)
Dim _list = GetListOfActivities(New Uri("https://example.api.accelo.com/api/v0/activities/count.xml"), data2, _AccessToken)
Dim reqa As WebRequest = WebRequest.Create(uri)
' reqa.Method = "GET"
reqa.Headers.Add("GET", "/api/v0/activities/count.xml HTTP/1.1")
reqa.Headers.Add("Authorization", "Bearer " & _AccessToken)
reqa.ContentType = "application/x-www-form-urlencoded"
'reqa.ContentLength = jsonDataBytes.Length
' Dim streama = reqa.GetRequestStream()
' streama.Write(jsonDataBytes, 0, jsonDataBytes.Length)
'streama.Close()
Dim responsea As WebResponse = reqa.GetResponse()
Console.WriteLine((CType(responsea, HttpWebResponse)).StatusDescription)
I must be formatting the request wrong - please help?
My problem turned out to be something stupid, and literally beyond the scope of what I posted here. I had specified a "scope" in my initial request to get the access token that was set to read-only "staff" data (I had copied-and-pasted their example online into my code, for other parameters like grant type, and I brought the scope along with it), and in this scenario here I was trying to access "activities" data and not "staff" data. I would have thought I'd get a permissions-related error, instead of "bad request" which confused me, but anyway it works now.
The above code - actually with this line:
reqa.Method = "GET"
instead of this line:
reqa.Headers.Add("GET", "/api/v0/activities/count.xml HTTP/1.1")
Works just fine since I changed my scope to read(all) in my initial web method getting the access token.

Error occurred during DocuSign API and Integration and Envelope Creation #DocuSignAPI

I am getting an error while creating Envelope using following code. But authentication is successful and I am able to retrieve Account Id.
Authentication code:
string authHeader = "{\"Username\":\"" + Username + "\", \"Password\":\"" + Password + "\", \"IntegratorKey\":\"" + IntegratorKey + "\"}";
cfg.AddDefaultHeader("X-DocuSign-Authentication", authHeader);
AuthenticationApi authApi = new AuthenticationApi(cfg);
Envelope Creation code Code:
EnvelopeSummary envelopeSummary = envelopesApi.CreateEnvelope(AccountId, envDef);
Error details:
A first chance exception of type 'DocuSign.eSign.Client.ApiException' occurred in DocuSign.eSign.dll
Error: Error calling CreateEnvelope: {
"errorCode": "PARTNER_AUTHENTICATION_FAILED",
"message": "The specified Integrator Key was not found or is disabled. An Integrator key was not specified."
}
Any help will be appreciated.
The error "PARTNER_AUTHENTICATION_FAILED" is the first failure before even the body is read, it means the Integrator Key is NOT valid for the environment, method call "Reserved" or Missing as the "message" states.
Most of the time this happens in a functioning system with the Integrator Key is "Turned off" if the system is doing something not allowed aka stuck in a loop of making a "reserved" call. If you have been testing and now went live in prod, it means your Integrator Key is NOT allowed in Production.
To help you the best way is to capture exact JSON/SOAP request posted by your API calls via Java to DocuSign by following steps explained at this DocuSign support article https://support.docusign.com/guides/ndse-user-guide-api-request-logging
Please post these and what actual DocuSign API call you are trying to make and I am sure it will be we will be able to deduce the issue.

Problems Connecting to MtGox API 2 with Python

I am writing a trading program that I need to connect to MtGox (a bitcoin exchange) through the API v2. But I keep getting the following error:
URL: 1 https://data.mtgox.com/api/2/BTCUSD/money/bitcoin/address
HTTP Error 403: Forbidden.
Most of my script is a direct copy from here (that is a pastebin link). I just had to change it to work with Python 3.3.
I suspect that it has to do with the part of script where I use base64.b64encode. In my code, I have to encode my strings to utf-8 to use base64.b64encode:
url = self.__url_parts + '2/' + path
api2postdatatohash = (path + chr(0) + post_data).encode('utf-8') #new way to hash for API 2, includes path + NUL
ahmac = base64.b64encode(str(hmac.new(base64.b64decode(self.secret),api2postdatatohash,hashlib.sha512).digest()).encode('utf-8'))
# Create header for auth-requiring operations
header = {
"User-Agent": 'Arbitrater',
"Rest-Key": self.key,
"Rest-Sign": ahmac
}
However, with the other guy's script, he doesn't have too:
url = self.__url_parts + '2/' + path
api2postdatatohash = path + chr(0) + post_data #new way to hash for API 2, includes path + NUL
ahmac = base64.b64encode(str(hmac.new(base64.b64decode(self.secret),api2postdatatohash,hashlib.sha512).digest()))
# Create header for auth-requiring operations
header = {
"User-Agent": 'genBTC-bot',
"Rest-Key": self.key,
"Rest-Sign": ahmac
}
I'm wondering if that extra encoding is causing my header credentials to be incorrect. I think this is another Python 2 v. Python 3 problem. I don't know how the other guy got away without changing to utf-8, because the script won't run if you try to pass a string to b64encode or hmac. Do you guys see any problems with what I am doing? Is out code equivalent?
This line specifically seems to be the problem -
ahmac = base64.b64encode(str(hmac.new(base64.b64decode(self.secret),api2postdatatohash,hashlib.sha512).digest()).encode('utf-8'))
To clarify, hmac.new() creates an object to which you then call digest(). Digest returns a bytes object such as
b.digest()
b'\x92b\x129\xdf\t\xbaPPZ\x00.\x96\xf8%\xaa'
Now, when you call str on this, it turns to
b'\\x92b\\x129\\xdf\\t\\xbaPPZ\\x00.\\x96\\xf8%\\xaa'
So, see what happens there? The byte indicator is now part of the string itself, which you then call encode() on.
str(b.digest()).encode("utf-8")
b"b'\\x92b\\x129\\xdf\\t\\xbaPPZ\\x00.\\x96\\xf8%\\xaa'"
To fix this, as turning bytes into a string back into bytes was unnecessary anyhow(besides problematic), I believe this will work -
ahmac = base64.b64encode(hmac.new(base64.b64decode(self.secret),api2postdatatohash,hashlib.sha512).digest())
I believe you are likely to find help in a related question of mine although it deals with the WebSocket API:
Authenticated call to MtGox WebSocket API in Python 3
Also, the HTTP 403 error seems to indicate that there is something fundamentally wrong with the request. Even if you threw the wrong authentication info at the API you should have gotten an error message as a response and not a 403. My best guess is that you are using the wrong HTTP method so check if you are using the appropriate one (GET/POST).

FB error:Expected 1 '.' in the input between the postcard and the payload

I have finished my app and then tried it on 3 FB accounts and it was ok,
but the 4th have a permanent error (it cannot get an access token):
com.restfb.exception.FacebookOAuthException: Received Facebook error response of type OAuthException: Expected 1 '.' In the input between the postcard and the payload.
I tried to remove the app and install it again on this account a few times and nothing changed.
I use Java and restFB client.
This is the code where i get the access token:
if (request.getParameter("code") != null) {
String code = request.getParameter("code");
String url = "https://graph.facebook.com/oauth/access_token?"
+ "client_id=" + clientId + "&" + "client_secret="
+ clientSecret + "&" + "code=" + code + "&" + "redirect_uri="
+ redirectURL +"&type=web_server";
String accessToken=readUrl(url).split("&")[0].replaceFirst("access_token=", "");
//....
}
I saw here someone with the same error, he said that the solution was:
replacing "|" with "%257C" which made my access token invalid"
I couldn't really understand what he means.
Embarrassing as it is -- I'll be honest in case it helps someone else:
When I got this error message, I had accidentally copy/pasted a Google access_token (e.g. ya29.A0A...) into a Facebook graph API route. :)
It's probably worth logging the response to the /oauth/access_token request and the value you extract for use as the access token.
For the account that doesn't work, check whether the /oauth/access_token response includes other parameters before access_token. IIRC I've seen responses like
expiry=86400&access_token=AAAxxxx
Check to ensure you are verifying the "code" parameter returned by Facebook before signing the request, not the "access token". That was the mistake I made.
I experience the same issue, and after debugging my only conclusion was that when this message is thrown it might just be the token is expired or invalid. Checking with a freshly generated token should not throw this error.