Merge lp:~chipaca/ubuntu-push/appname-from-dbus-path into lp:ubuntu-push
- appname-from-dbus-path
- Merge into trunk
Proposed by
John Lenton
Status: | Superseded |
---|---|
Proposed branch: | lp:~chipaca/ubuntu-push/appname-from-dbus-path |
Merge into: | lp:ubuntu-push |
Diff against target: |
1038 lines (+498/-98) 19 files modified
bus/endpoint.go (+4/-4) bus/testing/testing_endpoint_test.go (+1/-1) client/service/service.go (+19/-25) client/service/service_test.go (+16/-39) debian/changelog (+14/-0) debian/rules (+0/-1) nih/nih.go (+1/-1) scripts/register (+43/-0) scripts/unicast (+2/-0) server/acceptance/acceptanceclient.go (+1/-1) server/acceptance/cmd/acceptanceclient.go (+3/-1) server/acceptance/suites/suite.go (+2/-2) server/acceptance/suites/unicast.go (+11/-3) server/api/handlers.go (+104/-8) server/api/handlers_test.go (+193/-2) server/store/inmemory.go (+26/-0) server/store/inmemory_test.go (+44/-0) server/store/store.go (+8/-0) signing-helper/signing-helper.cpp (+6/-10) |
To merge this branch: | bzr merge lp:~chipaca/ubuntu-push/appname-from-dbus-path |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu Push Hackers | Pending | ||
Review via email: mp+222319@code.launchpad.net |
This proposal has been superseded by a proposal from 2014-06-06.
Commit message
switch dbus api to retrieve appname from dbus path
Description of the change
switch dbus api to retrieve appname from dbus path
To post a comment you must log in.
Unmerged revisions
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'bus/endpoint.go' |
2 | --- bus/endpoint.go 2014-05-15 11:28:06 +0000 |
3 | +++ bus/endpoint.go 2014-06-06 12:14:20 +0000 |
4 | @@ -29,7 +29,7 @@ |
5 | * Endpoint (and its implementation) |
6 | */ |
7 | |
8 | -type BusMethod func([]interface{}, []interface{}) ([]interface{}, error) |
9 | +type BusMethod func(string, []interface{}, []interface{}) ([]interface{}, error) |
10 | type DispatchMap map[string]BusMethod |
11 | |
12 | // bus.Endpoint represents the DBus connection itself. |
13 | @@ -249,12 +249,12 @@ |
14 | endp.log.Errorf("WatchMethod: unknown method %s", msg.Member) |
15 | } else { |
16 | args := msg.AllArgs() |
17 | - rvals, err := meth(args, extra) |
18 | + rvals, err := meth(string(msg.Path), args, extra) |
19 | if err != nil { |
20 | reply = dbus.NewErrorMessage(msg, err_iface, err.Error()) |
21 | - endp.log.Errorf("WatchMethod: %s(%#v, %#v) failure: %#v", msg.Member, args, extra, err) |
22 | + endp.log.Errorf("WatchMethod: %s(%v, %#v, %#v) failure: %#v", msg.Member, msg.Path, args, extra, err) |
23 | } else { |
24 | - endp.log.Debugf("WatchMethod: %s(%#v, %#v) success: %#v", msg.Member, args, extra, rvals) |
25 | + endp.log.Debugf("WatchMethod: %s(%v, %#v, %#v) success: %#v", msg.Member, msg.Path, args, extra, rvals) |
26 | reply = dbus.NewMethodReturnMessage(msg) |
27 | err = reply.AppendArgs(rvals...) |
28 | if err != nil { |
29 | |
30 | === modified file 'bus/testing/testing_endpoint_test.go' |
31 | --- bus/testing/testing_endpoint_test.go 2014-06-02 10:04:34 +0000 |
32 | +++ bus/testing/testing_endpoint_test.go 2014-06-06 12:14:20 +0000 |
33 | @@ -229,7 +229,7 @@ |
34 | // Test that WatchMethod updates callArgs |
35 | func (s *TestingEndpointSuite) TestWatchMethodUpdatesCallArgs(c *C) { |
36 | endp := NewTestingEndpoint(nil, condition.Work(true)) |
37 | - foo := func([]interface{}, []interface{}) ([]interface{}, error) { return nil, nil } |
38 | + foo := func(string, []interface{}, []interface{}) ([]interface{}, error) { return nil, nil } |
39 | foomp := bus.DispatchMap{"foo": foo} |
40 | endp.WatchMethod(foomp) |
41 | c.Check(GetCallArgs(endp), DeepEquals, []callArgs{ |
42 | |
43 | === modified file 'client/service/service.go' |
44 | --- client/service/service.go 2014-05-21 10:03:18 +0000 |
45 | +++ client/service/service.go 2014-06-06 12:14:20 +0000 |
46 | @@ -21,10 +21,12 @@ |
47 | import ( |
48 | "errors" |
49 | "os" |
50 | + "strings" |
51 | "sync" |
52 | |
53 | "launchpad.net/ubuntu-push/bus" |
54 | "launchpad.net/ubuntu-push/logger" |
55 | + "launchpad.net/ubuntu-push/nih" |
56 | ) |
57 | |
58 | // Service is the dbus api |
59 | @@ -51,7 +53,7 @@ |
60 | AlreadyStarted = errors.New("already started") |
61 | BusAddress = bus.Address{ |
62 | Interface: "com.ubuntu.PushNotifications", |
63 | - Path: "/com/ubuntu/PushNotifications", |
64 | + Path: "/com/ubuntu/PushNotifications/*", |
65 | Name: "com.ubuntu.PushNotifications", |
66 | } |
67 | ) |
68 | @@ -133,31 +135,26 @@ |
69 | BadArgType = errors.New("Bad argument type") |
70 | ) |
71 | |
72 | -func (svc *Service) register(args []interface{}, _ []interface{}) ([]interface{}, error) { |
73 | - if len(args) != 1 { |
74 | +func (svc *Service) register(path string, args, _ []interface{}) ([]interface{}, error) { |
75 | + if len(args) != 0 { |
76 | return nil, BadArgCount |
77 | } |
78 | - appname, ok := args[0].(string) |
79 | - if !ok { |
80 | - return nil, BadArgType |
81 | - } |
82 | + raw_appname := path[strings.LastIndex(path, "/")+1:] |
83 | + appname := string(nih.Unquote([]byte(raw_appname))) |
84 | |
85 | - rv := os.Getenv("PUSH_REG_" + appname) |
86 | + rv := os.Getenv("PUSH_REG_" + raw_appname) |
87 | if rv == "" { |
88 | - rv = "this-is-an-opaque-block-of-random-bits-i-promise" |
89 | + rv = appname + "::this-is-an-opaque-block-of-random-bits-i-promise" |
90 | } |
91 | |
92 | return []interface{}{rv}, nil |
93 | } |
94 | |
95 | -func (svc *Service) notifications(args []interface{}, _ []interface{}) ([]interface{}, error) { |
96 | - if len(args) != 1 { |
97 | +func (svc *Service) notifications(path string, args, _ []interface{}) ([]interface{}, error) { |
98 | + if len(args) != 0 { |
99 | return nil, BadArgCount |
100 | } |
101 | - appname, ok := args[0].(string) |
102 | - if !ok { |
103 | - return nil, BadArgType |
104 | - } |
105 | + appname := string(nih.Unquote([]byte(path[strings.LastIndex(path, "/")+1:]))) |
106 | |
107 | svc.lock.Lock() |
108 | defer svc.lock.Unlock() |
109 | @@ -171,18 +168,15 @@ |
110 | return []interface{}{msgs}, nil |
111 | } |
112 | |
113 | -func (svc *Service) inject(args []interface{}, _ []interface{}) ([]interface{}, error) { |
114 | - if len(args) != 2 { |
115 | +func (svc *Service) inject(path string, args, _ []interface{}) ([]interface{}, error) { |
116 | + if len(args) != 1 { |
117 | return nil, BadArgCount |
118 | } |
119 | - appname, ok := args[0].(string) |
120 | - if !ok { |
121 | - return nil, BadArgType |
122 | - } |
123 | - notif, ok := args[1].(string) |
124 | - if !ok { |
125 | - return nil, BadArgType |
126 | - } |
127 | + notif, ok := args[0].(string) |
128 | + if !ok { |
129 | + return nil, BadArgType |
130 | + } |
131 | + appname := string(nih.Unquote([]byte(path[strings.LastIndex(path, "/")+1:]))) |
132 | |
133 | return nil, svc.Inject(appname, notif) |
134 | } |
135 | |
136 | === modified file 'client/service/service_test.go' |
137 | --- client/service/service_test.go 2014-05-21 10:05:24 +0000 |
138 | +++ client/service/service_test.go 2014-06-06 12:14:20 +0000 |
139 | @@ -97,23 +97,13 @@ |
140 | // registration tests |
141 | |
142 | func (ss *serviceSuite) TestRegistrationFailsIfBadArgs(c *C) { |
143 | - for i, s := range []struct { |
144 | - args []interface{} |
145 | - errt error |
146 | - }{ |
147 | - {nil, BadArgCount}, // no args |
148 | - {[]interface{}{}, BadArgCount}, // still no args |
149 | - {[]interface{}{42}, BadArgType}, // bad arg type |
150 | - {[]interface{}{1, 2}, BadArgCount}, // too many args |
151 | - } { |
152 | - reg, err := new(Service).register(s.args, nil) |
153 | - c.Check(reg, IsNil, Commentf("iteration #%d", i)) |
154 | - c.Check(err, Equals, s.errt, Commentf("iteration #%d", i)) |
155 | - } |
156 | + reg, err := new(Service).register("", []interface{}{1}, nil) |
157 | + c.Check(reg, IsNil) |
158 | + c.Check(err, Equals, BadArgCount) |
159 | } |
160 | |
161 | func (ss *serviceSuite) TestRegistrationWorks(c *C) { |
162 | - reg, err := new(Service).register([]interface{}{"this"}, nil) |
163 | + reg, err := new(Service).register("/this", nil, nil) |
164 | c.Assert(reg, HasLen, 1) |
165 | regs, ok := reg[0].(string) |
166 | c.Check(ok, Equals, true) |
167 | @@ -125,7 +115,7 @@ |
168 | os.Setenv("PUSH_REG_stuff", "42") |
169 | defer os.Setenv("PUSH_REG_stuff", "") |
170 | |
171 | - reg, err := new(Service).register([]interface{}{"stuff"}, nil) |
172 | + reg, err := new(Service).register("/stuff", nil, nil) |
173 | c.Assert(reg, HasLen, 1) |
174 | regs, ok := reg[0].(string) |
175 | c.Check(ok, Equals, true) |
176 | @@ -138,10 +128,10 @@ |
177 | |
178 | func (ss *serviceSuite) TestInjectWorks(c *C) { |
179 | svc := NewService(ss.bus, ss.log) |
180 | - rvs, err := svc.inject([]interface{}{"hello", "world"}, nil) |
181 | + rvs, err := svc.inject("/hello", []interface{}{"world"}, nil) |
182 | c.Assert(err, IsNil) |
183 | c.Check(rvs, IsNil) |
184 | - rvs, err = svc.inject([]interface{}{"hello", "there"}, nil) |
185 | + rvs, err = svc.inject("/hello", []interface{}{"there"}, nil) |
186 | c.Assert(err, IsNil) |
187 | c.Check(rvs, IsNil) |
188 | c.Assert(svc.mbox, HasLen, 1) |
189 | @@ -162,7 +152,7 @@ |
190 | condition.Work(false)) |
191 | svc := NewService(bus, ss.log) |
192 | svc.SetMessageHandler(func([]byte) error { return errors.New("fail") }) |
193 | - _, err := svc.inject([]interface{}{"hello", "xyzzy"}, nil) |
194 | + _, err := svc.inject("/hello", []interface{}{"xyzzy"}, nil) |
195 | c.Check(err, NotNil) |
196 | } |
197 | |
198 | @@ -173,13 +163,10 @@ |
199 | }{ |
200 | {nil, BadArgCount}, |
201 | {[]interface{}{}, BadArgCount}, |
202 | - {[]interface{}{1}, BadArgCount}, |
203 | - {[]interface{}{1, 2}, BadArgType}, |
204 | - {[]interface{}{"1", 2}, BadArgType}, |
205 | - {[]interface{}{1, "2"}, BadArgType}, |
206 | - {[]interface{}{1, 2, 3}, BadArgCount}, |
207 | + {[]interface{}{1}, BadArgType}, |
208 | + {[]interface{}{1, 2}, BadArgCount}, |
209 | } { |
210 | - reg, err := new(Service).inject(s.args, nil) |
211 | + reg, err := new(Service).inject("", s.args, nil) |
212 | c.Check(reg, IsNil, Commentf("iteration #%d", i)) |
213 | c.Check(err, Equals, s.errt, Commentf("iteration #%d", i)) |
214 | } |
215 | @@ -189,7 +176,7 @@ |
216 | // Notifications tests |
217 | func (ss *serviceSuite) TestNotificationsWorks(c *C) { |
218 | svc := NewService(ss.bus, ss.log) |
219 | - nots, err := svc.notifications([]interface{}{"hello"}, nil) |
220 | + nots, err := svc.notifications("/hello", nil, nil) |
221 | c.Assert(err, IsNil) |
222 | c.Assert(nots, NotNil) |
223 | c.Assert(nots, HasLen, 1) |
224 | @@ -198,7 +185,7 @@ |
225 | svc.mbox = make(map[string][]string) |
226 | } |
227 | svc.mbox["hello"] = append(svc.mbox["hello"], "this", "thing") |
228 | - nots, err = svc.notifications([]interface{}{"hello"}, nil) |
229 | + nots, err = svc.notifications("/hello", nil, nil) |
230 | c.Assert(err, IsNil) |
231 | c.Assert(nots, NotNil) |
232 | c.Assert(nots, HasLen, 1) |
233 | @@ -206,19 +193,9 @@ |
234 | } |
235 | |
236 | func (ss *serviceSuite) TestNotificationsFailsIfBadArgs(c *C) { |
237 | - for i, s := range []struct { |
238 | - args []interface{} |
239 | - errt error |
240 | - }{ |
241 | - {nil, BadArgCount}, // no args |
242 | - {[]interface{}{}, BadArgCount}, // still no args |
243 | - {[]interface{}{42}, BadArgType}, // bad arg type |
244 | - {[]interface{}{1, 2}, BadArgCount}, // too many args |
245 | - } { |
246 | - reg, err := new(Service).notifications(s.args, nil) |
247 | - c.Check(reg, IsNil, Commentf("iteration #%d", i)) |
248 | - c.Check(err, Equals, s.errt, Commentf("iteration #%d", i)) |
249 | - } |
250 | + reg, err := new(Service).notifications("/foo", []interface{}{1}, nil) |
251 | + c.Check(reg, IsNil) |
252 | + c.Check(err, Equals, BadArgCount) |
253 | } |
254 | |
255 | func (ss *serviceSuite) TestMessageHandler(c *C) { |
256 | |
257 | === modified file 'debian/changelog' |
258 | --- debian/changelog 2014-06-05 09:42:22 +0000 |
259 | +++ debian/changelog 2014-06-06 12:14:20 +0000 |
260 | @@ -1,3 +1,17 @@ |
261 | +ubuntu-push (0.31ubuntu1) UNRELEASED; urgency=medium |
262 | + |
263 | + [ Samuele Pedroni ] |
264 | + * Support registering tokens and sending notifications with a token |
265 | + * Register script and scripts unicast support |
266 | + |
267 | + [ Roberto Alsina ] |
268 | + * Make signing-helper generate a HTTP header instead of a querystring. |
269 | + |
270 | + [ John R. Lenton ] |
271 | + * Switch dbus api to retrieve app name from dbus path. |
272 | + |
273 | + -- John R. Lenton <john.lenton@canonical.com> Fri, 06 Jun 2014 12:02:56 +0100 |
274 | + |
275 | ubuntu-push (0.3+14.10.20140605-0ubuntu1) utopic; urgency=medium |
276 | |
277 | [ John Lenton ] |
278 | |
279 | === modified file 'debian/rules' |
280 | --- debian/rules 2014-05-02 12:42:27 +0000 |
281 | +++ debian/rules 2014-06-06 12:14:20 +0000 |
282 | @@ -5,7 +5,6 @@ |
283 | export UBUNTU_PUSH_TEST_RESOURCES_ROOT := $(CURDIR) |
284 | |
285 | override_dh_auto_build: |
286 | - cd $$( find ./ -type d -regex '\./[^/]*/src/launchpad.net' -printf "%h\n" | head -n1) |
287 | dh_auto_build --buildsystem=golang |
288 | (cd signing-helper && cmake . && make) |
289 | |
290 | |
291 | === modified file 'nih/nih.go' |
292 | --- nih/nih.go 2014-05-23 12:56:27 +0000 |
293 | +++ nih/nih.go 2014-06-06 12:14:20 +0000 |
294 | @@ -45,7 +45,7 @@ |
295 | return out |
296 | } |
297 | |
298 | -// Quote() takes a byte slice and undoes the damage done to it by the quoting. |
299 | +// Unquote() takes a byte slice and undoes the damage done to it by Quote(). |
300 | func Unquote(s []byte) []byte { |
301 | out := make([]byte, 0, len(s)) |
302 | |
303 | |
304 | === added file 'scripts/register' |
305 | --- scripts/register 1970-01-01 00:00:00 +0000 |
306 | +++ scripts/register 2014-06-06 12:14:20 +0000 |
307 | @@ -0,0 +1,43 @@ |
308 | +#!/usr/bin/python3 |
309 | +""" |
310 | +request a unicast registration |
311 | +""" |
312 | +import argparse |
313 | +import json |
314 | +import requests |
315 | +import subprocess |
316 | +import datetime |
317 | +import sys |
318 | + |
319 | + |
320 | +def main(): |
321 | + parser = argparse.ArgumentParser(description=__doc__) |
322 | + parser.add_argument('deviceid', nargs=1) |
323 | + parser.add_argument('appid', nargs=1) |
324 | + parser.add_argument('-H', '--host', |
325 | + help="host:port (default: %(default)s)", |
326 | + default="localhost:8080") |
327 | + parser.add_argument('--no-https', action='store_true', default=False) |
328 | + parser.add_argument('--insecure', action='store_true', default=False, |
329 | + help="don't check host/certs with https") |
330 | + parser.add_argument('--auth_helper', default="") |
331 | + args = parser.parse_args() |
332 | + scheme = 'https' |
333 | + if args.no_https: |
334 | + scheme = 'http' |
335 | + url = "%s://%s/register" % (scheme, args.host) |
336 | + body = { |
337 | + 'deviceid': args.deviceid[0], |
338 | + 'appid': args.appid[0], |
339 | + } |
340 | + headers = {'Content-Type': 'application/json'} |
341 | + if args.auth_helper: |
342 | + auth = subprocess.check_output([args.auth_helper, url]).strip() |
343 | + headers['Authorization'] = auth |
344 | + r = requests.post(url, data=json.dumps(body), headers=headers, |
345 | + verify=not args.insecure) |
346 | + print(r.status_code) |
347 | + print(r.text) |
348 | + |
349 | +if __name__ == '__main__': |
350 | + main() |
351 | |
352 | === modified file 'scripts/unicast' |
353 | --- scripts/unicast 2014-05-29 14:55:19 +0000 |
354 | +++ scripts/unicast 2014-06-06 12:14:20 +0000 |
355 | @@ -52,6 +52,8 @@ |
356 | userid, devid = reg.split(':', 1) |
357 | body['userid'] = userid |
358 | body['deviceid'] = devid |
359 | + else: |
360 | + body['token'] = reg |
361 | xauth = {} |
362 | if args.user and args.password: |
363 | xauth = {'auth': requests.auth.HTTPBasicAuth(args.user, args.password)} |
364 | |
365 | === modified file 'server/acceptance/acceptanceclient.go' |
366 | --- server/acceptance/acceptanceclient.go 2014-05-23 12:30:32 +0000 |
367 | +++ server/acceptance/acceptanceclient.go 2014-06-06 12:14:20 +0000 |
368 | @@ -155,7 +155,7 @@ |
369 | return err |
370 | } |
371 | events <- fmt.Sprintf("%sbroadcast chan:%v app:%v topLevel:%d payloads:%s", sess.Prefix, recv.ChanId, recv.AppId, recv.TopLevel, pack) |
372 | - case "connwarn": |
373 | + case "warn", "connwarn": |
374 | events <- fmt.Sprintf("%sconnwarn %s", sess.Prefix, recv.Reason) |
375 | } |
376 | } |
377 | |
378 | === modified file 'server/acceptance/cmd/acceptanceclient.go' |
379 | --- server/acceptance/cmd/acceptanceclient.go 2014-05-21 07:58:26 +0000 |
380 | +++ server/acceptance/cmd/acceptanceclient.go 2014-06-06 12:14:20 +0000 |
381 | @@ -90,7 +90,9 @@ |
382 | } |
383 | } |
384 | if len(cfg.AuthHelper) != 0 { |
385 | - auth, err := exec.Command(cfg.AuthHelper[0], cfg.AuthHelper[1:]...).Output() |
386 | + helperArgs := cfg.AuthHelper[1:] |
387 | + helperArgs = append(helperArgs, "https://push.ubuntu.com/") |
388 | + auth, err := exec.Command(cfg.AuthHelper[0], helperArgs...).Output() |
389 | if err != nil { |
390 | log.Fatalf("auth helper: %v", err) |
391 | } |
392 | |
393 | === modified file 'server/acceptance/suites/suite.go' |
394 | --- server/acceptance/suites/suite.go 2014-05-02 09:56:49 +0000 |
395 | +++ server/acceptance/suites/suite.go 2014-06-06 12:14:20 +0000 |
396 | @@ -89,7 +89,7 @@ |
397 | // to kill the server process |
398 | KillGroup map[string]func(os.Signal) |
399 | // hook to adjust requests |
400 | - MassageRequest func(req *http.Request) *http.Request |
401 | + MassageRequest func(req *http.Request, message interface{}) *http.Request |
402 | // other state |
403 | httpClient *http.Client |
404 | } |
405 | @@ -124,7 +124,7 @@ |
406 | request.Header.Set("Content-Type", "application/json") |
407 | |
408 | if s.MassageRequest != nil { |
409 | - request = s.MassageRequest(request) |
410 | + request = s.MassageRequest(request, message) |
411 | } |
412 | |
413 | resp, err := s.httpClient.Do(request) |
414 | |
415 | === modified file 'server/acceptance/suites/unicast.go' |
416 | --- server/acceptance/suites/unicast.go 2014-05-15 16:41:54 +0000 |
417 | +++ server/acceptance/suites/unicast.go 2014-06-06 12:14:20 +0000 |
418 | @@ -40,11 +40,19 @@ |
419 | } |
420 | |
421 | func (s *UnicastAcceptanceSuite) TestUnicastToConnected(c *C) { |
422 | - userId, auth := s.associatedAuth("DEV1") |
423 | + _, auth := s.associatedAuth("DEV1") |
424 | + res, err := s.PostRequest("/register", &api.Registration{ |
425 | + DeviceId: "DEV1", |
426 | + AppId: "app1", |
427 | + }) |
428 | + c.Assert(err, IsNil) |
429 | + c.Assert(res, Matches, ".*ok.*") |
430 | + var reg map[string]interface{} |
431 | + err = json.Unmarshal([]byte(res), ®) |
432 | + c.Assert(err, IsNil) |
433 | events, errCh, stop := s.StartClientAuth(c, "DEV1", nil, auth) |
434 | got, err := s.PostRequest("/notify", &api.Unicast{ |
435 | - UserId: userId, |
436 | - DeviceId: "DEV1", |
437 | + Token: reg["token"].(string), |
438 | AppId: "app1", |
439 | ExpireOn: future, |
440 | Data: json.RawMessage(`{"a": 42}`), |
441 | |
442 | === modified file 'server/api/handlers.go' |
443 | --- server/api/handlers.go 2014-05-29 16:22:00 +0000 |
444 | +++ server/api/handlers.go 2014-06-06 12:14:20 +0000 |
445 | @@ -51,6 +51,8 @@ |
446 | ioError = "io-error" |
447 | invalidRequest = "invalid-request" |
448 | unknownChannel = "unknown-channel" |
449 | + unknownToken = "unknown-token" |
450 | + unauthorized = "unauthorized" |
451 | unavailable = "unavailable" |
452 | internalError = "internal" |
453 | ) |
454 | @@ -121,6 +123,11 @@ |
455 | unknownChannel, |
456 | "Unknown channel", |
457 | } |
458 | + ErrUnknownToken = &APIError{ |
459 | + http.StatusBadRequest, |
460 | + unknownToken, |
461 | + "Unknown token", |
462 | + } |
463 | ErrUnknown = &APIError{ |
464 | http.StatusInternalServerError, |
465 | internalError, |
466 | @@ -136,16 +143,33 @@ |
467 | unavailable, |
468 | "Could not store notification", |
469 | } |
470 | + ErrCouldNotMakeToken = &APIError{ |
471 | + http.StatusServiceUnavailable, |
472 | + unavailable, |
473 | + "Could not make token", |
474 | + } |
475 | + ErrCouldNotResolveToken = &APIError{ |
476 | + http.StatusServiceUnavailable, |
477 | + unavailable, |
478 | + "Could not resolve token", |
479 | + } |
480 | + ErrUnauthorized = &APIError{ |
481 | + http.StatusUnauthorized, |
482 | + unauthorized, |
483 | + "Unauthorized", |
484 | + } |
485 | ) |
486 | |
487 | -type castCommon struct { |
488 | +type Registration struct { |
489 | + DeviceId string `json:"deviceid"` |
490 | + AppId string `json:"appid"` |
491 | } |
492 | |
493 | type Unicast struct { |
494 | + Token string `json:"token"` |
495 | UserId string `json:"userid"` |
496 | DeviceId string `json:"deviceid"` |
497 | AppId string `json:"appid"` |
498 | - //Registration string `json:"registration"` |
499 | //CoalesceTag string `json:"coalesce_tag"` |
500 | ExpireOn string `json:"expire_on"` |
501 | Data json.RawMessage `json:"data"` |
502 | @@ -183,15 +207,15 @@ |
503 | } |
504 | |
505 | func checkRequestAsPost(request *http.Request, maxBodySize int64) *APIError { |
506 | + if request.Method != "POST" { |
507 | + return ErrWrongRequestMethod |
508 | + } |
509 | if err := checkContentLength(request, maxBodySize); err != nil { |
510 | return err |
511 | } |
512 | if request.Header.Get("Content-Type") != JSONMediaType { |
513 | return ErrWrongContentType |
514 | } |
515 | - if request.Method != "POST" { |
516 | - return ErrWrongRequestMethod |
517 | - } |
518 | return nil |
519 | } |
520 | |
521 | @@ -325,7 +349,10 @@ |
522 | } |
523 | |
524 | func checkUnicast(ucast *Unicast) (time.Time, *APIError) { |
525 | - if ucast.UserId == "" || ucast.DeviceId == "" || ucast.AppId == "" { |
526 | + if ucast.AppId == "" { |
527 | + return zeroTime, ErrMissingIdField |
528 | + } |
529 | + if ucast.Token == "" && (ucast.UserId == "" || ucast.DeviceId == "") { |
530 | return zeroTime, ErrMissingIdField |
531 | } |
532 | return checkCastCommon(ucast.Data, ucast.ExpireOn) |
533 | @@ -341,9 +368,21 @@ |
534 | if apiErr != nil { |
535 | return apiErr |
536 | } |
537 | - chanId := store.UnicastInternalChannelId(ucast.UserId, ucast.DeviceId) |
538 | + chanId, err := sto.GetInternalChannelIdFromToken(ucast.Token, ucast.AppId, ucast.UserId, ucast.DeviceId) |
539 | + if err != nil { |
540 | + switch err { |
541 | + case store.ErrUnknownToken: |
542 | + return ErrUnknownToken |
543 | + case store.ErrUnauthorized: |
544 | + return ErrUnauthorized |
545 | + default: |
546 | + h.logger.Errorf("could not resolve token: %v", err) |
547 | + return ErrCouldNotResolveToken |
548 | + } |
549 | + } |
550 | + |
551 | msgId := generateMsgId() |
552 | - err := sto.AppendToUnicastChannel(chanId, ucast.AppId, ucast.Data, msgId, expire) |
553 | + err = sto.AppendToUnicastChannel(chanId, ucast.AppId, ucast.Data, msgId, expire) |
554 | if err != nil { |
555 | h.logger.Errorf("could not store notification: %v", err) |
556 | return ErrCouldNotStoreNotification |
557 | @@ -378,6 +417,62 @@ |
558 | fmt.Fprintf(writer, `{"ok":true}`) |
559 | } |
560 | |
561 | +type RegisterHandler struct { |
562 | + *context |
563 | +} |
564 | + |
565 | +func checkRegister(reg *Registration) *APIError { |
566 | + if reg.DeviceId == "" || reg.AppId == "" { |
567 | + return ErrMissingIdField |
568 | + } |
569 | + return nil |
570 | +} |
571 | + |
572 | +func (h *RegisterHandler) doRegister(sto store.PendingStore, reg *Registration) (string, *APIError) { |
573 | + apiErr := checkRegister(reg) |
574 | + if apiErr != nil { |
575 | + return "", apiErr |
576 | + } |
577 | + token, err := sto.Register(reg.DeviceId, reg.AppId) |
578 | + if err != nil { |
579 | + h.logger.Errorf("could not make a token: %v", err) |
580 | + return "", ErrCouldNotMakeToken |
581 | + } |
582 | + return token, nil |
583 | +} |
584 | + |
585 | +func (h *RegisterHandler) ServeHTTP(writer http.ResponseWriter, request *http.Request) { |
586 | + var apiErr *APIError |
587 | + defer func() { |
588 | + if apiErr != nil { |
589 | + RespondError(writer, apiErr) |
590 | + } |
591 | + }() |
592 | + |
593 | + reg := &Registration{} |
594 | + |
595 | + sto, apiErr := h.prepare(writer, request, reg) |
596 | + if apiErr != nil { |
597 | + return |
598 | + } |
599 | + defer sto.Close() |
600 | + |
601 | + token, apiErr := h.doRegister(sto, reg) |
602 | + if apiErr != nil { |
603 | + return |
604 | + } |
605 | + |
606 | + writer.Header().Set("Content-Type", "application/json") |
607 | + res, err := json.Marshal(map[string]interface{}{ |
608 | + "ok": true, |
609 | + "token": token, |
610 | + }) |
611 | + if err != nil { |
612 | + panic(fmt.Errorf("couldn't marshal our own response: %v", err)) |
613 | + } |
614 | + writer.Write(res) |
615 | +} |
616 | + |
617 | // MakeHandlersMux makes a handler that dispatches for the various API endpoints. |
618 | func MakeHandlersMux(storeForRequest StoreForRequest, broker broker.BrokerSending, logger logger.Logger) *http.ServeMux { |
619 | ctx := &context{ |
620 | @@ -388,5 +483,6 @@ |
621 | mux := http.NewServeMux() |
622 | mux.Handle("/broadcast", &BroadcastHandler{context: ctx}) |
623 | mux.Handle("/notify", &UnicastHandler{context: ctx}) |
624 | + mux.Handle("/register", &RegisterHandler{context: ctx}) |
625 | return mux |
626 | } |
627 | |
628 | === modified file 'server/api/handlers_test.go' |
629 | --- server/api/handlers_test.go 2014-05-01 18:58:16 +0000 |
630 | +++ server/api/handlers_test.go 2014-06-06 12:14:20 +0000 |
631 | @@ -192,6 +192,16 @@ |
632 | intercept func(meth string, err error) error |
633 | } |
634 | |
635 | +func (isto *interceptInMemoryPendingStore) Register(appId, deviceId string) (string, error) { |
636 | + token, err := isto.InMemoryPendingStore.Register(appId, deviceId) |
637 | + return token, isto.intercept("Register", err) |
638 | +} |
639 | + |
640 | +func (isto *interceptInMemoryPendingStore) GetInternalChannelIdFromToken(token, appId, userId, deviceId string) (store.InternalChannelId, error) { |
641 | + chanId, err := isto.InMemoryPendingStore.GetInternalChannelIdFromToken(token, appId, userId, deviceId) |
642 | + return chanId, isto.intercept("GetInternalChannelIdFromToken", err) |
643 | +} |
644 | + |
645 | func (isto *interceptInMemoryPendingStore) GetInternalChannelId(channel string) (store.InternalChannelId, error) { |
646 | chanId, err := isto.InMemoryPendingStore.GetInternalChannelId(channel) |
647 | return chanId, isto.intercept("GetInternalChannelId", err) |
648 | @@ -262,6 +272,14 @@ |
649 | |
650 | u = unicast() |
651 | u.UserId = "" |
652 | + u.DeviceId = "" |
653 | + u.Token = "TOKEN" |
654 | + expire, apiErr = checkUnicast(u) |
655 | + c.Assert(apiErr, IsNil) |
656 | + c.Check(expire.Format(time.RFC3339), Equals, future) |
657 | + |
658 | + u = unicast() |
659 | + u.UserId = "" |
660 | expire, apiErr = checkUnicast(u) |
661 | c.Check(apiErr, Equals, ErrMissingIdField) |
662 | |
663 | @@ -353,6 +371,40 @@ |
664 | c.Check(s.testlog.Captured(), Equals, "ERROR could not store notification: fail\n") |
665 | } |
666 | |
667 | +func (s *handlersSuite) TestDoUnicastFromTokenFailures(c *C) { |
668 | + fail := errors.New("fail") |
669 | + sto := &interceptInMemoryPendingStore{ |
670 | + store.NewInMemoryPendingStore(), |
671 | + func(meth string, err error) error { |
672 | + if meth == "GetInternalChannelIdFromToken" { |
673 | + return fail |
674 | + } |
675 | + return err |
676 | + }, |
677 | + } |
678 | + ctx := &context{logger: s.testlog} |
679 | + bh := &UnicastHandler{ctx} |
680 | + u := &Unicast{ |
681 | + Token: "tok", |
682 | + AppId: "app1", |
683 | + ExpireOn: future, |
684 | + Data: json.RawMessage(`{"a": 1}`), |
685 | + } |
686 | + apiErr := bh.doUnicast(sto, u) |
687 | + c.Check(apiErr, Equals, ErrCouldNotResolveToken) |
688 | + c.Check(s.testlog.Captured(), Equals, "ERROR could not resolve token: fail\n") |
689 | + s.testlog.ResetCapture() |
690 | + |
691 | + fail = store.ErrUnknownToken |
692 | + apiErr = bh.doUnicast(sto, u) |
693 | + c.Check(apiErr, Equals, ErrUnknownToken) |
694 | + c.Check(s.testlog.Captured(), Equals, "") |
695 | + fail = store.ErrUnauthorized |
696 | + apiErr = bh.doUnicast(sto, u) |
697 | + c.Check(apiErr, Equals, ErrUnauthorized) |
698 | + c.Check(s.testlog.Captured(), Equals, "") |
699 | +} |
700 | + |
701 | func newPostRequest(path string, message interface{}, server *httptest.Server) *http.Request { |
702 | packedMessage, err := json.Marshal(message) |
703 | if err != nil { |
704 | @@ -427,7 +479,7 @@ |
705 | dest := make(map[string]bool) |
706 | err = json.Unmarshal(body, &dest) |
707 | c.Assert(err, IsNil) |
708 | - c.Check(dest, DeepEquals, map[string]bool{"ok": true}) |
709 | + c.Assert(dest, DeepEquals, map[string]bool{"ok": true}) |
710 | |
711 | top, _, err := sto.GetChannelSnapshot(store.SystemInternalChannelId) |
712 | c.Assert(err, IsNil) |
713 | @@ -639,7 +691,7 @@ |
714 | c.Check(response.Header.Get("Content-Type"), Equals, "application/json") |
715 | body, err := getResponseBody(response) |
716 | c.Assert(err, IsNil) |
717 | - c.Check(string(body), Matches, ".*ok.*") |
718 | + c.Assert(string(body), Matches, ".*ok.*") |
719 | |
720 | chanId := store.UnicastInternalChannelId("user2", "dev3") |
721 | c.Check(<-bsend.chanId, Equals, chanId) |
722 | @@ -682,3 +734,142 @@ |
723 | c.Assert(err, IsNil) |
724 | checkError(c, response, ErrMissingIdField) |
725 | } |
726 | + |
727 | +func (s *handlersSuite) TestCheckRegister(c *C) { |
728 | + registration := func() *Registration { |
729 | + return &Registration{ |
730 | + DeviceId: "DEV1", |
731 | + AppId: "app1", |
732 | + } |
733 | + } |
734 | + reg := registration() |
735 | + apiErr := checkRegister(reg) |
736 | + c.Assert(apiErr, IsNil) |
737 | + |
738 | + reg = registration() |
739 | + reg.AppId = "" |
740 | + apiErr = checkRegister(reg) |
741 | + c.Check(apiErr, Equals, ErrMissingIdField) |
742 | + |
743 | + reg = registration() |
744 | + reg.DeviceId = "" |
745 | + apiErr = checkRegister(reg) |
746 | + c.Check(apiErr, Equals, ErrMissingIdField) |
747 | +} |
748 | + |
749 | +func (s *handlersSuite) TestDoRegisterMissingIdField(c *C) { |
750 | + sto := store.NewInMemoryPendingStore() |
751 | + rh := &RegisterHandler{} |
752 | + token, apiErr := rh.doRegister(sto, &Registration{}) |
753 | + c.Check(apiErr, Equals, ErrMissingIdField) |
754 | + c.Check(token, Equals, "") |
755 | +} |
756 | + |
757 | +func (s *handlersSuite) TestDoRegisterCouldNotMakeToken(c *C) { |
758 | + sto := &interceptInMemoryPendingStore{ |
759 | + store.NewInMemoryPendingStore(), |
760 | + func(meth string, err error) error { |
761 | + if meth == "Register" { |
762 | + return errors.New("fail") |
763 | + } |
764 | + return err |
765 | + }, |
766 | + } |
767 | + ctx := &context{logger: s.testlog} |
768 | + rh := &RegisterHandler{ctx} |
769 | + _, apiErr := rh.doRegister(sto, &Registration{ |
770 | + DeviceId: "DEV1", |
771 | + AppId: "app1", |
772 | + }) |
773 | + c.Check(apiErr, Equals, ErrCouldNotMakeToken) |
774 | + c.Check(s.testlog.Captured(), Equals, "ERROR could not make a token: fail\n") |
775 | +} |
776 | + |
777 | +func (s *handlersSuite) TestRespondsToRegisterAndUnicast(c *C) { |
778 | + sto := store.NewInMemoryPendingStore() |
779 | + stoForReq := func(http.ResponseWriter, *http.Request) (store.PendingStore, error) { |
780 | + return sto, nil |
781 | + } |
782 | + bsend := testBrokerSending{make(chan store.InternalChannelId, 1)} |
783 | + testServer := httptest.NewServer(MakeHandlersMux(stoForReq, bsend, nil)) |
784 | + defer testServer.Close() |
785 | + |
786 | + request := newPostRequest("/register", &Registration{ |
787 | + DeviceId: "dev3", |
788 | + AppId: "app2", |
789 | + }, testServer) |
790 | + |
791 | + response, err := s.client.Do(request) |
792 | + c.Assert(err, IsNil) |
793 | + |
794 | + c.Check(response.StatusCode, Equals, http.StatusOK) |
795 | + c.Check(response.Header.Get("Content-Type"), Equals, "application/json") |
796 | + body, err := getResponseBody(response) |
797 | + c.Assert(err, IsNil) |
798 | + c.Assert(string(body), Matches, ".*ok.*") |
799 | + var reg map[string]interface{} |
800 | + err = json.Unmarshal(body, ®) |
801 | + c.Assert(err, IsNil) |
802 | + |
803 | + token, ok := reg["token"].(string) |
804 | + c.Assert(ok, Equals, true) |
805 | + c.Check(token, Not(Equals), nil) |
806 | + |
807 | + payload := json.RawMessage(`{"foo":"bar"}`) |
808 | + |
809 | + request = newPostRequest("/notify", &Unicast{ |
810 | + Token: token, |
811 | + AppId: "app2", |
812 | + ExpireOn: future, |
813 | + Data: payload, |
814 | + }, testServer) |
815 | + |
816 | + response, err = s.client.Do(request) |
817 | + c.Assert(err, IsNil) |
818 | + |
819 | + c.Check(response.StatusCode, Equals, http.StatusOK) |
820 | + c.Check(response.Header.Get("Content-Type"), Equals, "application/json") |
821 | + body, err = getResponseBody(response) |
822 | + c.Assert(err, IsNil) |
823 | + c.Assert(string(body), Matches, ".*ok.*") |
824 | + |
825 | + chanId := store.UnicastInternalChannelId("dev3", "dev3") |
826 | + c.Check(<-bsend.chanId, Equals, chanId) |
827 | + top, notifications, err := sto.GetChannelSnapshot(chanId) |
828 | + c.Assert(err, IsNil) |
829 | + c.Check(top, Equals, int64(0)) |
830 | + c.Check(notifications, HasLen, 1) |
831 | +} |
832 | + |
833 | +func (s *handlersSuite) TestCannotRegisterWithMissingFields(c *C) { |
834 | + stoForReq := func(http.ResponseWriter, *http.Request) (store.PendingStore, error) { |
835 | + return store.NewInMemoryPendingStore(), nil |
836 | + } |
837 | + ctx := &context{stoForReq, nil, nil} |
838 | + testServer := httptest.NewServer(&RegisterHandler{ctx}) |
839 | + defer testServer.Close() |
840 | + |
841 | + request := newPostRequest("/", &Registration{ |
842 | + DeviceId: "DEV1", |
843 | + }, testServer) |
844 | + |
845 | + response, err := s.client.Do(request) |
846 | + c.Assert(err, IsNil) |
847 | + checkError(c, response, ErrMissingIdField) |
848 | +} |
849 | + |
850 | +func (s *handlersSuite) TestCannotRegisterWithNonPOST(c *C) { |
851 | + stoForReq := func(http.ResponseWriter, *http.Request) (store.PendingStore, error) { |
852 | + return store.NewInMemoryPendingStore(), nil |
853 | + } |
854 | + ctx := &context{stoForReq, nil, nil} |
855 | + testServer := httptest.NewServer(&RegisterHandler{ctx}) |
856 | + defer testServer.Close() |
857 | + |
858 | + request, err := http.NewRequest("GET", testServer.URL, nil) |
859 | + c.Assert(err, IsNil) |
860 | + |
861 | + response, err := s.client.Do(request) |
862 | + c.Assert(err, IsNil) |
863 | + checkError(c, response, ErrWrongRequestMethod) |
864 | +} |
865 | |
866 | === modified file 'server/store/inmemory.go' |
867 | --- server/store/inmemory.go 2014-05-02 15:10:18 +0000 |
868 | +++ server/store/inmemory.go 2014-06-06 12:14:20 +0000 |
869 | @@ -17,7 +17,10 @@ |
870 | package store |
871 | |
872 | import ( |
873 | + "encoding/base64" |
874 | "encoding/json" |
875 | + "fmt" |
876 | + "strings" |
877 | "sync" |
878 | "time" |
879 | |
880 | @@ -44,6 +47,29 @@ |
881 | } |
882 | } |
883 | |
884 | +func (sto *InMemoryPendingStore) Register(deviceId, appId string) (string, error) { |
885 | + return base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s::%s", appId, deviceId))), nil |
886 | +} |
887 | + |
888 | +func (sto *InMemoryPendingStore) GetInternalChannelIdFromToken(token, appId, userId, deviceId string) (InternalChannelId, error) { |
889 | + if token != "" && appId != "" { |
890 | + decoded, err := base64.StdEncoding.DecodeString(token) |
891 | + if err != nil { |
892 | + return "", ErrUnknownToken |
893 | + } |
894 | + token = string(decoded) |
895 | + if !strings.HasPrefix(token, appId+"::") { |
896 | + return "", ErrUnauthorized |
897 | + } |
898 | + deviceId := token[len(appId)+2:] |
899 | + return UnicastInternalChannelId(deviceId, deviceId), nil |
900 | + } |
901 | + if userId != "" && deviceId != "" { |
902 | + return UnicastInternalChannelId(userId, deviceId), nil |
903 | + } |
904 | + return "", ErrUnknownToken |
905 | +} |
906 | + |
907 | func (sto *InMemoryPendingStore) GetInternalChannelId(name string) (InternalChannelId, error) { |
908 | if name == "system" { |
909 | return SystemInternalChannelId, nil |
910 | |
911 | === modified file 'server/store/inmemory_test.go' |
912 | --- server/store/inmemory_test.go 2014-04-30 17:44:56 +0000 |
913 | +++ server/store/inmemory_test.go 2014-06-06 12:14:20 +0000 |
914 | @@ -30,6 +30,50 @@ |
915 | |
916 | var _ = Suite(&inMemorySuite{}) |
917 | |
918 | +func (s *inMemorySuite) TestRegister(c *C) { |
919 | + sto := NewInMemoryPendingStore() |
920 | + |
921 | + tok1, err := sto.Register("DEV1", "app1") |
922 | + c.Assert(err, IsNil) |
923 | + tok2, err := sto.Register("DEV1", "app1") |
924 | + c.Assert(err, IsNil) |
925 | + c.Check(len(tok1), Not(Equals), 0) |
926 | + c.Check(tok1, Equals, tok2) |
927 | +} |
928 | + |
929 | +func (s *inMemorySuite) TestGetInternalChannelIdFromToken(c *C) { |
930 | + sto := NewInMemoryPendingStore() |
931 | + |
932 | + tok1, err := sto.Register("DEV1", "app1") |
933 | + c.Assert(err, IsNil) |
934 | + chanId, err := sto.GetInternalChannelIdFromToken(tok1, "app1", "", "") |
935 | + c.Assert(err, IsNil) |
936 | + c.Check(chanId, Equals, UnicastInternalChannelId("DEV1", "DEV1")) |
937 | +} |
938 | + |
939 | +func (s *inMemorySuite) TestGetInternalChannelIdFromTokenFallback(c *C) { |
940 | + sto := NewInMemoryPendingStore() |
941 | + |
942 | + chanId, err := sto.GetInternalChannelIdFromToken("", "app1", "u1", "d1") |
943 | + c.Assert(err, IsNil) |
944 | + c.Check(chanId, Equals, UnicastInternalChannelId("u1", "d1")) |
945 | +} |
946 | + |
947 | +func (s *inMemorySuite) TestGetInternalChannelIdFromTokenErrors(c *C) { |
948 | + sto := NewInMemoryPendingStore() |
949 | + tok1, err := sto.Register("DEV1", "app1") |
950 | + c.Assert(err, IsNil) |
951 | + |
952 | + _, err = sto.GetInternalChannelIdFromToken(tok1, "app2", "", "") |
953 | + c.Assert(err, Equals, ErrUnauthorized) |
954 | + |
955 | + _, err = sto.GetInternalChannelIdFromToken("", "app2", "", "") |
956 | + c.Assert(err, Equals, ErrUnknownToken) |
957 | + |
958 | + _, err = sto.GetInternalChannelIdFromToken("****", "app2", "", "") |
959 | + c.Assert(err, Equals, ErrUnknownToken) |
960 | +} |
961 | + |
962 | func (s *inMemorySuite) TestGetInternalChannelId(c *C) { |
963 | sto := NewInMemoryPendingStore() |
964 | |
965 | |
966 | === modified file 'server/store/store.go' |
967 | --- server/store/store.go 2014-05-02 15:10:18 +0000 |
968 | +++ server/store/store.go 2014-06-06 12:14:20 +0000 |
969 | @@ -52,6 +52,8 @@ |
970 | } |
971 | |
972 | var ErrUnknownChannel = errors.New("unknown channel name") |
973 | +var ErrUnknownToken = errors.New("unknown token") |
974 | +var ErrUnauthorized = errors.New("unauthorized") |
975 | var ErrFull = errors.New("channel is full") |
976 | var ErrExpected128BitsHexRepr = errors.New("expected 128 bits hex repr") |
977 | |
978 | @@ -98,11 +100,17 @@ |
979 | |
980 | // PendingStore let store notifications into channels. |
981 | type PendingStore interface { |
982 | + // Register returns a token for a device id, application id pair. |
983 | + Register(deviceId, appId string) (token string, err error) |
984 | // GetInternalChannelId returns the internal store id for a channel |
985 | // given the name. |
986 | GetInternalChannelId(name string) (InternalChannelId, error) |
987 | // AppendToChannel appends a notification to the channel. |
988 | AppendToChannel(chanId InternalChannelId, notification json.RawMessage, expiration time.Time) error |
989 | + // GetInternalChannelIdFromToken returns the matching internal store |
990 | + // id for a channel given a registered token and application id or |
991 | + // directly a device id, user id pair. |
992 | + GetInternalChannelIdFromToken(token, appId, userId, deviceId string) (InternalChannelId, error) |
993 | // AppendToUnicastChannel appends a notification to the unicast channel. |
994 | // GetChannelSnapshot gets all the current notifications and |
995 | AppendToUnicastChannel(chanId InternalChannelId, appId string, notification json.RawMessage, msgId string, expiration time.Time) error |
996 | |
997 | === modified file 'signing-helper/signing-helper.cpp' |
998 | --- signing-helper/signing-helper.cpp 2014-05-01 10:24:23 +0000 |
999 | +++ signing-helper/signing-helper.cpp 2014-06-06 12:14:20 +0000 |
1000 | @@ -33,6 +33,7 @@ |
1001 | #include <QObject> |
1002 | #include <QString> |
1003 | #include <QTimer> |
1004 | +#include <QUrlQuery> |
1005 | |
1006 | #include "ssoservice.h" |
1007 | #include "token.h" |
1008 | @@ -63,12 +64,8 @@ |
1009 | void SigningExample::handleCredentialsFound(Token token) |
1010 | { |
1011 | qDebug() << "Credentials found, signing url."; |
1012 | - |
1013 | - QString authHeader = token.signUrl(this->url, QStringLiteral("GET"), true); |
1014 | - |
1015 | - std::cout << authHeader.toStdString() << "\n"; |
1016 | + std::cout << token.signUrl(this->url, QStringLiteral("POST")).toStdString(); |
1017 | QCoreApplication::instance()->exit(0); |
1018 | - |
1019 | } |
1020 | |
1021 | void SigningExample::handleCredentialsNotFound() |
1022 | @@ -84,13 +81,12 @@ |
1023 | int main(int argc, char *argv[]) |
1024 | { |
1025 | QCoreApplication a(argc, argv); |
1026 | - |
1027 | - UbuntuOne::SigningExample *example = new UbuntuOne::SigningExample(&a); |
1028 | - |
1029 | + if (argc<2) { |
1030 | + return 2; |
1031 | + } |
1032 | + UbuntuOne::SigningExample *example = new UbuntuOne::SigningExample(&a, argv[1]); |
1033 | QObject::connect(example, SIGNAL(finished()), &a, SLOT(quit())); |
1034 | - |
1035 | QTimer::singleShot(0, example, SLOT(doExample())); |
1036 | - |
1037 | return a.exec(); |
1038 | } |
1039 |