Hi,
At first I want to explain that I know it is a BUG tracker, so I asked this question first via support but they redirected me here because community is quite active and supportive.
So, I would like to make custom cross-platform, open-source client with lightweight UI based on low level GDI/X graphic server. Since protocol by itself looks easy but I have troubles with preparing all needed librarys. There is a lot of resources links but I don't know where to start. Is there something like base-wrapper _wire.dll_ or _libwire.so_ which I have to build first or everything including ciphers and TCP/IP connections have to make by my self? Is there HOWTO document which I'm missing?
Regards
You may find these links interesting: #994, #665, #642, #567.
https://gitlab.com/ddobrev/Fibre/
Dude, your links seems to be what I'm looking for. Thanks a lot but please don't close this topic yet
Seems that Wire backend is based on sending JSON via websocket protocol. I'm analyzing Coax source (https://github.com/wireapp/coax) but Rest language is not familiar for me so it is not easy. I don't understand authorisation. I guess that I first have to request for authorisation key by POST to https://prod-nginz-https.wire.com/access, remember token and pass it to websocket URL https://prod-nginz-ssl.wire.com/await . But this curl command:
curl -k -i -H "Accept: application/json" -H "Content-Type: application/json" -X POST "https://prod-nginz-https.wire.com/access"
return me:
HTTP/1.1 403 Forbidden
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: Request-Id, Location
Content-Type: application/json
Date: Sun, 26 Nov 2017 20:08:28 GMT
Request-Id: 51dd604c87e0b8f5e6f77fc5e22acbf2
Server: nginx
Strict-Transport-Security: max-age=31536000; preload
Vary: Accept-Encoding
Content-Length: 69
Connection: keep-alive
{"code":403,"message":"Missing cookie","label":"invalid-credentials"}
I have to post there my login and password?
Thanks. I'm now looking at android source. Java is much clear for me
Ok, small progress. Your javascript example is indeed helpful. I'm able to login now. Sending JSON with email and password and finally getting OK 200 response with JSON:
{"expires_in":900,"access_token":"blabla","user":"blabla","token_type":"Bearer"}
Now I guess I have to request on https://prod-nginz-https.wire.com/access using token above. Adding header:
h.Headers.Insert(0, 'Authorization: '+js.Get('token_type','')+' '+js.Get('access_token',''));
as equivalent for javascript's:
Authorization: `Bearer ${window.decodeURIComponent(this.client.access_token)}
but still getting:
403 Forbidden {"code":403,"message":"Missing cookie","label":"invalid-credentials"}
BTW: Does anyone know what is difference between these two URLs?
https://staging-nginz-https.zinfra.io/login
https://prod-nginz-https.wire.com/login
I wasn't able to login on staging url. Sorry for such stupid questions but since there is no official documenation, everything is done by try and check methods
The error says "missing cookie", so my guess would be... to check cookies :stuck_out_tongue_winking_eye:
I think you can configure curl to print all received cookies from the /login request, as well as send cookies to the /access request. Give it a try 🙂
Staging is a testing infrastructure, it runs against a different database which doesn't have your user. Use production URL 🙂
Yes, I tried /cookies too but then getting Authorization Required. But you are probably right, I have to pass cookies from login request, that has sense. Let me check this, I'm not using curl anymore but native HTTP component in my test app
Yep, now /access works but getting same json as in /login:
{"expires_in":900,"access_token":"blabla","user":"blabla","token_type":"Bearer"}
but of course with different values. Seems that request for /access is not necessary after login. It looks like /access is some kind of request for regenerate token. Hmmm, so seems that is all, I have everything what is needed. I have to now pass somehow token to websocket listener, no? Do you see any javascript code responsible for that?
You might also want to check those (instead of doing things manually):
https://github.com/wireapp/wire-web-packages/tree/master/packages/core
https://github.com/wireapp/wire-web-packages/tree/master/packages/api-client
Hi @dibok, happy to see that you are interested in building your own Wire client! 👍
To get things started I highly recommend (as @lipis already suggested) to use our API Client or our Web Core (which connects pure backend API calls with Cryptobox.js, our end-to-end encryption layer).
You can also have a look at our minimal command-line interface. It demonstrates really well how to send and receive messages. Just ping back, if you have further questions!
Hmm, not sure how to handle these links, must review them first. My goal is to make totally native desktop app without using any browser, electron or javascript engine behind, just pure tiny C++ or Free Pascal (didn't decided yet) binary with native OS widgetsets. So I guess I have to do this on lower layer by HTTP requests and websockets or with some kind of wrapper arround it. Maybe these command line interface is what I'm looking for? I could run and manage it as subprocess of my base app
If you want to build a native client (without any JavaScript involved), then you are better off with coax. Best is to ask in the coax repo for help.
Regarding the endpoints, you definetly need to connect to the following URLs:
https://prod-nginz-https.wire.comwss://prod-nginz-ssl.wire.comYes, I'm also looking at coax source but Rest language is totally new for me so it is taking some time. The worst part is authorisation, I mean REST requests order to get some things which I have to pass to websocket listener and make it working (and make it stable in case of password change or token expire). Then I think It will be downhill because wire JSON protocol messaging looks quite clear. Thanks guys for your help! And please let me know if something new came to your mind. Regards!
@bennyn BTW, you mentioned that URL for websocket is prod-nginz-ssl.wire.com but in coax source I see prod-nginz-ssl.wire.com/await. So which one is correct? Also, how to pass token to websocket? By header or by prod-nginz-ssl.wire.com?token=....., that is the major puzzler for me which I can't find in coax source
@dibok: Here is some JavaScript code (taken from the API client) which shows how to connect to the WebSocket:
private buildWebSocketURL(accessToken: string = this.client.accessTokenStore.accessToken.access_token): string {
let url = `${this.baseURL}/await?access_token=${accessToken}`;
if (this.clientId) {
// Note: If no client ID is given, then the WebSocket connection will receive all notifications for all clients of the connected user
url += `&client=${this.clientId}`;
}
return url;
}
Grrr still can't estabilish websocket connection. Testing with two different websockets clients. They connect successful on echo.websocket.org but with:
HttpClientWebsockets.Create('prod-nginz-ssl.wire.com/await?access_token='+sToken,'443',TSQLModel.Create([]))
I'm getting connection refused / host not found when try to upgrade connection to websocket. Although, when connected directly on prod-nginz-ssl.wire.com (without any access_token), upgrade to websocket work but diagnostic method Client.ServerTimeStampSynchronize fail. Have few questions:
/login or the one from /access?Authorisation: header? Cookies?access_token='+sToken be as raw string or should be base64 encoded?Sec-WebSocket-Key important? I'm sending random keyBTW: just locked my account:
{"code":429,"message":"Logins too frequent","label":"client-error"}
How long I have to wait?
@bennyn @maximbaz ?
Hi @dibok, the Logins too frequent error will block you for 24 hours. After that you can reconnect. If you don't want to be rate-limited, you need to logout before logging back in.
For the WebSocket connection you need to supply the Bearer token. You get that on the access call but don't forget to refresh it every 15 minutes (the exact time will be told when you receive the token).
For Logins too frequent - can I logout now using API or it is too late?
For the WebSocket connection you need to supply the Bearer token. You get that on the access call but don't forget to refresh it every 15 minutes (the exact time will be told when you receive the token)
Yes and this is what I actually do. My steps:
/login by POST command and getting access_token and saving cookies/access by POST, sending cookies and access_token as Authorisation: header from point 1 . Saving again retrieved access_token and cookies (they are different than in point 1)prod-nginz-ssl.wire.com/await?access_token=<access_token from point 2> on port 443connection refused / host not found (depending on which socket client I'm testing).access_token as raw string looks like a mess, I don't think so that I should send it as it is in URL, I think I need to first gzip it or encode to base 64 or encode to URL or both. Tried these prod-nginz-ssl.wire.com/await?access_token=+EncodeBase64(sTokenVar) and prod-nginz-ssl.wire.com/await?access_token=+EncodeURL(sTokenVar) but noticed that my account is locked so I don't know if they worked or not. Seems that I have to wait until tomorrow@bennyn . Sorry for direct calling in separate post. This topic is closed so I'm not sure if members are getting notifications
@bennyn @maximbaz . My account is unlocked, giving another try. I think that I need to register my client posting to /clients so I can send it to websocket URL as javascript do next to access_token:
// Note: If no client ID is given, then the WebSocket connection will receive all notifications for all clients of the connected user
url += `&client=${this.clientId}`;
But I'm getting 415 Unsupported Media Type
I'm sending in headers Authorization: Bearer <token from /access>, Accept: application/json and Content-type: application/json. What else is needed? Is it possible that User-Agent is not accepted?
Or maybe I have to do something with user :{} field retrieved in /login or /access?
No, I definitely have to send something in content to /clients. With empty content I'm getting 415 Unsupported Media Type, with enything else, even blablabla I'm getting 400 Bad Request. So it has to be some fixed payload, very possibly in JSON format, json retrieved by /access (I mean { "expires_in" : 900, "access_token" : "xxx", "user" : "xxx", "token_type" : "Bearer" } ) is not acceptable neither. This rest code from coax is illegible for me:
/// Register a new client [`POST /clients`].
pub fn client_register<'b>(&mut self, p: &client::register::Params, t: &AccessToken) -> Result<ApiClient<'b>, Error<client::register::Error>> {
info!(self.log, "registering client");
self.url.set_path("/clients");
let hdrs = &[(AUTHORIZATION, Value::new(t.bearer.as_bytes()))];
let tkn = self.tkn.take().ok_or(Error::InvalidState)?;
let tkn = self.rpc.send_json(tkn, Method::Post, &self.url, hdrs, p)?;
let tkn = self.rpc.recv_header(tkn)?;
let json_resp = is_json(self.response());
match self.response().status() {
201 if json_resp => Ok(self.recv_json(tkn)?),
num if json_resp => {
let e: ApiError = self.recv_json(tkn)?;
error!(self.log, "client registration error"; "status" => num, "error" => ?e);
Err(Error::Error(e.into()))
}
num => {
let e = self.error_response(tkn, json_resp)?;
error!(self.log, "client registration error"; "status" => num, "error" => ?e);
Err(e)
}
}
}
Ok, in ClientRepository.js I found that payload for /clients registration is:
return {
class: 'desktop',
cookie: this._get_cookie_label_value(this.self_user().email() || this.self_user().phone()),
label: device_label,
lastkey: last_resort_key,
model: device_model,
password: password,
prekeys: pre_keys,
sigkeys: signaling_keys,
type: client_type,
};
I'll dig and test more tomorrow but what I can say now, new "unknown" things for me is prekeys and sigkeys
@dibok Great to see that you are progressing but keep in mind that this is an issue tracker and not a support forum. At this moment we cannot offer much support for custom client creation. Documentation of our API is something that is coming in the future. If you want to be notified about it, check here from time to time: https://wire.com/developers/
Most helpful comment
You might also want to check those (instead of doing things manually):
https://github.com/wireapp/wire-web-packages/tree/master/packages/core
https://github.com/wireapp/wire-web-packages/tree/master/packages/api-client