From 89c3c3fdde0b32d768f14d283b561e5b8ef53476 Mon Sep 17 00:00:00 2001 From: Philip Kin Date: Fri, 18 Nov 2016 17:04:50 -0600 Subject: [PATCH 1/4] Fixed csrf failures --- geeknote/oauth.py | 43 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/geeknote/oauth.py b/geeknote/oauth.py index 3c44a01..5e51d3d 100644 --- a/geeknote/oauth.py +++ b/geeknote/oauth.py @@ -7,6 +7,7 @@ import re from urllib import urlencode, unquote from urlparse import urlparse +from lxml import html import out import tools @@ -42,6 +43,7 @@ class GeekNoteAuth(object): 'oauth_token': None, 'oauth_callback': None, 'embed': 'false', + 'expireMillis': '31536000000', }, 'tfa': { 'code': '', @@ -72,7 +74,7 @@ def getTokenRequestData(self, **kwargs): return params - def loadPage(self, url, uri=None, method="GET", params=""): + def loadPage(self, url, uri=None, method="GET", params="", additionalParams=""): if not url: logging.error("Request URL undefined") tools.exitErr() @@ -84,7 +86,7 @@ def loadPage(self, url, uri=None, method="GET", params=""): # prepare params, append to uri if params: - params = urlencode(params) + params = urlencode(params) + additionalParams if method == "GET": uri += ('?' if uri.find('?') == -1 else '&') + params params = "" @@ -239,16 +241,49 @@ def login(self): #self.allowAccess(response.location) def allowAccess(self): + response = self.loadPage(self.url['base'], + self.url['access'], + "GET", + {'oauth_token': self.tmpOAuthToken}) + + logging.debug(response.data) + tree = html.fromstring(response.data); + token = "&" + urlencode({ 'csrfBusterToken': tree.xpath("//input[@name='csrfBusterToken']/@value")[0]}) + "&" + urlencode({ 'csrfBusterToken': tree.xpath("//input[@name='csrfBusterToken']/@value")[1]}) + sourcePage = tree.xpath("//input[@name='_sourcePage']/@value")[0] + fp = tree.xpath("//input[@name='__fp']/@value")[0] + targetUrl = tree.xpath("//input[@name='targetUrl']/@value")[0] + logging.debug(token); + + if response.status != 200: + logging.error("Unexpected response status " + "on login 200 != %s", response.status) + tools.exitErr() + + if 'JSESSIONID' not in self.cookies: + logging.error("Not found value JSESSIONID in the response cookies") + tools.exitErr() + access = self.postData['access'] access['oauth_token'] = self.tmpOAuthToken - access['oauth_callback'] = "https://" + self.url['base'] + access['oauth_callback'] = "" + access['embed'] = 'false' + access['suggestedNotebookName'] = 'Geeknote' + access['supportLinkedSandbox'] = '' + access['analyticsLoginOrigin'] = 'Other' + access['clipperFlow'] = 'false' + access['showSwitchService'] = 'true' + access['_sourcePage'] = sourcePage + access['__fp'] = fp + access['targetUrl'] = targetUrl + response = self.loadPage(self.url['base'], self.url['access'], - "POST", access) + "POST", access, token) if response.status != 302: logging.error("Unexpected response status on allowing " "access 302 != %s", response.status) + logging.error(response.data) tools.exitErr() responseData = self.parseResponse(response.location) From 9e1b27f021c4cd5a68142eb4c62fffbfc1693dfe Mon Sep 17 00:00:00 2001 From: Philip Kin Date: Fri, 18 Nov 2016 17:14:48 -0600 Subject: [PATCH 2/4] added lxml lib --- geeknote/setup.py | 141 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 geeknote/setup.py diff --git a/geeknote/setup.py b/geeknote/setup.py new file mode 100644 index 0000000..0f8c562 --- /dev/null +++ b/geeknote/setup.py @@ -0,0 +1,141 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from __future__ import with_statement +import sys +import os +import getpass +import codecs +import geeknote +from setuptools import setup +from setuptools.command.install import install + + +BASH_COMPLETION = ''' +_geeknote_command() +{ + COMPREPLY=() + cur="${COMP_WORDS[COMP_CWORD]}" + + SAVE_IFS=$IFS + IFS=" " + args="${COMP_WORDS[*]:1}" + IFS=$SAVE_IFS + + COMPREPLY=( $(compgen -W "`geeknote autocomplete ${args}`" -- ${cur}) ) + + return 0 +} +complete -F _geeknote_command geeknote +''' + +def read(fname): + return codecs.open(os.path.join(os.path.dirname(__file__), fname)).read() + +class full_install(install): + + user_options = install.user_options + [ + ('userhome', None, "(Linux only) Set user home directory for" + " bash completion (/home/{0})" + .format(getpass.getuser())) + ] + + def initialize_options(self): + install.initialize_options(self) + self.userhome = '' + + def run(self): + if sys.platform == 'linux2': + self.install_autocomplite() + install.run(self) + + def install_autocomplite(self): + if self.userhome: + self.userhome = '{0}/.bash_completion'.format(self.userhome) + else: + self.userhome = '/home/{0}/.bash_completion'.format(os.getlogin()) + + if not BASH_COMPLETION in open(self.userhome, 'r').read(): + with open(self.userhome, 'a') as completion: + print('Autocomplete was written to {0}'.format(self.userhome)) + completion.write(BASH_COMPLETION) + + +setup( + name='geeknote', + version=geeknote.__version__, + license='GPL', + author='Vitaliy Rodnenko', + author_email='vitaliy@rodnenko.ru', + description='Geeknote - is a command line client for Evernote, ' + 'that can be use on Linux, FreeBSD and OS X.', + long_description=read("README.md"), + url='http://www.geeknote.me', + packages=['geeknote'], + + classifiers=[ + 'Development Status :: 3 - Alpha', + 'Intended Audience :: End Users/Desktop', + 'License :: OSI Approved :: GNU General Public License (GPL)', + 'Environment :: Console', + 'Natural Language :: English', + 'Operating System :: OS Independent', + 'Programming Language :: Python', + 'Topic :: Utilities', + ], + + install_requires=[ + 'evernote>=1.17', + 'html2text', + 'sqlalchemy', + 'markdown2', + 'beautifulsoup4', + 'thrift', + 'lxml' + ], + + entry_points={ + 'console_scripts': [ + 'geeknote = geeknote.geeknote:main', + 'gnsync = geeknote.gnsync:main' + ] + }, +# cmdclass={ +# 'install': full_install +# }, + platforms='Any', + test_suite='tests', + zip_safe=False, + keywords='Evernote, console' +) + +""" +import time +import os +from setuptools import setup, find_packages + +# local +import config + +os.system('rm -rf geeknote') + +packages = ['geeknote.' + x for x in find_packages()] + ['geeknote'] + +# This is to properly encapsulate the library during egg generation +os.system('mkdir .geeknote && cp -pr * .geeknote/ && mv .geeknote geeknote') + +setup( + name = "geeknote", + version = time.strftime(str(config.VERSION) + '.%Y%m%d.%H%M'), + packages = packages, + author = 'Vitaliy Rodnenko', + author_email = 'vitaly@webpp.ru', + description = 'terminal-mode geeknote client and synchronizer', + entry_points = { + 'console_scripts': [ + 'geeknote = geeknote.geeknote:main', + 'gnsync = geeknote.gnsync:main', + ] + } +) +""" From 683dbee8e88e0a7c35fae90bdda4cef9fb172dbf Mon Sep 17 00:00:00 2001 From: Philip Kin Date: Fri, 18 Nov 2016 17:20:25 -0600 Subject: [PATCH 3/4] added lxml lib --- geeknote/setup.py | 141 ---------------------------------------------- setup.py | 3 +- 2 files changed, 2 insertions(+), 142 deletions(-) delete mode 100644 geeknote/setup.py diff --git a/geeknote/setup.py b/geeknote/setup.py deleted file mode 100644 index 0f8c562..0000000 --- a/geeknote/setup.py +++ /dev/null @@ -1,141 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from __future__ import with_statement -import sys -import os -import getpass -import codecs -import geeknote -from setuptools import setup -from setuptools.command.install import install - - -BASH_COMPLETION = ''' -_geeknote_command() -{ - COMPREPLY=() - cur="${COMP_WORDS[COMP_CWORD]}" - - SAVE_IFS=$IFS - IFS=" " - args="${COMP_WORDS[*]:1}" - IFS=$SAVE_IFS - - COMPREPLY=( $(compgen -W "`geeknote autocomplete ${args}`" -- ${cur}) ) - - return 0 -} -complete -F _geeknote_command geeknote -''' - -def read(fname): - return codecs.open(os.path.join(os.path.dirname(__file__), fname)).read() - -class full_install(install): - - user_options = install.user_options + [ - ('userhome', None, "(Linux only) Set user home directory for" - " bash completion (/home/{0})" - .format(getpass.getuser())) - ] - - def initialize_options(self): - install.initialize_options(self) - self.userhome = '' - - def run(self): - if sys.platform == 'linux2': - self.install_autocomplite() - install.run(self) - - def install_autocomplite(self): - if self.userhome: - self.userhome = '{0}/.bash_completion'.format(self.userhome) - else: - self.userhome = '/home/{0}/.bash_completion'.format(os.getlogin()) - - if not BASH_COMPLETION in open(self.userhome, 'r').read(): - with open(self.userhome, 'a') as completion: - print('Autocomplete was written to {0}'.format(self.userhome)) - completion.write(BASH_COMPLETION) - - -setup( - name='geeknote', - version=geeknote.__version__, - license='GPL', - author='Vitaliy Rodnenko', - author_email='vitaliy@rodnenko.ru', - description='Geeknote - is a command line client for Evernote, ' - 'that can be use on Linux, FreeBSD and OS X.', - long_description=read("README.md"), - url='http://www.geeknote.me', - packages=['geeknote'], - - classifiers=[ - 'Development Status :: 3 - Alpha', - 'Intended Audience :: End Users/Desktop', - 'License :: OSI Approved :: GNU General Public License (GPL)', - 'Environment :: Console', - 'Natural Language :: English', - 'Operating System :: OS Independent', - 'Programming Language :: Python', - 'Topic :: Utilities', - ], - - install_requires=[ - 'evernote>=1.17', - 'html2text', - 'sqlalchemy', - 'markdown2', - 'beautifulsoup4', - 'thrift', - 'lxml' - ], - - entry_points={ - 'console_scripts': [ - 'geeknote = geeknote.geeknote:main', - 'gnsync = geeknote.gnsync:main' - ] - }, -# cmdclass={ -# 'install': full_install -# }, - platforms='Any', - test_suite='tests', - zip_safe=False, - keywords='Evernote, console' -) - -""" -import time -import os -from setuptools import setup, find_packages - -# local -import config - -os.system('rm -rf geeknote') - -packages = ['geeknote.' + x for x in find_packages()] + ['geeknote'] - -# This is to properly encapsulate the library during egg generation -os.system('mkdir .geeknote && cp -pr * .geeknote/ && mv .geeknote geeknote') - -setup( - name = "geeknote", - version = time.strftime(str(config.VERSION) + '.%Y%m%d.%H%M'), - packages = packages, - author = 'Vitaliy Rodnenko', - author_email = 'vitaly@webpp.ru', - description = 'terminal-mode geeknote client and synchronizer', - entry_points = { - 'console_scripts': [ - 'geeknote = geeknote.geeknote:main', - 'gnsync = geeknote.gnsync:main', - ] - } -) -""" diff --git a/setup.py b/setup.py index e963105..0f8c562 100644 --- a/setup.py +++ b/setup.py @@ -90,7 +90,8 @@ def install_autocomplite(self): 'sqlalchemy', 'markdown2', 'beautifulsoup4', - 'thrift' + 'thrift', + 'lxml' ], entry_points={ From 7cc26f82bec552a7723f248fa634e46d31040a9e Mon Sep 17 00:00:00 2001 From: pipakin Date: Fri, 18 Nov 2016 19:26:07 -0600 Subject: [PATCH 4/4] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 07c009e..21eff6a 100755 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ You can install Geeknote as a python script. $ [sudo] apt-get update; [sudo] apt-get -y install python-setuptools # Download the repository. - $ git clone git://github.com/VitaliyRodnenko/geeknote.git + $ git clone git://github.com/pipakin/geeknote.git $ cd geeknote