Sfoglia il codice sorgente

Initial code commit

First draft taking code from Walter Huf and adding pieces of the
JIRACookieAuth (early drafts, needs revision) to handle relogins.
Original repo was
https://bitbucket.org/geekytwink/dudesnude_mail.git
for reference to Walter's code.
master
Nate Bohman 6 anni fa
parent
commit
51fc6658ac
5 ha cambiato i file con 332 aggiunte e 0 eliminazioni
  1. +15
    -0
      .idea/dudesnude_client.iml
  2. +4
    -0
      .idea/misc.xml
  3. +8
    -0
      .idea/modules.xml
  4. +121
    -0
      .idea/workspace.xml
  5. +184
    -0
      client.py

+ 15
- 0
.idea/dudesnude_client.iml Vedi File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="PackageRequirementsSettings">
<option name="requirementsPath" value="" />
</component>
<component name="TestRunnerService">
<option name="projectConfiguration" value="Twisted Trial" />
<option name="PROJECT_TEST_RUNNER" value="Twisted Trial" />
</component>
</module>

+ 4
- 0
.idea/misc.xml Vedi File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Python 2.7" project-jdk-type="Python SDK" />
</project>

+ 8
- 0
.idea/modules.xml Vedi File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/dudesnude_client.iml" filepath="$PROJECT_DIR$/.idea/dudesnude_client.iml" />
</modules>
</component>
</project>

+ 121
- 0
.idea/workspace.xml Vedi File

@@ -0,0 +1,121 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ChangeListManager">
<list default="true" id="b72e990d-b17a-470e-b0c4-327d1e6d5129" name="Default" comment="" />
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
<option name="TRACKING_ENABLED" value="true" />
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="FileEditorManager">
<leaf>
<file leaf-file-name="client.py" pinned="false" current-in-tab="true">
<entry file="file://$PROJECT_DIR$/client.py">
<provider selected="true" editor-type-id="text-editor" />
</entry>
</file>
</leaf>
</component>
<component name="ProjectFrameBounds" extendedState="1">
<option name="x" value="140" />
<option name="y" value="20" />
<option name="width" value="1400" />
<option name="height" value="990" />
</component>
<component name="ProjectView">
<navigator proportions="" version="1">
<foldersAlwaysOnTop value="true" />
</navigator>
<panes>
<pane id="Scope" />
<pane id="ProjectPane">
<subPane>
<expand>
<path>
<item name="dudesnude_client" type="b2602c69:ProjectViewProjectNode" />
<item name="dudesnude_client" type="462c0819:PsiDirectoryNode" />
</path>
</expand>
<select />
</subPane>
</pane>
</panes>
</component>
<component name="PropertiesComponent">
<property name="last_opened_file_path" value="$PROJECT_DIR$" />
<property name="settings.editor.selected.configurable" value="preferences.startup.tasks" />
</component>
<component name="RunDashboard">
<option name="ruleStates">
<list>
<RuleState>
<option name="name" value="ConfigurationTypeDashboardGroupingRule" />
</RuleState>
<RuleState>
<option name="name" value="StatusDashboardGroupingRule" />
</RuleState>
</list>
</option>
</component>
<component name="SvnConfiguration">
<configuration />
</component>
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="b72e990d-b17a-470e-b0c4-327d1e6d5129" name="Default" comment="" />
<created>1530625076390</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1530625076390</updated>
</task>
<servers />
</component>
<component name="ToolWindowManager">
<frame x="140" y="20" width="1400" height="990" extended-state="0" />
<editor active="true" />
<layout>
<window_info active="true" content_ui="combo" id="Project" order="0" visible="true" weight="0.25" />
<window_info anchor="bottom" id="TODO" order="6" />
<window_info anchor="bottom" id="Event Log" side_tool="true" />
<window_info anchor="bottom" id="Run" order="2" />
<window_info anchor="bottom" id="Version Control" show_stripe_button="false" />
<window_info anchor="bottom" id="Python Console" />
<window_info id="Structure" order="1" side_tool="true" weight="0.25" />
<window_info anchor="bottom" id="Terminal" />
<window_info anchor="bottom" id="Debug" order="3" weight="0.4" />
<window_info id="Favorites" side_tool="true" />
<window_info anchor="bottom" id="Find" order="1" />
<window_info anchor="right" id="Commander" internal_type="SLIDING" order="0" type="SLIDING" weight="0.4" />
<window_info anchor="bottom" id="Inspection" order="5" weight="0.4" />
<window_info anchor="right" content_ui="combo" id="Hierarchy" order="2" weight="0.25" />
<window_info anchor="right" id="Ant Build" order="1" weight="0.25" />
<window_info anchor="bottom" id="Cvs" order="4" weight="0.25" />
<window_info anchor="bottom" id="Message" order="0" />
</layout>
</component>
<component name="VcsContentAnnotationSettings">
<option name="myLimit" value="2678400000" />
</component>
<component name="editorHistoryManager">
<entry file="file://$PROJECT_DIR$/client.py">
<provider selected="true" editor-type-id="text-editor" />
</entry>
</component>
<component name="masterDetails">
<states>
<state key="ScopeChooserConfigurable.UI">
<settings>
<splitter-proportions>
<option name="proportions">
<list>
<option value="0.2" />
</list>
</option>
</splitter-proportions>
</settings>
</state>
</states>
</component>
</project>

+ 184
- 0
client.py Vedi File

@@ -0,0 +1,184 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Standard library imports
import argparse
import errno
import logging
import os
import re
import threading

# Related third party imports (If you used pip/apt/yum to install)
import arrow
from bs4 import BeautifulSoup as bs
from expand_path import expand_path
import requests
from requests.auth import AuthBase
from shm_dict import SHMDict

__author__ = "Nate Bohman"
__license__ = "GPL-3"
__version__ = "1.1.0"
__maintainer__ = "Nate Bohman"
__email__ = "natrinicle@gmail.com"

logger = logging.getLogger(__name__)

try:
unichr
except NameError:
unichr = chr

try:
unicode
except NameError:
unicode = str


DEFAULT_CFGDIR_BASE = expand_path("~/.config/dudesnude")
LOGIN_URL = {"default": "https://dudesnude.com/login.php",
"guest": "http://dudesnude.com/warning.php"}
LOGIN_INPUT_RGX = re.compile(r'<input.*name="(?P<name>[^"]+)".*value="(?P<value>[^"]+)"', re.I)


class DudesNudeCookieAuth(AuthBase):
def __init__(self, email, password="", cookie_dir=DEFAULT_CFGDIR_BASE):
self.cookie_dict = None
self._cookie_dir = ""
self.cookie_dir = cookie_dir

self._email = ""
self.email = email
self.password = password

self.session = requests.Session()

@property
def email(self):
return self._email

@email.setter
def email(self, value):
if self._email != value:
self._email = value
self.cookie_dict = SHMDict(name=self.cookie_file,
size=8192, is_file=True)

@property
def cookie_dir(self):
return self._cookie_dir

@cookie_dir.setter
def cookie_dir(self, value):
value = expand_path(value)

self._cookie_dir = value

try:
os.makedirs(value, mode=0o750)
except OSError as e:
if e.errno != errno.EEXIST:
raise


@property
def cookie_file(self):
return "{}/{}_cookies".format(self.cookie_dir,
self.email)

@property
def login_form_fields(self):
r = self.session.get(LOGIN_URL.get("default"))
self.cookie_dict['cookies'] = self.session.cookies

login_form_fields = {}
if LOGIN_INPUT_RGX.search(r.text):
for login_input in LOGIN_INPUT_RGX.finditer(r.text):
login_input = login_input.groupdict()
login_form_fields[login_input.get("name")] = login_input.get("value")
return login_form_fields

@property
def login_data(self):
if self.email == "guest":
return {'go': '1', 'iagree': '1', 'token': '', 'win_x': '1080', 'win_y': '720'}
else:
login_form_fields = self.login_form_fields

assert login_form_fields.get('s_token') is not None
assert self.cookie_dict['cookies'].get('PHPSESSID') is not None

login_data = {
'PHPSESSID': self.cookie_dict['cookies'].get('PHPSESSID'),
's_token': login_form_fields.get('s_token'),
'email': self.email,
'pass': self.password,
'logon': '1',
'seeking': '0', # 0 -, 1 chat only, 2 hookups
'tz': 0, # Force GMT
'win_x': '1080', # Force desktop
'win_y': '720', # Force desktop
}

return login_data

def login(self):
with self.cookie_dict.exclusive_lock():
if self.cookie_dict.get('last_refresh') is None:
log_message = "Creating cookie {}".format(self.cookie_file)
else:
log_message = "Updating cookie that was last refreshed {}".format(
self.cookie_dict.get('last_refresh').humanize())
logger.info(log_message)

r = self.session.post(LOGIN_URL.get(self.email, LOGIN_URL.get("default")),
data=self.login_data)

# Check for HTTP error codes
r.raise_for_status()

# Check for bad URL
if self.email == "guest" and r.url != 'http://dudesnude.com/search_menu.php':
raise Exception('Failure to log in')
if self.email != "guest" and r.url == 'http://dudesnude.com/login.php':
raise Exception('Failure to log in')

self.cookie_dict['cookies'] = self.session.cookies
self.cookie_dict['last_refresh'] = arrow.utcnow()

def handle_relogin(self, r, **kwargs):
"""Handle logging back in if response URL indicates not logged in."""
if not r.url == 'http://dudesnude.com/enable_cookies.php':
return r
self.login()

def __call__(self, req):
"""Handle every call through requests to webpage."""
# Login if cookies dict doesn't exist
if self.cookie_dict.get('last_refresh') is None:
self.login()

# Clean up, since we can't generate new cookies otherwise
if 'Cookie' in req.headers:
del req.headers['Cookie']

# Add saved cookies to request
req.prepare_cookies(self.cookie_dict.get('cookies'))

# Register a method that is called after every request
# to ensure that we don't have to login.
req.register_hook('response', self.handle_relogin)

return req


class DudesNudeClient(object):
def __init__(self, email, password, config_dir=DEFAULT_CFGDIR_BASE):
self._config_dir = ""
self.config_dir = config_dir

#self.guest_session = requests.Session()
#self.guest_session.auth = DudesNudeCookieAuth(email="guest")
self.session = requests.Session()
self.session.auth = DudesNudeCookieAuth(email=email, password=password)

Loading…
Annulla
Salva