epicyon.py 56 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472
  1. __filename__ = "epicyon.py"
  2. __author__ = "Bob Mottram"
  3. __license__ = "AGPL3+"
  4. __version__ = "1.0.0"
  5. __maintainer__ = "Bob Mottram"
  6. __email__ = "bob@freedombone.net"
  7. __status__ = "Production"
  8. from person import createPerson
  9. from person import createGroup
  10. from person import createSharedInbox
  11. from person import createCapabilitiesInbox
  12. from person import setDisplayNickname
  13. from person import setBio
  14. from person import setProfileImage
  15. from person import removeAccount
  16. from person import activateAccount
  17. from person import deactivateAccount
  18. from skills import setSkillLevel
  19. from roles import setRole
  20. from person import setOrganizationScheme
  21. from webfinger import webfingerHandle
  22. from posts import getPosts
  23. from posts import createPublicPost
  24. from posts import deleteAllPosts
  25. from posts import createOutbox
  26. from posts import archivePosts
  27. from posts import sendPostViaServer
  28. from posts import getPublicPostsOfPerson
  29. from posts import getUserUrl
  30. from posts import archivePosts
  31. from session import createSession
  32. from session import getJson
  33. from blocking import addBlock
  34. from blocking import removeBlock
  35. from filters import addFilter
  36. from filters import removeFilter
  37. import json
  38. import os
  39. import shutil
  40. import sys
  41. import requests
  42. import time
  43. from pprint import pprint
  44. from tests import testHttpsig
  45. from daemon import runDaemon
  46. import socket
  47. from follow import clearFollows
  48. from follow import clearFollowers
  49. from follow import followerOfPerson
  50. from follow import unfollowPerson
  51. from follow import unfollowerOfPerson
  52. from follow import getFollowersOfPerson
  53. from tests import testPostMessageBetweenServers
  54. from tests import testFollowBetweenServers
  55. from tests import testClientToServer
  56. from tests import runAllTests
  57. from config import setConfigParam
  58. from config import getConfigParam
  59. from auth import storeBasicCredentials
  60. from auth import removePassword
  61. from auth import createPassword
  62. from utils import getDomainFromActor
  63. from utils import getNicknameFromActor
  64. from utils import followPerson
  65. from utils import validNickname
  66. from media import archiveMedia
  67. from media import getAttachmentMediaType
  68. from delete import sendDeleteViaServer
  69. from like import sendLikeViaServer
  70. from like import sendUndoLikeViaServer
  71. from blocking import sendBlockViaServer
  72. from blocking import sendUndoBlockViaServer
  73. from roles import sendRoleViaServer
  74. from skills import sendSkillViaServer
  75. from availability import setAvailability
  76. from availability import sendAvailabilityViaServer
  77. from manualapprove import manualDenyFollowRequest
  78. from manualapprove import manualApproveFollowRequest
  79. from shares import sendShareViaServer
  80. from shares import sendUndoShareViaServer
  81. from shares import addShare
  82. import argparse
  83. def str2bool(v):
  84. if isinstance(v, bool):
  85. return v
  86. if v.lower() in ('yes', 'true', 't', 'y', '1'):
  87. return True
  88. elif v.lower() in ('no', 'false', 'f', 'n', '0'):
  89. return False
  90. else:
  91. raise argparse.ArgumentTypeError('Boolean value expected.')
  92. parser = argparse.ArgumentParser(description='ActivityPub Server')
  93. parser.add_argument('-n','--nickname', dest='nickname', type=str,default=None, \
  94. help='Nickname of the account to use')
  95. parser.add_argument('--fol','--follow', dest='follow', type=str,default=None, \
  96. help='Handle of account to follow. eg. nickname@domain')
  97. parser.add_argument('--unfol','--unfollow', dest='unfollow', type=str,default=None, \
  98. help='Handle of account stop following. eg. nickname@domain')
  99. parser.add_argument('-d','--domain', dest='domain', type=str,default=None, \
  100. help='Domain name of the server')
  101. parser.add_argument('-p','--port', dest='port', type=int,default=None, \
  102. help='Port number to run on')
  103. parser.add_argument('--proxy', dest='proxyPort', type=int,default=None, \
  104. help='Proxy port number to run on')
  105. parser.add_argument('--path', dest='baseDir', \
  106. type=str,default=os.getcwd(), \
  107. help='Directory in which to store posts')
  108. parser.add_argument('--language', dest='language', \
  109. type=str,default=None, \
  110. help='Language code, eg. en/fr/de/es')
  111. parser.add_argument('-a','--addaccount', dest='addaccount', \
  112. type=str,default=None, \
  113. help='Adds a new account')
  114. parser.add_argument('-g','--addgroup', dest='addgroup', \
  115. type=str,default=None, \
  116. help='Adds a new group')
  117. parser.add_argument('--activate', dest='activate', \
  118. type=str,default=None, \
  119. help='Activate a previously deactivated account')
  120. parser.add_argument('--deactivate', dest='deactivate', \
  121. type=str,default=None, \
  122. help='Deactivate an account')
  123. parser.add_argument('-r','--rmaccount', dest='rmaccount', \
  124. type=str,default=None, \
  125. help='Remove an account')
  126. parser.add_argument('--rmgroup', dest='rmgroup', \
  127. type=str,default=None, \
  128. help='Remove a group')
  129. parser.add_argument('--pass','--password', dest='password', \
  130. type=str,default=None, \
  131. help='Set a password for an account')
  132. parser.add_argument('--chpass','--changepassword', \
  133. nargs='+',dest='changepassword', \
  134. help='Change the password for an account')
  135. parser.add_argument('--actor', dest='actor', type=str,default=None, \
  136. help='Show the json actor the given handle')
  137. parser.add_argument('--posts', dest='posts', type=str,default=None, \
  138. help='Show posts for the given handle')
  139. parser.add_argument('--postsraw', dest='postsraw', type=str,default=None, \
  140. help='Show raw json of posts for the given handle')
  141. parser.add_argument('--json', dest='json', type=str,default=None, \
  142. help='Show the json for a given activitypub url')
  143. parser.add_argument('-f','--federate', nargs='+',dest='federationList', \
  144. help='Specify federation list separated by spaces')
  145. parser.add_argument("--debug", type=str2bool, nargs='?', \
  146. const=True, default=False, \
  147. help="Show debug messages")
  148. parser.add_argument("--authenticatedFetch", type=str2bool, nargs='?', \
  149. const=True, default=False, \
  150. help="Enable authentication on GET requests for json (authenticated fetch)")
  151. parser.add_argument("--instanceOnlySkillsSearch", type=str2bool, nargs='?', \
  152. const=True, default=False, \
  153. help="Skills searches only return results from this instance")
  154. parser.add_argument("--http", type=str2bool, nargs='?', \
  155. const=True, default=False, \
  156. help="Use http only")
  157. parser.add_argument("--dat", type=str2bool, nargs='?', \
  158. const=True, default=False, \
  159. help="Use dat protocol only")
  160. parser.add_argument("--tor", type=str2bool, nargs='?', \
  161. const=True, default=False, \
  162. help="Route via Tor")
  163. parser.add_argument("--tests", type=str2bool, nargs='?', \
  164. const=True, default=False, \
  165. help="Run unit tests")
  166. parser.add_argument("--testsnetwork", type=str2bool, nargs='?', \
  167. const=True, default=False, \
  168. help="Run network unit tests")
  169. parser.add_argument("--testdata", type=str2bool, nargs='?', \
  170. const=True, default=False, \
  171. help="Generate some data for testing purposes")
  172. parser.add_argument("--ocap", type=str2bool, nargs='?', \
  173. const=True, default=False, \
  174. help="Always strictly enforce object capabilities")
  175. parser.add_argument("--noreply", type=str2bool, nargs='?', \
  176. const=True, default=False, \
  177. help="Default capabilities don't allow replies on posts")
  178. parser.add_argument("--nolike", type=str2bool, nargs='?', \
  179. const=True, default=False, \
  180. help="Default capabilities don't allow likes/favourites on posts")
  181. parser.add_argument("--nopics", type=str2bool, nargs='?', \
  182. const=True, default=False, \
  183. help="Default capabilities don't allow attached pictures")
  184. parser.add_argument("--noannounce","--norepeat", type=str2bool, nargs='?', \
  185. const=True, default=False, \
  186. help="Default capabilities don't allow announce/repeat")
  187. parser.add_argument("--cw", type=str2bool, nargs='?', \
  188. const=True, default=False, \
  189. help="Default capabilities don't allow posts without content warnings")
  190. parser.add_argument('--icon','--avatar', dest='avatar', type=str,default=None, \
  191. help='Set the avatar filename for an account')
  192. parser.add_argument('--image','--background', dest='backgroundImage', type=str,default=None, \
  193. help='Set the profile background image for an account')
  194. parser.add_argument('--archive', dest='archive', type=str,default=None, \
  195. help='Archive old files to the given directory')
  196. parser.add_argument('--archiveweeks', dest='archiveWeeks', type=str,default=None, \
  197. help='Specify the number of weeks after which data will be archived')
  198. parser.add_argument('--maxposts', dest='archiveMaxPosts', type=str,default=None, \
  199. help='Maximum number of posts in in/outbox')
  200. parser.add_argument('--message', dest='message', type=str,default=None, \
  201. help='Message content')
  202. parser.add_argument('--delete', dest='delete', type=str,default=None, \
  203. help='Delete a specified post')
  204. parser.add_argument("--allowdeletion", type=str2bool, nargs='?', \
  205. const=True, default=False, \
  206. help="Do not allow deletions")
  207. parser.add_argument('--repeat','--announce', dest='announce', type=str,default=None, \
  208. help='Announce/repeat a url')
  209. parser.add_argument('--favorite','--like', dest='like', type=str,default=None, \
  210. help='Like a url')
  211. parser.add_argument('--undolike','--unlike', dest='undolike', type=str,default=None, \
  212. help='Undo a like of a url')
  213. parser.add_argument('--sendto', dest='sendto', type=str,default=None, \
  214. help='Address to send a post to')
  215. parser.add_argument('--attach', dest='attach', type=str,default=None, \
  216. help='File to attach to a post')
  217. parser.add_argument('--imagedescription', dest='imageDescription', type=str,default=None, \
  218. help='Description of an attached image')
  219. parser.add_argument("--blurhash", type=str2bool, nargs='?', \
  220. const=True, default=False, \
  221. help="Create blurhash for an image")
  222. parser.add_argument('--warning','--warn','--cwsubject','--subject', dest='subject', type=str,default=None, \
  223. help='Subject of content warning')
  224. parser.add_argument('--reply','--replyto', dest='replyto', type=str,default=None, \
  225. help='Url of post to reply to')
  226. parser.add_argument("--followersonly", type=str2bool, nargs='?', \
  227. const=True, default=True, \
  228. help="Send to followers only")
  229. parser.add_argument("--followerspending", type=str2bool, nargs='?', \
  230. const=True, default=False, \
  231. help="Show a list of followers pending")
  232. parser.add_argument('--approve', dest='approve', type=str,default=None, \
  233. help='Approve a follow request')
  234. parser.add_argument('--deny', dest='deny', type=str,default=None, \
  235. help='Deny a follow request')
  236. parser.add_argument("-c","--client", type=str2bool, nargs='?', \
  237. const=True, default=False, \
  238. help="Use as an ActivityPub client")
  239. parser.add_argument('--maxreplies', dest='maxReplies', type=int,default=64, \
  240. help='Maximum number of replies to a post')
  241. parser.add_argument('--maxMentions','--hellthread', dest='maxMentions', type=int,default=10, \
  242. help='Maximum number of mentions within a post')
  243. parser.add_argument('--role', dest='role', type=str,default=None, \
  244. help='Set a role for a person')
  245. parser.add_argument('--organization','--project', dest='project', type=str,default=None, \
  246. help='Set a project for a person')
  247. parser.add_argument('--skill', dest='skill', type=str,default=None, \
  248. help='Set a skill for a person')
  249. parser.add_argument('--level', dest='skillLevelPercent', type=int,default=None, \
  250. help='Set a skill level for a person as a percentage, or zero to remove')
  251. parser.add_argument('--status','--availability', dest='availability', type=str,default=None, \
  252. help='Set an availability status')
  253. parser.add_argument('--block', dest='block', type=str,default=None, \
  254. help='Block a particular address')
  255. parser.add_argument('--unblock', dest='unblock', type=str,default=None, \
  256. help='Remove a block on a particular address')
  257. parser.add_argument('--delegate', dest='delegate', type=str,default=None, \
  258. help='Address of an account to delegate a role to')
  259. parser.add_argument('--undodelegate','--undelegate', dest='undelegate', type=str,default=None, \
  260. help='Removes a delegated role for the given address')
  261. parser.add_argument('--filter', dest='filterStr', type=str,default=None, \
  262. help='Adds a word or phrase which if present will cause a message to be ignored')
  263. parser.add_argument('--unfilter', dest='unfilterStr', type=str,default=None, \
  264. help='Remove a filter on a particular word or phrase')
  265. parser.add_argument('--domainmax', dest='domainMaxPostsPerDay', type=int,default=8640, \
  266. help='Maximum number of received posts from a domain per day')
  267. parser.add_argument('--accountmax', dest='accountMaxPostsPerDay', type=int,default=8640, \
  268. help='Maximum number of received posts from an account per day')
  269. parser.add_argument('--itemName', dest='itemName', type=str,default=None, \
  270. help='Name of an item being shared')
  271. parser.add_argument('--undoItemName', dest='undoItemName', type=str,default=None, \
  272. help='Name of an shared item to remove')
  273. parser.add_argument('--summary', dest='summary', type=str,default=None, \
  274. help='Description of an item being shared')
  275. parser.add_argument('--itemImage', dest='itemImage', type=str,default=None, \
  276. help='Filename of an image for an item being shared')
  277. parser.add_argument('--itemType', dest='itemType', type=str,default=None, \
  278. help='Type of item being shared')
  279. parser.add_argument('--itemCategory', dest='itemCategory', type=str,default=None, \
  280. help='Category of item being shared')
  281. parser.add_argument('--location', dest='location', type=str,default=None, \
  282. help='Location/City of item being shared')
  283. parser.add_argument('--duration', dest='duration', type=str,default=None, \
  284. help='Duration for which to share an item')
  285. parser.add_argument('--registration', dest='registration', type=str,default=None, \
  286. help='Whether new registrations are open or closed')
  287. parser.add_argument('--maxregistrations', dest='maxRegistrations', type=int,default=None, \
  288. help='The maximum number of new registrations')
  289. parser.add_argument("--resetregistrations", type=str2bool, nargs='?', \
  290. const=True, default=False, \
  291. help="Reset the number of remaining registrations")
  292. args = parser.parse_args()
  293. debug=False
  294. if args.debug:
  295. debug=True
  296. if args.tests:
  297. runAllTests()
  298. sys.exit()
  299. if args.testsnetwork:
  300. print('Network Tests')
  301. testPostMessageBetweenServers()
  302. testFollowBetweenServers()
  303. testClientToServer()
  304. print('All tests succeeded')
  305. sys.exit()
  306. httpPrefix='https'
  307. if args.http:
  308. httpPrefix='http'
  309. baseDir=args.baseDir
  310. if baseDir.endswith('/'):
  311. print("--path option should not end with '/'")
  312. sys.exit()
  313. if args.posts:
  314. if '@' not in args.posts:
  315. print('Syntax: --posts nickname@domain')
  316. sys.exit()
  317. if not args.http:
  318. args.port=443
  319. nickname=args.posts.split('@')[0]
  320. domain=args.posts.split('@')[1]
  321. getPublicPostsOfPerson(baseDir,nickname,domain,False,True, \
  322. args.tor,args.port,httpPrefix,debug, \
  323. __version__)
  324. sys.exit()
  325. if args.postsraw:
  326. if '@' not in args.postsraw:
  327. print('Syntax: --postsraw nickname@domain')
  328. sys.exit()
  329. if not args.http:
  330. args.port=443
  331. nickname=args.postsraw.split('@')[0]
  332. domain=args.postsraw.split('@')[1]
  333. getPublicPostsOfPerson(baseDir,nickname,domain,False,False, \
  334. args.tor,args.port,httpPrefix,debug, \
  335. __version__)
  336. sys.exit()
  337. if args.json:
  338. session = createSession(False)
  339. asHeader = {'Accept': 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'}
  340. testJson = getJson(session,args.json,asHeader,None,__version__,httpPrefix,None)
  341. pprint(testJson)
  342. sys.exit()
  343. # create cache for actors
  344. if not os.path.isdir(baseDir+'/cache'):
  345. os.mkdir(baseDir+'/cache')
  346. if not os.path.isdir(baseDir+'/cache/actors'):
  347. print('Creating actors cache')
  348. os.mkdir(baseDir+'/cache/actors')
  349. if not os.path.isdir(baseDir+'/cache/announce'):
  350. print('Creating announce cache')
  351. os.mkdir(baseDir+'/cache/announce')
  352. # set the theme in config.json
  353. themeName=getConfigParam(baseDir,'theme')
  354. if not themeName:
  355. setConfigParam(baseDir,'theme','default')
  356. if args.domain:
  357. domain=args.domain
  358. setConfigParam(baseDir,'domain',domain)
  359. if not args.language:
  360. languageCode=getConfigParam(baseDir,'language')
  361. if languageCode:
  362. args.language=languageCode
  363. # maximum number of new registrations
  364. if not args.maxRegistrations:
  365. maxRegistrations=getConfigParam(baseDir,'maxRegistrations')
  366. if not maxRegistrations:
  367. maxRegistrations=10
  368. setConfigParam(baseDir,'maxRegistrations',str(maxRegistrations))
  369. else:
  370. maxRegistrations=int(maxRegistrations)
  371. else:
  372. maxRegistrations=args.maxRegistrations
  373. setConfigParam(baseDir,'maxRegistrations',str(maxRegistrations))
  374. # if this is the initial run then allow new registrations
  375. if not getConfigParam(baseDir,'registration'):
  376. setConfigParam(baseDir,'registration','open')
  377. setConfigParam(baseDir,'maxRegistrations',str(maxRegistrations))
  378. setConfigParam(baseDir,'registrationsRemaining',str(maxRegistrations))
  379. if args.resetregistrations:
  380. setConfigParam(baseDir,'registrationsRemaining',str(maxRegistrations))
  381. print('Number of new registrations reset to '+str(maxRegistrations))
  382. # whether new registrations are open or closed
  383. if args.registration:
  384. if args.registration.lower()=='open':
  385. registration=getConfigParam(baseDir,'registration')
  386. if not registration:
  387. setConfigParam(baseDir,'registrationsRemaining',str(maxRegistrations))
  388. else:
  389. if registration!='open':
  390. setConfigParam(baseDir,'registrationsRemaining',str(maxRegistrations))
  391. setConfigParam(baseDir,'registration','open')
  392. print('New registrations open')
  393. else:
  394. setConfigParam(baseDir,'registration','closed')
  395. print('New registrations closed')
  396. # unique ID for the instance
  397. instanceId=getConfigParam(baseDir,'instanceId')
  398. if not instanceId:
  399. instanceId=createPassword(32)
  400. setConfigParam(baseDir,'instanceId',instanceId)
  401. print('Instance ID: '+instanceId)
  402. # get domain name from configuration
  403. configDomain=getConfigParam(baseDir,'domain')
  404. if configDomain:
  405. domain=configDomain
  406. else:
  407. domain='localhost'
  408. # get port number from configuration
  409. configPort=getConfigParam(baseDir,'port')
  410. if configPort:
  411. port=configPort
  412. else:
  413. port=8085
  414. configProxyPort=getConfigParam(baseDir,'proxyPort')
  415. if configProxyPort:
  416. proxyPort=configProxyPort
  417. else:
  418. proxyPort=port
  419. nickname=None
  420. if args.nickname:
  421. nickname=nickname
  422. federationList=[]
  423. if args.federationList:
  424. if len(args.federationList)==1:
  425. if not (args.federationList[0].lower()=='any' or \
  426. args.federationList[0].lower()=='all' or \
  427. args.federationList[0].lower()=='*'):
  428. for federationDomain in args.federationList:
  429. if '@' in federationDomain:
  430. print(federationDomain+': Federate with domains, not individual accounts')
  431. sys.exit()
  432. federationList=args.federationList.copy()
  433. setConfigParam(baseDir,'federationList',federationList)
  434. else:
  435. configFederationList=getConfigParam(baseDir,'federationList')
  436. if configFederationList:
  437. federationList=configFederationList
  438. useTor=args.tor
  439. if domain.endswith('.onion'):
  440. useTor=True
  441. if args.approve:
  442. if not args.nickname:
  443. print('Specify a nickname with the --nickname option')
  444. sys.exit()
  445. if '@' not in args.approve:
  446. print('syntax: --approve nick@domain')
  447. sys.exit()
  448. session = createSession(useTor)
  449. sendThreads=[]
  450. postLog=[]
  451. cachedWebfingers={}
  452. personCache={}
  453. acceptedCaps=[]
  454. manualApproveFollowRequest(session,baseDir, \
  455. httpPrefix,
  456. args.nickname,domain,port, \
  457. args.approve, \
  458. federationList, \
  459. sendThreads,postLog, \
  460. cachedWebfingers,personCache, \
  461. acceptedCaps, \
  462. debug,__version__)
  463. sys.exit()
  464. if args.deny:
  465. if not args.nickname:
  466. print('Specify a nickname with the --nickname option')
  467. sys.exit()
  468. if '@' not in args.deny:
  469. print('syntax: --deny nick@domain')
  470. sys.exit()
  471. session = createSession(useTor)
  472. sendThreads=[]
  473. postLog=[]
  474. cachedWebfingers={}
  475. personCache={}
  476. manualDenyFollowRequest(session,baseDir, \
  477. httpPrefix,
  478. args.nickname,domain,port, \
  479. args.deny, \
  480. federationList, \
  481. sendThreads,postLog, \
  482. cachedWebfingers,personCache, \
  483. debug,__version__)
  484. sys.exit()
  485. if args.followerspending:
  486. if not args.nickname:
  487. print('Specify a nickname with the --nickname option')
  488. sys.exit()
  489. accountsDir=baseDir+'/accounts/'+args.nickname+'@'+domain
  490. approveFollowsFilename=accountsDir+'/followrequests.txt'
  491. approveCtr=0
  492. if os.path.isfile(approveFollowsFilename):
  493. with open(approveFollowsFilename, 'r') as approvefile:
  494. for approve in approvefile:
  495. print(approve.replace('\n',''))
  496. approveCtr+=1
  497. if approveCtr==0:
  498. print('There are no follow requests pending approval.')
  499. sys.exit()
  500. if args.message:
  501. if not args.nickname:
  502. print('Specify a nickname with the --nickname option')
  503. sys.exit()
  504. if not args.password:
  505. print('Specify a password with the --password option')
  506. sys.exit()
  507. session = createSession(useTor)
  508. if not args.sendto:
  509. print('Specify an account to sent to: --sendto [nickname@domain]')
  510. sys.exit()
  511. if '@' not in args.sendto and \
  512. not args.sendto.lower().endswith('public') and \
  513. not args.sendto.lower().endswith('followers'):
  514. print('syntax: --sendto [nickname@domain]')
  515. print(' --sendto public')
  516. print(' --sendto followers')
  517. sys.exit()
  518. if '@' in args.sendto:
  519. toNickname=args.sendto.split('@')[0]
  520. toDomain=args.sendto.split('@')[1].replace('\n','')
  521. toPort=443
  522. if ':' in toDomain:
  523. toPort=toDomain.split(':')[1]
  524. toDomain=toDomain.split(':')[0]
  525. else:
  526. if args.sendto.endswith('followers'):
  527. toNickname=None
  528. toDomain='followers'
  529. toPort=port
  530. else:
  531. toNickname=None
  532. toDomain='public'
  533. toPort=port
  534. #ccUrl=httpPrefix+'://'+domain+'/users/'+nickname+'/followers'
  535. ccUrl=None
  536. sendMessage=args.message
  537. followersOnly=args.followersonly
  538. clientToServer=args.client
  539. attachedImageDescription=args.imageDescription
  540. useBlurhash=args.blurhash
  541. sendThreads = []
  542. postLog = []
  543. personCache={}
  544. cachedWebfingers={}
  545. subject=args.subject
  546. attach=args.attach
  547. mediaType=None
  548. if attach:
  549. mediaType=getAttachmentMediaType(attach)
  550. replyTo=args.replyto
  551. followersOnly=False
  552. print('Sending post to '+args.sendto)
  553. sendPostViaServer(__version__, \
  554. baseDir,session,args.nickname,args.password, \
  555. domain,port, \
  556. toNickname,toDomain,toPort,ccUrl, \
  557. httpPrefix,sendMessage,followersOnly, \
  558. attach,mediaType, \
  559. attachedImageDescription,useBlurhash, \
  560. cachedWebfingers,personCache, \
  561. args.debug,replyTo,replyTo,subject)
  562. for i in range(10):
  563. # TODO detect send success/fail
  564. time.sleep(1)
  565. sys.exit()
  566. if args.announce:
  567. if not args.nickname:
  568. print('Specify a nickname with the --nickname option')
  569. sys.exit()
  570. if not args.password:
  571. print('Specify a password with the --password option')
  572. sys.exit()
  573. session = createSession(useTor)
  574. personCache={}
  575. cachedWebfingers={}
  576. print('Sending announce/repeat of '+args.announce)
  577. sendAnnounceViaServer(baseDir,session,args.nickname,args.password,
  578. domain,port, \
  579. httpPrefix,args.announce, \
  580. cachedWebfingers,personCache, \
  581. True,__version__)
  582. for i in range(10):
  583. # TODO detect send success/fail
  584. time.sleep(1)
  585. sys.exit()
  586. if args.itemName:
  587. if not args.password:
  588. print('Specify a password with the --password option')
  589. sys.exit()
  590. if not args.nickname:
  591. print('Specify a nickname with the --nickname option')
  592. sys.exit()
  593. if not args.summary:
  594. print('Specify a description for your shared item with the --summary option')
  595. sys.exit()
  596. if not args.itemType:
  597. print('Specify a type of shared item with the --itemType option')
  598. sys.exit()
  599. if not args.itemCategory:
  600. print('Specify a category of shared item with the --itemCategory option')
  601. sys.exit()
  602. if not args.location:
  603. print('Specify a location or city where theshared item resides with the --location option')
  604. sys.exit()
  605. if not args.duration:
  606. print('Specify a duration to share the object with the --duration option')
  607. sys.exit()
  608. session = createSession(useTor)
  609. personCache={}
  610. cachedWebfingers={}
  611. print('Sending shared item: '+args.itemName)
  612. sendShareViaServer(baseDir,session, \
  613. args.nickname,args.password, \
  614. domain,port, \
  615. httpPrefix, \
  616. args.itemName, \
  617. args.summary, \
  618. args.itemImage, \
  619. args.itemType, \
  620. args.itemCategory, \
  621. args.location, \
  622. args.duration, \
  623. cachedWebfingers,personCache, \
  624. debug,__version__)
  625. for i in range(10):
  626. # TODO detect send success/fail
  627. time.sleep(1)
  628. sys.exit()
  629. if args.undoItemName:
  630. if not args.password:
  631. print('Specify a password with the --password option')
  632. sys.exit()
  633. if not args.nickname:
  634. print('Specify a nickname with the --nickname option')
  635. sys.exit()
  636. session = createSession(useTor)
  637. personCache={}
  638. cachedWebfingers={}
  639. print('Sending undo of shared item: '+args.undoItemName)
  640. sendUndoShareViaServer(session, \
  641. args.nickname,args.password, \
  642. domain,port, \
  643. httpPrefix, \
  644. args.undoItemName, \
  645. cachedWebfingers,personCache, \
  646. debug,__version__)
  647. for i in range(10):
  648. # TODO detect send success/fail
  649. time.sleep(1)
  650. sys.exit()
  651. if args.like:
  652. if not args.nickname:
  653. print('Specify a nickname with the --nickname option')
  654. sys.exit()
  655. if not args.password:
  656. print('Specify a password with the --password option')
  657. sys.exit()
  658. session = createSession(useTor)
  659. personCache={}
  660. cachedWebfingers={}
  661. print('Sending like of '+args.like)
  662. sendLikeViaServer(baseDir,session, \
  663. args.nickname,args.password, \
  664. domain,port, \
  665. httpPrefix,args.like, \
  666. cachedWebfingers,personCache, \
  667. True,__version__)
  668. for i in range(10):
  669. # TODO detect send success/fail
  670. time.sleep(1)
  671. sys.exit()
  672. if args.undolike:
  673. if not args.nickname:
  674. print('Specify a nickname with the --nickname option')
  675. sys.exit()
  676. if not args.password:
  677. print('Specify a password with the --password option')
  678. sys.exit()
  679. session = createSession(useTor)
  680. personCache={}
  681. cachedWebfingers={}
  682. print('Sending undo like of '+args.undolike)
  683. sendUndoLikeViaServer(baseDir,session, \
  684. args.nickname,args.password, \
  685. domain,port, \
  686. httpPrefix,args.undolike, \
  687. cachedWebfingers,personCache, \
  688. True,__version__)
  689. for i in range(10):
  690. # TODO detect send success/fail
  691. time.sleep(1)
  692. sys.exit()
  693. if args.delete:
  694. if not args.nickname:
  695. print('Specify a nickname with the --nickname option')
  696. sys.exit()
  697. if not args.password:
  698. print('Specify a password with the --password option')
  699. sys.exit()
  700. session = createSession(useTor)
  701. personCache={}
  702. cachedWebfingers={}
  703. print('Sending delete request of '+args.delete)
  704. sendDeleteViaServer(baseDir,session, \
  705. args.nickname,args.password, \
  706. domain,port, \
  707. httpPrefix,args.delete, \
  708. cachedWebfingers,personCache, \
  709. True,__version__)
  710. for i in range(10):
  711. # TODO detect send success/fail
  712. time.sleep(1)
  713. sys.exit()
  714. if args.follow:
  715. # follow via c2s protocol
  716. if '.' not in args.follow:
  717. print("This doesn't look like a fediverse handle")
  718. sys.exit()
  719. if not args.nickname:
  720. print('Please specify the nickname for the account with --nickname')
  721. sys.exit()
  722. if not args.password:
  723. print('Please specify the password for '+args.nickname+' on '+domain)
  724. sys.exit()
  725. followNickname=getNicknameFromActor(args.follow)
  726. if not followNickname:
  727. print('Unable to find nickname in '+args.follow)
  728. sys.exit()
  729. followDomain,followPort=getDomainFromActor(args.follow)
  730. session = createSession(useTor)
  731. personCache={}
  732. cachedWebfingers={}
  733. followHttpPrefix=httpPrefix
  734. if args.follow.startswith('https'):
  735. followHttpPrefix='https'
  736. sendFollowRequestViaServer(baseDir,session, \
  737. args.nickname,args.password, \
  738. domain,port, \
  739. followNickname,followDomain,followPort, \
  740. httpPrefix, \
  741. cachedWebfingers,personCache, \
  742. debug,__version__)
  743. for t in range(20):
  744. time.sleep(1)
  745. # TODO some method to know if it worked
  746. print('Ok')
  747. sys.exit()
  748. if args.unfollow:
  749. # unfollow via c2s protocol
  750. if '.' not in args.follow:
  751. print("This doesn't look like a fediverse handle")
  752. sys.exit()
  753. if not args.nickname:
  754. print('Please specify the nickname for the account with --nickname')
  755. sys.exit()
  756. if not args.password:
  757. print('Please specify the password for '+args.nickname+' on '+domain)
  758. sys.exit()
  759. followNickname=getNicknameFromActor(args.unfollow)
  760. if not followNickname:
  761. print('WARN: unable to find nickname in '+args.unfollow)
  762. sys.exit()
  763. followDomain,followPort=getDomainFromActor(args.unfollow)
  764. session = createSession(useTor)
  765. personCache={}
  766. cachedWebfingers={}
  767. followHttpPrefix=httpPrefix
  768. if args.follow.startswith('https'):
  769. followHttpPrefix='https'
  770. sendUnfollowRequestViaServer(baseDir,session, \
  771. args.nickname,args.password, \
  772. domain,port, \
  773. followNickname,followDomain,followPort, \
  774. httpPrefix, \
  775. cachedWebfingers,personCache, \
  776. debug,__version__)
  777. for t in range(20):
  778. time.sleep(1)
  779. # TODO some method to know if it worked
  780. print('Ok')
  781. sys.exit()
  782. nickname='admin'
  783. if args.domain:
  784. domain=args.domain
  785. setConfigParam(baseDir,'domain',domain)
  786. if args.port:
  787. port=args.port
  788. setConfigParam(baseDir,'port',port)
  789. if args.proxyPort:
  790. proxyPort=args.proxyPort
  791. setConfigParam(baseDir,'proxyPort',proxyPort)
  792. ocapAlways=False
  793. if args.ocap:
  794. ocapAlways=args.ocap
  795. if args.dat:
  796. httpPrefix='dat'
  797. if args.actor:
  798. originalActor=args.actor
  799. if '/@' in args.actor or '/users/' in args.actor or args.actor.startswith('http') or args.actor.startswith('dat'):
  800. # format: https://domain/@nick
  801. args.actor=args.actor.replace('https://','').replace('http://','').replace('dat://','').replace('/@','/users/')
  802. if '/users/' not in args.actor and \
  803. '/channel/' not in args.actor and \
  804. '/profile/' not in args.actor:
  805. print('Expected actor format: https://domain/@nick or https://domain/users/nick')
  806. sys.exit()
  807. if '/users/' in args.actor:
  808. nickname=args.actor.split('/users/')[1].replace('\n','')
  809. domain=args.actor.split('/users/')[0]
  810. elif '/profile/' in args.actor:
  811. nickname=args.actor.split('/profile/')[1].replace('\n','')
  812. domain=args.actor.split('/profile/')[0]
  813. else:
  814. nickname=args.actor.split('/channel/')[1].replace('\n','')
  815. domain=args.actor.split('/channel/')[0]
  816. else:
  817. # format: @nick@domain
  818. if '@' not in args.actor:
  819. print('Syntax: --actor nickname@domain')
  820. sys.exit()
  821. if args.actor.startswith('@'):
  822. args.actor=args.actor[1:]
  823. if '@' not in args.actor:
  824. print('Syntax: --actor nickname@domain')
  825. sys.exit()
  826. nickname=args.actor.split('@')[0]
  827. domain=args.actor.split('@')[1].replace('\n','')
  828. wfCache={}
  829. if args.http or domain.endswith('.onion'):
  830. httpPrefix='http'
  831. port=80
  832. else:
  833. httpPrefix='https'
  834. port=443
  835. session=createSession(useTor)
  836. if nickname=='inbox':
  837. nickname=domain
  838. wfRequest=webfingerHandle(session,nickname+'@'+domain,httpPrefix,wfCache, \
  839. None,__version__)
  840. if not wfRequest:
  841. print('Unable to webfinger '+nickname+'@'+domain)
  842. sys.exit()
  843. pprint(wfRequest)
  844. personUrl=None
  845. if wfRequest.get('errors'):
  846. print('wfRequest error: '+str(wfRequest['errors']))
  847. if '/users/' in args.actor or \
  848. '/profile/' in args.actor or \
  849. '/channel/' in args.actor:
  850. personUrl=originalActor
  851. else:
  852. sys.exit()
  853. asHeader = {'Accept': 'application/activity+json; profile="https://www.w3.org/ns/activitystreams"'}
  854. if not personUrl:
  855. personUrl = getUserUrl(wfRequest)
  856. if nickname==domain:
  857. personUrl=personUrl.replace('/users/','/actor/').replace('/channel/','/actor/').replace('/profile/','/actor/')
  858. if not personUrl:
  859. # try single user instance
  860. personUrl=httpPrefix+'://'+domain
  861. asHeader = {'Accept': 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'}
  862. if '/channel/' in personUrl:
  863. asHeader = {'Accept': 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'}
  864. personJson = getJson(session,personUrl,asHeader,None,__version__,httpPrefix,None)
  865. if personJson:
  866. pprint(personJson)
  867. else:
  868. print('Failed to get '+personUrl)
  869. sys.exit()
  870. if args.addaccount:
  871. if '@' in args.addaccount:
  872. nickname=args.addaccount.split('@')[0]
  873. domain=args.addaccount.split('@')[1]
  874. else:
  875. nickname=args.addaccount
  876. if not args.domain or not getConfigParam(baseDir,'domain'):
  877. print('Use the --domain option to set the domain name')
  878. sys.exit()
  879. if not validNickname(domain,nickname):
  880. print(nickname+' is a reserved name. Use something different.')
  881. sys.exit()
  882. if not args.password:
  883. print('Use the --password option to set the password for '+nickname)
  884. sys.exit()
  885. if len(args.password.strip())<8:
  886. print('Password should be at least 8 characters')
  887. sys.exit()
  888. if os.path.isdir(baseDir+'/accounts/'+nickname+'@'+domain):
  889. print('Account already exists')
  890. sys.exit()
  891. if os.path.isdir(baseDir+'/deactivated/'+nickname+'@'+domain):
  892. print('Account is deactivated')
  893. sys.exit()
  894. createPerson(baseDir,nickname,domain,port,httpPrefix,True,args.password.strip())
  895. if os.path.isdir(baseDir+'/accounts/'+nickname+'@'+domain):
  896. print('Account created for '+nickname+'@'+domain)
  897. else:
  898. print('Account creation failed')
  899. sys.exit()
  900. if args.addgroup:
  901. if '@' in args.addgroup:
  902. nickname=args.addgroup.split('@')[0]
  903. domain=args.addgroup.split('@')[1]
  904. else:
  905. nickname=args.addgroup
  906. if not args.domain or not getConfigParam(baseDir,'domain'):
  907. print('Use the --domain option to set the domain name')
  908. sys.exit()
  909. if not validNickname(domain,nickname):
  910. print(nickname+' is a reserved name. Use something different.')
  911. sys.exit()
  912. if not args.password:
  913. print('Use the --password option to set the password for '+nickname)
  914. sys.exit()
  915. if len(args.password.strip())<8:
  916. print('Password should be at least 8 characters')
  917. sys.exit()
  918. if os.path.isdir(baseDir+'/accounts/'+nickname+'@'+domain):
  919. print('Group already exists')
  920. sys.exit()
  921. createGroup(baseDir,nickname,domain,port,httpPrefix,True,args.password.strip())
  922. if os.path.isdir(baseDir+'/accounts/'+nickname+'@'+domain):
  923. print('Group created for '+nickname+'@'+domain)
  924. else:
  925. print('Group creation failed')
  926. sys.exit()
  927. if args.rmgroup:
  928. args.rmaccount=args.rmgroup
  929. if args.deactivate:
  930. args.rmaccount=args.deactivate
  931. if args.rmaccount:
  932. if '@' in args.rmaccount:
  933. nickname=args.rmaccount.split('@')[0]
  934. domain=args.rmaccount.split('@')[1]
  935. else:
  936. nickname=args.rmaccount
  937. if not args.domain or not getConfigParam(baseDir,'domain'):
  938. print('Use the --domain option to set the domain name')
  939. sys.exit()
  940. if args.deactivate:
  941. if deactivateAccount(baseDir,nickname,domain):
  942. print('Account for '+handle+' was deactivated')
  943. else:
  944. print('Account for '+handle+' was not found')
  945. sys.exit()
  946. if removeAccount(baseDir,nickname,domain,port):
  947. if not args.rmgroup:
  948. print('Account for '+handle+' was removed')
  949. else:
  950. print('Group '+handle+' was removed')
  951. sys.exit()
  952. if args.activate:
  953. if '@' in args.activate:
  954. nickname=args.activate.split('@')[0]
  955. domain=args.activate.split('@')[1]
  956. else:
  957. nickname=args.activate
  958. if not args.domain or not getConfigParam(baseDir,'domain'):
  959. print('Use the --domain option to set the domain name')
  960. sys.exit()
  961. if activateAccount(baseDir,nickname,domain):
  962. print('Account for '+handle+' was activated')
  963. else:
  964. print('Deactivated account for '+handle+' was not found')
  965. sys.exit()
  966. if args.changepassword:
  967. if len(args.changepassword)!=2:
  968. print('--changepassword [nickname] [new password]')
  969. sys.exit()
  970. if '@' in args.changepassword[0]:
  971. nickname=args.changepassword[0].split('@')[0]
  972. domain=args.changepassword[0].split('@')[1]
  973. else:
  974. nickname=args.changepassword[0]
  975. if not args.domain or not getConfigParam(baseDir,'domain'):
  976. print('Use the --domain option to set the domain name')
  977. sys.exit()
  978. newPassword=args.changepassword[1]
  979. if len(newPassword)<8:
  980. print('Password should be at least 8 characters')
  981. sys.exit()
  982. if not os.path.isdir(baseDir+'/accounts/'+nickname+'@'+domain):
  983. print('Account '+nickname+'@'+domain+' not found')
  984. sys.exit()
  985. passwordFile=baseDir+'/accounts/passwords'
  986. if os.path.isfile(passwordFile):
  987. if nickname+':' in open(passwordFile).read():
  988. storeBasicCredentials(baseDir,nickname,newPassword)
  989. print('Password for '+nickname+' was changed')
  990. else:
  991. print(nickname+' is not in the passwords file')
  992. else:
  993. print('Passwords file not found')
  994. sys.exit()
  995. archiveWeeks=4
  996. if args.archiveWeeks:
  997. archiveWeeks=args.archiveWeeks
  998. archiveMaxPosts=32000
  999. if args.archiveMaxPosts:
  1000. archiveMaxPosts=args.archiveMaxPosts
  1001. if args.archive:
  1002. if args.archive.lower().endswith('null') or \
  1003. args.archive.lower().endswith('delete') or \
  1004. args.archive.lower().endswith('none'):
  1005. args.archive=None
  1006. print('Archiving with deletion of old posts...')
  1007. else:
  1008. print('Archiving to '+args.archive+'...')
  1009. archiveMedia(baseDir,args.archive,archiveWeeks)
  1010. archivePosts(baseDir,httpPrefix,args.archive,archiveMaxPosts)
  1011. print('Archiving complete')
  1012. sys.exit()
  1013. if not args.domain and not domain:
  1014. print('Specify a domain with --domain [name]')
  1015. sys.exit()
  1016. if args.avatar:
  1017. if not os.path.isfile(args.avatar):
  1018. print(args.avatar+' is not an image filename')
  1019. sys.exit()
  1020. if not args.nickname:
  1021. print('Specify a nickname with --nickname [name]')
  1022. sys.exit()
  1023. if setProfileImage(baseDir,httpPrefix,args.nickname,domain, \
  1024. port,args.avatar,'avatar','128x128'):
  1025. print('Avatar added for '+args.nickname)
  1026. else:
  1027. print('Avatar was not added for '+args.nickname)
  1028. sys.exit()
  1029. if args.backgroundImage:
  1030. if not os.path.isfile(args.backgroundImage):
  1031. print(args.backgroundImage+' is not an image filename')
  1032. sys.exit()
  1033. if not args.nickname:
  1034. print('Specify a nickname with --nickname [name]')
  1035. sys.exit()
  1036. if setProfileImage(baseDir,httpPrefix,args.nickname,domain, \
  1037. port,args.backgroundImage,'background','256x256'):
  1038. print('Background image added for '+args.nickname)
  1039. else:
  1040. print('Background image was not added for '+args.nickname)
  1041. sys.exit()
  1042. if args.project:
  1043. if not args.delegate and not args.undelegate:
  1044. if not nickname:
  1045. print('No nickname given')
  1046. sys.exit()
  1047. if args.role.lower()=='none' or \
  1048. args.role.lower()=='remove' or \
  1049. args.role.lower()=='delete':
  1050. args.role=None
  1051. if args.role:
  1052. if setRole(baseDir,nickname,domain,args.project,args.role):
  1053. print('Role within '+args.project+' set to '+args.role)
  1054. else:
  1055. if setRole(baseDir,nickname,domain,args.project,None):
  1056. print('Left '+args.project)
  1057. sys.exit()
  1058. if args.skill:
  1059. if not nickname:
  1060. print('Specify a nickname with the --nickname option')
  1061. sys.exit()
  1062. if not args.password:
  1063. print('Specify a password with the --password option')
  1064. sys.exit()
  1065. if not args.skillLevelPercent:
  1066. print('Specify a skill level in the range 0-100')
  1067. sys.exit()
  1068. if int(args.skillLevelPercent)<0 or int(args.skillLevelPercent)>100:
  1069. print('Skill level should be a percentage in the range 0-100')
  1070. sys.exit()
  1071. session = createSession(useTor)
  1072. personCache={}
  1073. cachedWebfingers={}
  1074. print('Sending '+args.skill+' skill level '+str(args.skillLevelPercent)+' for '+nickname)
  1075. sendSkillViaServer(baseDir,session, \
  1076. nickname,args.password, \
  1077. domain,port, \
  1078. httpPrefix, \
  1079. args.skill,args.skillLevelPercent, \
  1080. cachedWebfingers,personCache, \
  1081. True,__version__)
  1082. for i in range(10):
  1083. # TODO detect send success/fail
  1084. time.sleep(1)
  1085. sys.exit()
  1086. if args.availability:
  1087. if not nickname:
  1088. print('Specify a nickname with the --nickname option')
  1089. sys.exit()
  1090. if not args.password:
  1091. print('Specify a password with the --password option')
  1092. sys.exit()
  1093. session = createSession(useTor)
  1094. personCache={}
  1095. cachedWebfingers={}
  1096. print('Sending availability status of '+nickname+' as '+args.availability)
  1097. sendAvailabilityViaServer(baseDir,session,nickname,args.password,
  1098. domain,port, \
  1099. httpPrefix, \
  1100. args.availability, \
  1101. cachedWebfingers,personCache, \
  1102. True,__version__)
  1103. for i in range(10):
  1104. # TODO detect send success/fail
  1105. time.sleep(1)
  1106. sys.exit()
  1107. if federationList:
  1108. print('Federating with: '+str(federationList))
  1109. #if not os.path.isdir(baseDir+'/accounts/'+nickname+'@'+domain):
  1110. # print('Creating default admin account '+nickname+'@'+domain)
  1111. # print('See config.json for the password. You can remove the password from config.json after moving it elsewhere.')
  1112. # adminPassword=createPassword(10)
  1113. # setConfigParam(baseDir,'adminPassword',adminPassword)
  1114. # createPerson(baseDir,nickname,domain,port,httpPrefix,True,adminPassword)
  1115. if args.block:
  1116. if not nickname:
  1117. print('Specify a nickname with the --nickname option')
  1118. sys.exit()
  1119. if not args.password:
  1120. print('Specify a password with the --password option')
  1121. sys.exit()
  1122. if '@' in args.block:
  1123. blockedDomain=args.block.split('@')[1].replace('\n','')
  1124. blockedNickname=args.block.split('@')[0]
  1125. blockedActor=httpPrefix+'://'+blockedDomain+'/users/'+blockedNickname
  1126. args.block=blockedActor
  1127. else:
  1128. if '/users/' not in args.block:
  1129. print(args.block+' does not look like an actor url')
  1130. sys.exit()
  1131. session = createSession(useTor)
  1132. personCache={}
  1133. cachedWebfingers={}
  1134. print('Sending block of '+args.block)
  1135. sendBlockViaServer(baseDir,session,nickname,args.password,
  1136. domain,port, \
  1137. httpPrefix,args.block, \
  1138. cachedWebfingers,personCache, \
  1139. True,__version__)
  1140. for i in range(10):
  1141. # TODO detect send success/fail
  1142. time.sleep(1)
  1143. sys.exit()
  1144. if args.delegate:
  1145. if not nickname:
  1146. print('Specify a nickname with the --nickname option')
  1147. sys.exit()
  1148. if not args.password:
  1149. print('Specify a password with the --password option')
  1150. sys.exit()
  1151. if not args.project:
  1152. print('Specify a project with the --project option')
  1153. sys.exit()
  1154. if not args.role:
  1155. print('Specify a role with the --role option')
  1156. sys.exit()
  1157. if '@' in args.delegate:
  1158. delegatedNickname=args.delegate.split('@')[0]
  1159. args.delegate=blockedActor
  1160. session = createSession(useTor)
  1161. personCache={}
  1162. cachedWebfingers={}
  1163. print('Sending delegation for '+args.delegate+' with role '+args.role+' in project '+args.project)
  1164. sendRoleViaServer(baseDir,session, \
  1165. nickname,args.password, \
  1166. domain,port, \
  1167. httpPrefix,args.delegate, \
  1168. args.project,args.role, \
  1169. cachedWebfingers,personCache, \
  1170. True,__version__)
  1171. for i in range(10):
  1172. # TODO detect send success/fail
  1173. time.sleep(1)
  1174. sys.exit()
  1175. if args.undelegate:
  1176. if not nickname:
  1177. print('Specify a nickname with the --nickname option')
  1178. sys.exit()
  1179. if not args.password:
  1180. print('Specify a password with the --password option')
  1181. sys.exit()
  1182. if not args.project:
  1183. print('Specify a project with the --project option')
  1184. sys.exit()
  1185. if '@' in args.undelegate:
  1186. delegatedNickname=args.undelegate.split('@')[0]
  1187. args.undelegate=blockedActor
  1188. session = createSession(useTor)
  1189. personCache={}
  1190. cachedWebfingers={}
  1191. print('Sending delegation removal for '+args.undelegate+' from role '+args.role+' in project '+args.project)
  1192. sendRoleViaServer(baseDir,session, \
  1193. nickname,args.password, \
  1194. domain,port, \
  1195. httpPrefix,args.delegate, \
  1196. args.project,None, \
  1197. cachedWebfingers,personCache, \
  1198. True,__version__)
  1199. for i in range(10):
  1200. # TODO detect send success/fail
  1201. time.sleep(1)
  1202. sys.exit()
  1203. if args.unblock:
  1204. if not nickname:
  1205. print('Specify a nickname with the --nickname option')
  1206. sys.exit()
  1207. if not args.password:
  1208. print('Specify a password with the --password option')
  1209. sys.exit()
  1210. if '@' in args.unblock:
  1211. blockedDomain=args.unblock.split('@')[1].replace('\n','')
  1212. blockedNickname=args.unblock.split('@')[0]
  1213. blockedActor=httpPrefix+'://'+blockedDomain+'/users/'+blockedNickname
  1214. args.unblock=blockedActor
  1215. else:
  1216. if '/users/' not in args.unblock:
  1217. print(args.unblock+' does not look like an actor url')
  1218. sys.exit()
  1219. session = createSession(useTor)
  1220. personCache={}
  1221. cachedWebfingers={}
  1222. print('Sending undo block of '+args.unblock)
  1223. sendUndoBlockViaServer(baseDir,session,nickname,args.password,
  1224. domain,port, \
  1225. httpPrefix,args.unblock, \
  1226. cachedWebfingers,personCache, \
  1227. True,__version__)
  1228. for i in range(10):
  1229. # TODO detect send success/fail
  1230. time.sleep(1)
  1231. sys.exit()
  1232. if args.filterStr:
  1233. if not args.nickname:
  1234. print('Please specify a nickname')
  1235. sys.exit()
  1236. if addFilter(baseDir,args.nickname,domain,args.filterStr):
  1237. print('Filter added to '+args.nickname+': '+args.filterStr)
  1238. sys.exit()
  1239. if args.unfilterStr:
  1240. if not args.nickname:
  1241. print('Please specify a nickname')
  1242. sys.exit()
  1243. if removeFilter(baseDir,args.nickname,domain,args.unfilterStr):
  1244. print('Filter removed from '+args.nickname+': '+args.unfilterStr)
  1245. sys.exit()
  1246. if args.testdata:
  1247. useBlurhash=False
  1248. nickname='testuser567'
  1249. password='boringpassword'
  1250. print('Generating some test data for user: '+nickname)
  1251. if os.path.isdir(baseDir+'/tags'):
  1252. shutil.rmtree(baseDir+'/tags')
  1253. if os.path.isdir(baseDir+'/accounts'):
  1254. shutil.rmtree(baseDir+'/accounts')
  1255. if os.path.isdir(baseDir+'/keys'):
  1256. shutil.rmtree(baseDir+'/keys')
  1257. if os.path.isdir(baseDir+'/media'):
  1258. shutil.rmtree(baseDir+'/media')
  1259. if os.path.isdir(baseDir+'/sharefiles'):
  1260. shutil.rmtree(baseDir+'/sharefiles')
  1261. if os.path.isdir(baseDir+'/wfendpoints'):
  1262. shutil.rmtree(baseDir+'/wfendpoints')
  1263. setConfigParam(baseDir,'registrationsRemaining',str(maxRegistrations))
  1264. createPerson(baseDir,'maxboardroom',domain,port,httpPrefix,True,password)
  1265. createPerson(baseDir,'ultrapancake',domain,port,httpPrefix,True,password)
  1266. createPerson(baseDir,'drokk',domain,port,httpPrefix,True,password)
  1267. createPerson(baseDir,'sausagedog',domain,port,httpPrefix,True,password)
  1268. createPerson(baseDir,nickname,domain,port,httpPrefix,True,'likewhateveryouwantscoob')
  1269. setSkillLevel(baseDir,nickname,domain,'testing',60)
  1270. setSkillLevel(baseDir,nickname,domain,'typing',50)
  1271. setRole(baseDir,nickname,domain,'instance','admin')
  1272. setRole(baseDir,nickname,domain,'epicyon','hacker')
  1273. setRole(baseDir,nickname,domain,'someproject','assistant')
  1274. setAvailability(baseDir,nickname,domain,'busy')
  1275. addShare(baseDir, \
  1276. httpPrefix,nickname,domain,port, \
  1277. "spanner", \
  1278. "It's a spanner", \
  1279. "img/shares1.png", \
  1280. "tool", \
  1281. "mechanical", \
  1282. "City", \
  1283. "2 months",
  1284. debug)
  1285. addShare(baseDir, \
  1286. httpPrefix,nickname,domain,port, \
  1287. "witch hat", \
  1288. "Spooky", \
  1289. "img/shares2.png", \
  1290. "hat", \
  1291. "clothing", \
  1292. "City", \
  1293. "3 months",
  1294. debug)
  1295. deleteAllPosts(baseDir,nickname,domain,'inbox')
  1296. deleteAllPosts(baseDir,nickname,domain,'outbox')
  1297. createPublicPost(baseDir,nickname,domain,port,httpPrefix,"like, this is totally just a #test, man",False,True,False,None,None,useBlurhash)
  1298. createPublicPost(baseDir,nickname,domain,port,httpPrefix,"Zoiks!!!",False,True,False,None,None,useBlurhash)
  1299. createPublicPost(baseDir,nickname,domain,port,httpPrefix,"Hey scoob we need like a hundred more #milkshakes",False,True,False,None,None,useBlurhash)
  1300. createPublicPost(baseDir,nickname,domain,port,httpPrefix,"Getting kinda spooky around here",False,True,False,None,None,useBlurhash,'someone')
  1301. createPublicPost(baseDir,nickname,domain,port,httpPrefix,"And they would have gotten away with it too if it wasn't for those pesky hackers",False,True,False,'img/logo.png','Description of image',useBlurhash)
  1302. createPublicPost(baseDir,nickname,domain,port,httpPrefix,"man, these centralized sites are, like, the worst!",False,True,False,None,None,useBlurhash)
  1303. createPublicPost(baseDir,nickname,domain,port,httpPrefix,"another mystery solved #test",False,True,False,None,None,useBlurhash)
  1304. createPublicPost(baseDir,nickname,domain,port,httpPrefix,"let's go bowling",False,True,False,None,None,useBlurhash)
  1305. domainFull=domain+':'+str(port)
  1306. clearFollows(baseDir,nickname,domain)
  1307. followPerson(baseDir,nickname,domain,'maxboardroom',domainFull,federationList,False)
  1308. followPerson(baseDir,nickname,domain,'ultrapancake',domainFull,federationList,False)
  1309. followPerson(baseDir,nickname,domain,'sausagedog',domainFull,federationList,False)
  1310. followPerson(baseDir,nickname,domain,'drokk',domainFull,federationList,False)
  1311. followerOfPerson(baseDir,nickname,domain,'drokk',domainFull,federationList,False)
  1312. followerOfPerson(baseDir,nickname,domain,'maxboardroom',domainFull,federationList,False)
  1313. setConfigParam(baseDir,'admin',nickname)
  1314. # set a lower bound to the maximum mentions
  1315. # so that it can't be accidentally set to zero and disable replies
  1316. if args.maxMentions<4:
  1317. args.maxMentions=4
  1318. registration=getConfigParam(baseDir,'registration')
  1319. if not registration:
  1320. registration=False
  1321. runDaemon(registration,args.language,__version__, \
  1322. instanceId,args.client,baseDir, \
  1323. domain,port,proxyPort,httpPrefix, \
  1324. federationList,args.maxMentions, \
  1325. args.authenticatedFetch, \
  1326. args.noreply,args.nolike,args.nopics, \
  1327. args.noannounce,args.cw,ocapAlways, \
  1328. useTor,args.maxReplies, \
  1329. args.domainMaxPostsPerDay,args.accountMaxPostsPerDay, \
  1330. args.allowdeletion,debug,False, \
  1331. args.instanceOnlySkillsSearch)