4 import tornado
.httpserver
5 import tornado
.httpclient
as httpclient
9 from rd
import RD
, Link
13 #insert into user (name,email) values('mikael','mikael@frykholm.com');
14 #insert into entry (userid,text) values (1,'My thoughts on ostatus');
15 import tornado
.options
18 "static_path": os
.path
.join(os
.path
.dirname(__file__
), "static"),
19 "cookie_secret": "__TODO:_GENERATE_YOUR_OWN_RANDOM_VALUE_HERE__",
20 "login_url": "/login",
21 "xsrf_cookies": False,
22 "domain":"https://ronin.frykholm.com",
25 class PushHandler(tornado
.web
.RequestHandler
):
26 #curl -v -k "https://ronin.frykholm.com/hub" -d "hub.callback=a" -d "hub.mode=b" -d "hub.topic=c" -d "hub.verify=d"
28 """ Someone wants to subscribe to hub_topic feed"""
29 hub_callback
= self
.get_argument('hub.callback')
30 hub_mode
= self
.get_argument('hub.mode')
31 hub_topic
= self
.get_argument('hub.topic')
32 hub_verify
= self
.get_argument('hub.verify')
33 hub_lease_seconds
= self
.get_argument('hub.lease_seconds','')
34 hub_secret
= self
.get_argument('hub.secret','')
35 hub_verify_token
= self
.get_argument('hub.verify_token','')
36 print(self
.request
.body
)
37 if hub_mode
== 'unsubscribe':
39 path
= hub_topic
.split(self
.settings
['domain'])[1]
40 user
= path
.split('user/')[1]
41 row
= db
.execute("select id from user where name=?",(user
,)).fetchone()
42 expire
= datetime
.datetime
.utcnow() + datetime
.timedelta(seconds
=int(hub_lease_seconds
))
44 db
.execute("INSERT into subscriptions (userid, expires, callback, secret, verified) "
45 "values (?,?,?,?,?)",(row
['id'],expire
,hub_callback
,hub_secret
,False))
48 http_client
= httpclient
.HTTPClient()
50 response
= http_client
.fetch(hub_callback
+"?hub.mode={}&hub.topic={}&hub.secret".format(hub_mode
,hub_topic
,hub_secret
))
52 except httpclient
.HTTPError
as e
:
53 # HTTPError is raised for non-200 responses; the response
54 # can be found in e.response.
55 print("Error: " + str(e
))
56 except Exception as e
:
57 # Other errors are possible, such as IOError.
58 print("Error: " + str(e
))
60 #TODO add secret to outgoing feeds with hmac
62 class XrdHandler(tornado
.web
.RequestHandler
):
64 self
.render("templates/xrd.xml", hostname
="ronin.frykholm.com", url
=self
.settings
['domain'])
66 class FingerHandler(tornado
.web
.RequestHandler
):
68 user
= self
.get_argument('resource')
69 user
= user
.split('acct:')[1]
70 (user
,domain
) = user
.split('@')
71 rows
= db
.execute("select id from user where user.name=?",(user
,)).fetchone()
74 self
.write("Not found")
77 lnk
= Link(rel
='http://spec.example.net/photo/1.0',
79 href
='{}/static/{}.jpg'.format(self
.settings
['domain'],user
))
80 lnk
.titles
.append(('User Photo', 'en'))
81 lnk
.titles
.append(('Benutzerfoto', 'de'))
82 lnk
.properties
.append(('http://spec.example.net/created/1.0', '1970-01-01'))
83 lnk2
= Link(rel
='http://schemas.google.com/g/2010#updates-from',
84 type='application/atom+xml',
85 href
='{}/user/{}'.format(self
.settings
['domain'],user
))
87 rd
= RD(subject
='{}/{}'.format(self
.settings
['domain'],user
))
88 rd
.properties
.append('http://spec.example.net/type/person')
91 self
.write(rd
.to_json())
93 class UserHandler(tornado
.web
.RequestHandler
):
95 entries
= db
.execute("select entry.id,text,ts from user,entry where user.id=entry.userid and user.name=?",(user
,))
96 #import pdb;pdb.set_trace()
97 self
.set_header("Content-Type", 'application/atom+xml')
98 out
= self
.render("templates/feed.xml",
100 feed_url
="{}/user/{}".format(self
.settings
['domain'], user
),
101 hub_url
="{}/hub".format(self
.settings
['domain']),
106 def post(self
, user
):
107 entries
= db
.execute("select entry.id,text,ts from user,entry where user.id=entry.userid and user.name=?",(user
,))
109 self
.set_header("Content-Type", 'application/atom+xml')
110 out
= self
.render_string("templates/feed.xml",
112 feed_url
="{}/user/{}".format(self
.settings
['domain'], user
),
113 hub_url
="{}/hub".format(self
.settings
['domain']),
116 #import pdb;pdb.set_trace()
117 subscribers
= db
.execute("select callback, secret from subscriptions, user where user.id=subscriptions.userid and user.name=?",(user
,))
118 for url
,secret
in subscribers
:
119 digest
= hmac
.new(secret
.encode('utf8'), out
, digestmod
='sha1').hexdigest()
121 req
= httpclient
.HTTPRequest(url
=url
, allow_nonstandard_methods
=True,method
='POST', body
=out
, headers
={"X-Hub-Signature":"sha1={}".format(digest
),"Content-Type": 'application/atom+xml',"Content-Length":len(out
)})
122 apa
= httpclient
.HTTPClient()
125 application
= tornado
.web
.Application([
126 (r
"/.well-known/host-meta", XrdHandler
),
127 (r
"/.well-known/webfinger", FingerHandler
),
128 (r
"/user/(.+)", UserHandler
),
129 (r
"/hub", PushHandler
),
130 ],debug
=True,**settings
)
131 srv
= tornado
.httpserver
.HTTPServer(application
, )
133 print("No db found, creating in {}".format(path
))
134 con
= sqlite3
.connect(path
)
135 con
.execute(""" create table user (id integer primary key,
138 create table entry (id integer primary key,
141 ts timestamp default current_timestamp,
142 FOREIGN KEY(userid) REFERENCES user(id));
143 create table subscriptions (id integer primary key,
149 FOREIGN KEY(userid) REFERENCES user(id));""")
152 if __name__
== "__main__":
153 dbPath
= 'friends.db'
154 tornado
.options
.parse_command_line()
155 if not os
.path
.exists(dbPath
):
157 db
= sqlite3
.connect(dbPath
, detect_types
=sqlite3
.PARSE_DECLTYPES|sqlite3
.PARSE_COLNAMES
)
158 db
.row_factory
= sqlite3
.Row
160 tornado
.ioloop
.IOLoop
.instance().start()