Nfs/directory : Unauthorized ? Need help

Hello,

I am still trying to get play around with the API. However it’s my first time calling a REST Api.
All my POST queries are Unauthorized. While my GET query to /auth is successful.
What am I missing ?

Here my localhost:8100/nfs/directory result :

POST http://localhost:8100/nfs/directory
Authorization: bearer eyJhbGciOiJIUzI1NiJ9.eyJpZCI6IjU0ZGl2N2JOeW9mZVJyVjFnU090YTcxVkl6ckkrbFpzejh2VXhtSERWajQ9In0.G1DchQTAoOhF7lwdZmSYT3jCnLzbtx-NXaEDJJ8OVQ8
Content-Type: text/plain
AAAAAAAAAAAAAAAAAAAAAF+6xYuuC5k5l8E+NzMhlfW97rmokfB1VNXaghWWBVod5XzcMbiU+wdx8iw38h8HokjXpGA3KnwX9/JbHlD3oWeXe7fkqln2sR0RY16MhnPG/QHvcmBxCyoY97vS6nA330Uxx2pGfH9bdIMTGKRyepQ+Fs49
 -- response --
401 Unauthorized
X-Powered-By:  Express
Access-Control-Allow-Origin:  *
Access-Control-Allow-Headers:  Origin, X-Requested-With, Content-Type, Accept, Authorization
Access-Control-Allow-Methods:  DELETE, GET, OPTIONS, POST, PUT
Content-Type:  text/plain; charset=utf-8
Content-Length:  12
Etag:  W/"c-4G0bpw8TMen5oRPML4h9Pw"
Date:  Fri, 01 Apr 2016 15:55:04 GMT
Connection:  keep-alive

Unauthorized

Here me /auth GET result:

GET http://localhost:8100/auth
Authorization: bearer eyJhbGciOiJIUzI1NiJ9.eyJpZCI6IjU0ZGl2N2JOeW9mZVJyVjFnU090YTcxVkl6ckkrbFpzejh2VXhtSERWajQ9In0.G1DchQTAoOhF7lwdZmSYT3jCnLzbtx-NXaEDJJ8OVQ8

 -- response --
200 OK
X-Powered-By:  Express
Access-Control-Allow-Origin:  *
Access-Control-Allow-Headers:  Origin, X-Requested-With, Content-Type, Accept, Authorization
Access-Control-Allow-Methods:  DELETE, GET, OPTIONS, POST, PUT
Content-Type:  text/plain; charset=utf-8
Content-Length:  2
Etag:  W/"2-4KoCHiHd29bYzs7HHpz1ZA"
Date:  Fri, 01 Apr 2016 15:49:22 GMT
Connection:  keep-alive

OK
1 Like

Unfortunately the 401 is a bit of a catch all in the launcher source. Assuming that your body is encrypted and base 64’d, what does it look like in clear text?

It’s a simple (json) string. Using the exact same logic to encrypt and transform to base64 like in the https://maidsafe.readme.io/docs/nfsfile example.

{“dirPath”: “/photos”,“isPrivate”: true,“metadata”: null,“isVersioned”: false,“isPathShared”: false}

Yeah, sorry, I am not sure what the issue is here just by looking. It might be an encryption problem. You can compare with other libraries to see how their requests work. You may have to debug the launcher yourself.

No problem :wink:
Isn’t it possible get an error code 400 somehow without valid body content ?
Or is a valid body content absolutely necesary to get something different from 401… ?
Empty body yields 500 …

It is possible, just not done yet. It was claimed that they did that (i.e. remove 500’s for user problems) but they persist. In the source, if the bearer JWT is invalid you get a 401 (ref https://github.com/maidsafe/safe_launcher/blob/3cb7a7dd91ae4216ed43489fa42c9faadb775220/app/server/controllers/dns.js#L7). Also, if there is a failure decrypting the body or query string you also get a 401 (ref: https://github.com/maidsafe/safe_launcher/blob/3cb7a7dd91ae4216ed43489fa42c9faadb775220/app/server/utils.js#L74). Both of these seem like ok uses of 401 though I’d probably make the latter do a 400 on a localhost-only API where I am not worried about disclosing too much info about successful/failed JWT’s vs shared keys.

Okay, thanks for pointing to the exact lines of code…
Since /auth is working fine i suppose my body is incorrect.
I’m not fit enough in .js to dig deeper into this at the moment.

On a similar note:
(omitted setup code, let me know if its relevant) - I do have permissions: [‘SAFE_DRIVE_ACCESS’] in it.

var longName;
 var services;

p = p.then(_ => {
return safe.dns.getLongNames(client).then(function(data) {
console.log('Long Names: ', data)
longName = data;


    })
})

let serviceName = 'www3';
//let longNameName = longName[0];
p = p.then(_ => {
return safe.dns.getServices(client, longName[0]).then(function(service) {
	//console.log('Service Names: ', fileBuf.toString())
	//services = safe.dns.getServices(client, longName);
	services = service;
	for (var i=0, len=services.length; i<len; i++)
	{
		if (services[i] == serviceName){
			console.log('Services: ', services[i]);
			//services = services[i];
			return safe.dns.getServiceDir(client, longName[0], serviceName).then(function(data){
				console.log('dns data: ', data)
			})
			
			//return;
		}
	}
	return safe.dns.addService(client, {longName: longName[0], serviceName: serviceName, serviceHomeDirPath: '/', isPathShared: true}).then(function(){
		console.log('created new service')
	})
})
})

p = p.then(_ => {
return safe.nfs.getDir(client, {dirPath: '/'}).then(function(data){
				console.log('nfs data: ', data);
			})

})`

yields:
Error: 400: {"errorCode":-10,"description":"CoreError::OperationForbiddenForClient"}
On the second run. The error is at the getServiceDir call… Any ideas?

Also, please ignore the hack-job coding. Still learning nodejs. The syntax seems very foreign to me.

I just decrypted my string after encrypting it and it actually looks like this:

{“dirPath”:"/photos",“isPrivate”:true,“metadata”:null,“isVersioned”:false,“isPathShared”:false}

Is this possibly the cause for the error ? Can the launcher handle this properly ?
I can’t see how I could pass a string in C# to contain doubleQuotes without escaping them.

That is invalid JSON and could be the cause. In programming languages there is a difference between string literals (where you have to escape double quotes) and runtime strings (where they are not escaped). C# also allows you to prefix the string literal with @ that would obviate escaping. But that’s only for string literals. At this point I’d probably have to see the code. Whenever there is a bug, the best thing you could do is make the smallest possible test case to replicate.

As mentioned to the other poster, can you make the smallest possible test case to replicate from scratch instead of pasting your existing code? Also, set client.logger = console.log to see some HTTP debug details.

I want to create a new service, then get the info on that service… The code below is as condensed as I know how to make it:

let longName = 'wes';
let serviceName = 'www4';

p = p.then(_ => {	
return safe.dns.addService(client, {longName: longName, serviceName: serviceName, serviceHomeDirPath: '/', isPathShared: true}).then(function(){
		console.log('created new service')
	})
})
p = p.then(_ => {	
return safe.dns.getServiceDir(client, longName, serviceName).then(function(data){
				console.log('dns data: ', data)
			})
			
})

yields:

Calling GET http://localhost:8100/auth
RESP BODY OK
Calling PUT http://localhost:8100/dns
REQ BODY {"longName":"wes","serviceName":"www4","serviceHomeDirPath":"/","isPathShared":true}
RESP BODY OK
created new service
Calling GET http://localhost:8100/dns/www4/wes
RESP BODY {"errorCode":-10,"description":"CoreError::OperationForbiddenForClient"}

I have not tried creating a service tied to the root dir, I don’t think you can. The top level shared directory is “SAFEDrive” (as opposed to the top level non-shared directory of “MYAPP-Root-Dir”). Top level directories (i.e. /) are considered “private”. Private directories I don’t think can be tied to DNS. It might be better to get someone from maidsafe to confirm this.

Create a non-private sub directory and tie the service to that.

Edit: OK, I have thought about this. The DNS call you make is unauthorized and therefore cannot access a private directory. Before there was an issue where authing during an unauth’d operation actually failed. It might be fixed, I have to check. Then I have to check if I give the user in my API the option to perform that call while authorized if the private dir will be available.

it seems that the problem was indeed with creating in the root. Created a new dir, then set the service to use that dir instead of root with no other changes and it worked as expected.

Thanks for your help.

EDIT: Correction. Your second thought may also be true, if I create the dir as private, it fails the getServiceDir call, when private is false, it works.

My entire code can been seen here:

http://csharppad.com/gist/d3be5c1ff6e9b974be90664fddc2f8d6
(with syntax highlighting)

It starts at line 116.

What I do is building the Json string like this:

// building json body
string json = “{‘dirPath’:’/photos’,‘isPrivate’:true,‘metadata’:null,‘isVersioned’:false,‘isPathShared’:false}”;
// escaping doubleQuotes
json = json.Replace("’", @"""");

This is working fine for the /auth POST . The difference however between /auth and /nfs/directory is that in the second case, the body is encrypted.
While making a REST Api call with escaped doublequotes works fine in the first case, the escape characters are also encrypted in the second case. Decrypting within a non dotNet environment might cause the problem.

Thanks for your time and helping us get started :slight_smile:

1 Like

The single quote to double quote makes little sense, but it doesn’t appear to cause a wrong result. Nothing here is jumping out at me. Sorry. You’re gonna have to debug the launcher I’m afraid unless someone else pops in and sees the obvious issue. You can also compare it to the other clients that have been released and do not get 401’s.

1 Like