+#!/usr/bin/python3
import tornado.ioloop
import tornado.web
-import os, os.path
+import os
+import os.path
import tornado.httpserver
import tornado.httpclient as httpclient
+import salmoning
import sqlite3
import arrow
import datetime
from rd import RD, Link
-import hashlib
import hmac
+from tornado.options import options, define
+import logging
db = None
-#insert into user (name,email) values('mikael','mikael@frykholm.com');
-#insert into entry (userid,text) values (1,'My thoughts on ostatus');
-import tornado.options
+# insert into user (name,email) values('mikael','mikael@frykholm.com');
+# insert into entry (userid,text) values (1,'My thoughts on ostatus');
+
settings = {
"static_path": os.path.join(os.path.dirname(__file__), "static"),
- "cookie_secret": "__TODO:_GENERATE_YOUR_OWN_RANDOM_VALUE_HERE__",
+ "cookie_secret": "supersecret123",
"login_url": "/login",
"xsrf_cookies": False,
"domain":"https://ronin.frykholm.com",
}
-class PushHandler(tornado.web.RequestHandler):
+
#curl -v -k "https://ronin.frykholm.com/hub" -d "hub.callback=a" -d "hub.mode=b" -d "hub.topic=c" -d "hub.verify=d"
+
+class PushHandler(tornado.web.RequestHandler):
def post(self):
""" Someone wants to subscribe to hub_topic feed"""
hub_callback = self.get_argument('hub.callback')
pass #FIXME
path = hub_topic.split(self.settings['domain'])[1]
user = path.split('user/')[1]
- row = db.execute("select id from user where name=?",(user,)).fetchone()
+ row = db.execute("select id from author where name=?",(user,)).fetchone()
expire = datetime.datetime.utcnow() + datetime.timedelta(seconds=int(hub_lease_seconds))
if row:
- db.execute("INSERT into subscriptions (userid, expires, callback, secret, verified) "
+ db.execute("INSERT into subscriptions (author, expires, callback, secret, verified) "
"values (?,?,?,?,?)",(row['id'],expire,hub_callback,hub_secret,False))
db.commit()
self.set_status(202)
def get(self):
self.render("templates/xrd.xml", hostname="ronin.frykholm.com", url=self.settings['domain'])
+class apa():
+ def LookupPublicKey(self, signer_uri=None):
+ return """RSA.jj2_lJ348aNh_9s3eCHlJlbMQdnHVm9svdU2ESW86TvV-4wZId-z3M029pjPvco0UEvlUUnJytXwoTLd70pzfZ8Cu5MMwGbvm9asI9-PKUDSNFgr5T_B017qUXOG5UH1ZNI_fVA2mSAkxxfEksv4HXg43dBvEIW94JpyAtqggHM=.AQAB.Bzz_LcnoLCu7RfDa3sMizROnq0YwzaY362UZLkA0X84KspVLhhzDI15SCLR4BdlvVhK2pa9SlH7Uku9quc2ZGNyr5mEdqjO7YTbQA9UCgbobEq2ImqV_j7Y4IfjPc8prDPCKb_mO9DUlS_ZUxJYfsOuc-SVlGmPZ93uEl8i9OjE="""
+
+
+class SalmonHandler(tornado.web.RequestHandler):
+ def post(self, user):
+ sp = salmoning.SalmonProtocol()
+ sp.key_retriever = apa()
+ data = sp.ParseSalmon(self.request.body)
+ pass
+
class FingerHandler(tornado.web.RequestHandler):
def get(self):
user = self.get_argument('resource')
user = user.split('acct:')[1]
(user,domain) = user.split('@')
- rows = db.execute("select id from user where user.name=?",(user,)).fetchone()
- if not rows:
+ row = db.execute("select id,salmon_pubkey from author where author.name=?",(user,)).fetchone()
+ if not row:
self.set_status(404)
self.write("Not found")
self.finish()
rd.properties.append('http://spec.example.net/type/person')
rd.links.append(lnk)
rd.links.append(lnk2)
+ rd.links.append(Link(rel="magic-public-key",
+ href="data:application/magic-public-key,RSA."+row['salmon_pubkey']))
+ rd.links.append(Link(rel="salmon",
+ href="{}/salmon/{}".format(self.settings['domain'],user)))
+ rd.links.append(Link(rel="http://salmon-protocol.org/ns/salmon-replies",
+ href="{}/salmon/{}".format(self.settings['domain'],user)))
+ rd.links.append(Link(rel="http://salmon-protocol.org/ns/salmon-mention",
+ href="{}/salmon/{}".format(self.settings['domain'],user)))
self.write(rd.to_json())
class UserHandler(tornado.web.RequestHandler):
def get(self, user):
- entries = db.execute("select entry.id,text,ts from user,entry where user.id=entry.userid and user.name=?",(user,))
- #import pdb;pdb.set_trace()
+ entries = db.execute("select entry.id,text,ts from author,entry where author.id=entry.author and author.name=?",(user,))
+ # import pdb;pdb.set_trace()
self.set_header("Content-Type", 'application/atom+xml')
out = self.render("templates/feed.xml",
user=user,
arrow=arrow )
#digest = hmac.new()
+ def post(self, user):
+ entries = db.execute("select entry.id,text,ts from user,entry where user.id=entry.userid and user.name=?",(user,))
+
+ self.set_header("Content-Type", 'application/atom+xml')
+ out = self.render_string("templates/feed.xml",
+ user=user,
+ feed_url="{}/user/{}".format(self.settings['domain'], user),
+ hub_url="{}/hub".format(self.settings['domain']),
+ entries=entries,
+ arrow=arrow)
+ #import pdb;pdb.set_trace()
+ # Notify subscribers
+ subscribers = db.execute("select callback, secret from subscriptions, author where author.id=subscriptions.author and author.name=?",(user,))
+ for url,secret in subscribers:
+ digest = hmac.new(secret.encode('utf8'), out, digestmod='sha1').hexdigest()
+
+ 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)})
+ apa = httpclient.HTTPClient()
+ apa.fetch(req)
+
application = tornado.web.Application([
(r"/.well-known/host-meta", XrdHandler),
(r"/.well-known/webfinger", FingerHandler),
+ (r"/salmon/(.+)", SalmonHandler),
(r"/user/(.+)", UserHandler),
(r"/hub", PushHandler),
],debug=True,**settings)
srv = tornado.httpserver.HTTPServer(application, )
+
def setup_db(path):
- print("No db found, creating in {}".format(path))
+ gen_log = logging.getLogger("tornado.general")
+ gen_log.warn("No db found, creating in {}".format(path))
con = sqlite3.connect(path)
- con.execute(""" create table user (id integer primary key,
+ con.execute("""create table author (id integer primary key,
+ uri varchar,
name varchar,
- email varchar);
- create table entry (id integer primary key,
- userid INTEGER,
- text varchar,
+ email varchar,
+ salmon_pubkey varchar, -- base64_urlencoded public modulus +.+ base64_urlencoded public exponent
+ salmon_privkey varchar -- base64_urlencoded private exponent
+ );""")
+ con.execute(""" create table entry (id integer primary key,
+ author INTEGER,
+ text varchar, -- xml atom <entry>
+ verb varchar,
ts timestamp default current_timestamp,
- FOREIGN KEY(userid) REFERENCES user(id));
+ FOREIGN KEY(author) REFERENCES author(id));""")
+ con.execute("""
create table subscriptions (id integer primary key,
- userid integer,
+ author integer,
expires datetime,
callback varchar,
secret varchar,
verified bool,
- FOREIGN KEY(userid) REFERENCES user(id));""")
+ FOREIGN KEY(author) REFERENCES author(id));""")
con.commit()
+
+options.define("config_file", default="/etc/friends/friends.conf", type=str)
+options.define("webroot", default="/srv/friends/", type=str)
+
if __name__ == "__main__":
dbPath = 'friends.db'
+# options.log_file_prefix="/tmp/friends"
+ tornado.options.parse_config_file(options.config_file)
tornado.options.parse_command_line()
+ gen_log = logging.getLogger("tornado.general")
+ gen_log.info("Reading config from: %s", options.config_file,)
if not os.path.exists(dbPath):
setup_db(dbPath)
db = sqlite3.connect(dbPath, detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
db.row_factory = sqlite3.Row
- srv.listen(8080)
+ srv.listen(80)
tornado.ioloop.IOLoop.instance().start()
- #TODO hmac.new(b'5cc324285ece71e21e9554f4056563806f6ce0b7e4ab18d0133b602f8ba7e87a',open("apa.xml","rb").read(),digestmod='sha1').hexdigest()
-'b75d4733e0802629a0c15d0faa8de8fc9778cd05' queue runner
+