6 import tornado
.httpserver
7 import tornado
.httpclient
as httpclient
11 from rd
import RD
, Link
13 from tornado
.options
import options
, define
16 # insert into user (name,email) values('mikael','mikael@frykholm.com');
17 # insert into entry (userid,text) values (1,'My thoughts on ostatus');
21 "static_path": os
.path
.join(os
.path
.dirname(__file__
), "static"),
22 "cookie_secret": "supersecret123",
23 "login_url": "/login",
24 "xsrf_cookies": False,
25 "domain":"https://ronin.frykholm.com",
29 #curl -v -k "https://ronin.frykholm.com/hub" -d "hub.callback=a" -d "hub.mode=b" -d "hub.topic=c" -d "hub.verify=d"
31 class PushHandler(tornado
.web
.RequestHandler
):
33 """ Someone wants to subscribe to hub_topic feed"""
34 hub_callback
= self
.get_argument('hub.callback')
35 hub_mode
= self
.get_argument('hub.mode')
36 hub_topic
= self
.get_argument('hub.topic')
37 hub_verify
= self
.get_argument('hub.verify')
38 hub_lease_seconds
= self
.get_argument('hub.lease_seconds','')
39 hub_secret
= self
.get_argument('hub.secret','')
40 hub_verify_token
= self
.get_argument('hub.verify_token','')
41 print(self
.request
.body
)
42 if hub_mode
== 'unsubscribe':
44 path
= hub_topic
.split(self
.settings
['domain'])[1]
45 user
= path
.split('user/')[1]
46 row
= db
.execute("select id from user where name=?",(user
,)).fetchone()
47 expire
= datetime
.datetime
.utcnow() + datetime
.timedelta(seconds
=int(hub_lease_seconds
))
49 db
.execute("INSERT into subscriptions (userid, expires, callback, secret, verified) "
50 "values (?,?,?,?,?)",(row
['id'],expire
,hub_callback
,hub_secret
,False))
53 http_client
= httpclient
.HTTPClient()
55 response
= http_client
.fetch(hub_callback
+"?hub.mode={}&hub.topic={}&hub.secret".format(hub_mode
,hub_topic
,hub_secret
))
57 except httpclient
.HTTPError
as e
:
58 # HTTPError is raised for non-200 responses; the response
59 # can be found in e.response.
60 print("Error: " + str(e
))
61 except Exception as e
:
62 # Other errors are possible, such as IOError.
63 print("Error: " + str(e
))
65 #TODO add secret to outgoing feeds with hmac
67 class XrdHandler(tornado
.web
.RequestHandler
):
69 self
.render("templates/xrd.xml", hostname
="ronin.frykholm.com", url
=self
.settings
['domain'])
71 class FingerHandler(tornado
.web
.RequestHandler
):
73 user
= self
.get_argument('resource')
74 user
= user
.split('acct:')[1]
75 (user
,domain
) = user
.split('@')
76 rows
= db
.execute("select id from user where user.name=?",(user
,)).fetchone()
79 self
.write("Not found")
82 lnk
= Link(rel
='http://spec.example.net/photo/1.0',
84 href
='{}/static/{}.jpg'.format(self
.settings
['domain'],user
))
85 lnk
.titles
.append(('User Photo', 'en'))
86 lnk
.titles
.append(('Benutzerfoto', 'de'))
87 lnk
.properties
.append(('http://spec.example.net/created/1.0', '1970-01-01'))
88 lnk2
= Link(rel
='http://schemas.google.com/g/2010#updates-from',
89 type='application/atom+xml',
90 href
='{}/user/{}'.format(self
.settings
['domain'],user
))
92 rd
= RD(subject
='{}/{}'.format(self
.settings
['domain'],user
))
93 rd
.properties
.append('http://spec.example.net/type/person')
96 self
.write(rd
.to_json())
98 class UserHandler(tornado
.web
.RequestHandler
):
100 entries
= db
.execute("select entry.id,text,ts from user,entry where user.id=entry.userid and user.name=?",(user
,))
101 # import pdb;pdb.set_trace()
102 self
.set_header("Content-Type", 'application/atom+xml')
103 out
= self
.render("templates/feed.xml",
105 feed_url
="{}/user/{}".format(self
.settings
['domain'], user
),
106 hub_url
="{}/hub".format(self
.settings
['domain']),
111 def post(self
, user
):
112 entries
= db
.execute("select entry.id,text,ts from user,entry where user.id=entry.userid and user.name=?",(user
,))
114 self
.set_header("Content-Type", 'application/atom+xml')
115 out
= self
.render_string("templates/feed.xml",
117 feed_url
="{}/user/{}".format(self
.settings
['domain'], user
),
118 hub_url
="{}/hub".format(self
.settings
['domain']),
121 #import pdb;pdb.set_trace()
122 subscribers
= db
.execute("select callback, secret from subscriptions, user where user.id=subscriptions.userid and user.name=?",(user
,))
123 for url
,secret
in subscribers
:
124 digest
= hmac
.new(secret
.encode('utf8'), out
, digestmod
='sha1').hexdigest()
126 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)})
127 apa = httpclient.HTTPClient()
130 application = tornado.web.Application([
131 (r"/.well
-known
/host
-meta
", XrdHandler),
132 (r"/.well
-known
/webfinger
", FingerHandler),
133 (r"/user
/(.+)", UserHandler),
134 (r"/hub
", PushHandler),
135 ],debug=True,**settings)
136 srv = tornado.httpserver.HTTPServer(application, )
139 gen_log = logging.getLogger("tornado
.general
")
140 gen_log.warn("No db found
, creating
in {}".format(path))
141 con = sqlite3.connect(path)
142 con.execute(""" create table user (id integer primary key,
145 create table entry (id integer primary key,
148 ts timestamp default current_timestamp,
149 FOREIGN KEY(userid) REFERENCES user(id));
150 create table subscriptions (id integer primary key,
156 FOREIGN KEY(userid) REFERENCES user(id));""")
160 options.define("config_file
", default="/etc
/friends
/friends
.conf
", type=str)
161 options.define("webroot
", default="/srv
/friends
/", type=str)
163 if __name__ == "__main__
":
164 dbPath = 'friends.db'
165 # options.log_file_prefix="/tmp
/friends
"
166 tornado.options.parse_config_file(options.config_file)
167 tornado.options.parse_command_line()
168 gen_log = logging.getLogger("tornado
.general
")
169 gen_log.info("Reading config
from: %s", options.config_file,)
170 if not os.path.exists(dbPath):
172 db = sqlite3.connect(dbPath, detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
173 db.row_factory = sqlite3.Row
175 tornado.ioloop.IOLoop.instance().start()