优化代码结构

super_signature
nineven 5 years ago
parent d9b0d3718c
commit 9f21a2f51e
  1. 2
      fir_ser/api/urls.py
  2. 6
      fir_ser/api/utils/TokenManager.py
  3. 46
      fir_ser/api/utils/ali/__init__.py
  4. 58
      fir_ser/api/utils/ali/api.py
  5. 3
      fir_ser/api/utils/ali/client/__init__.py
  6. 3
      fir_ser/api/utils/ali/client/api/__init__.py
  7. 13
      fir_ser/api/utils/ali/client/api/certify.py
  8. 3
      fir_ser/api/utils/ali/client/basic.py
  9. 3
      fir_ser/api/utils/ali/pay/__init__.py
  10. 10
      fir_ser/api/utils/ali/pay/api/__init__.py
  11. 82
      fir_ser/api/utils/ali/pay/api/app.py
  12. 31
      fir_ser/api/utils/ali/pay/api/base.py
  13. 44
      fir_ser/api/utils/ali/pay/api/order.py
  14. 81
      fir_ser/api/utils/ali/pay/api/page.py
  15. 100
      fir_ser/api/utils/ali/pay/api/transfer.py
  16. 81
      fir_ser/api/utils/ali/pay/api/wap.py
  17. 198
      fir_ser/api/utils/ali/pay/basic.py
  18. 69
      fir_ser/api/utils/ali/tools.py
  19. 12
      fir_ser/api/utils/ali/yun/__init__.py
  20. 7
      fir_ser/api/utils/ali/yun/api/__init__.py
  21. 41
      fir_ser/api/utils/ali/yun/api/base.py
  22. 144
      fir_ser/api/utils/ali/yun/api/sms.py
  23. 212
      fir_ser/api/utils/ali/yun/api/vod.py
  24. 224
      fir_ser/api/utils/ali/yun/basic.py
  25. 19
      fir_ser/api/utils/app/apputils.py
  26. 73
      fir_ser/api/utils/app/dadf.py
  27. 14
      fir_ser/api/utils/app/iossignapi.py
  28. 6
      fir_ser/api/utils/app/shellcmds.py
  29. 21
      fir_ser/api/utils/app/supersignutils.py
  30. 48
      fir_ser/api/utils/captcha_verify.py
  31. 6
      fir_ser/api/utils/crontab/run.py
  32. 11
      fir_ser/api/utils/crontab/sync_cache.py
  33. 199
      fir_ser/api/utils/geetest.py
  34. 19
      fir_ser/api/utils/permission.py
  35. 6
      fir_ser/api/utils/serializer.py
  36. 2
      fir_ser/api/utils/storage/caches.py
  37. 8
      fir_ser/api/utils/storage/localApi.py
  38. 5
      fir_ser/api/utils/storage/storage.py
  39. 36
      fir_ser/api/views/captcha.py
  40. 2
      fir_ser/api/views/login.py
  41. 2
      fir_ser/api/views/logout.py
  42. 1
      fir_ser/fir_ser/urls.py

@ -18,7 +18,6 @@ from django.urls import path, re_path, include
from api.views.login import LoginView, UserInfoView from api.views.login import LoginView, UserInfoView
from api.views.logout import LogoutView from api.views.logout import LogoutView
from api.views.captcha import AjaxExampleForm
from api.views.apps import AppsView, AppInfoView, AppReleaseinfoView from api.views.apps import AppsView, AppInfoView, AppReleaseinfoView
from api.views.download import ShortDownloadView from api.views.download import ShortDownloadView
from api.views.uploads import AppAnalyseView, UploadView from api.views.uploads import AppAnalyseView, UploadView
@ -34,7 +33,6 @@ urlpatterns = [
# path("",include(router.urls)), # path("",include(router.urls)),
re_path("^login", LoginView.as_view()), re_path("^login", LoginView.as_view()),
re_path("^logout", LogoutView.as_view()), re_path("^logout", LogoutView.as_view()),
re_path("^captcha_check/", AjaxExampleForm.as_view()),
re_path("^apps$", AppsView.as_view()), re_path("^apps$", AppsView.as_view()),
re_path("^storage$", StorageView.as_view()), re_path("^storage$", StorageView.as_view()),
re_path("^apps/(?P<app_id>\w+)", AppInfoView.as_view()), re_path("^apps/(?P<app_id>\w+)", AppInfoView.as_view()),

@ -10,12 +10,6 @@ import time
from django.core.cache import cache from django.core.cache import cache
from fir_ser.settings import CACHE_KEY_TEMPLATE from fir_ser.settings import CACHE_KEY_TEMPLATE
'''
user = cache.get(token)
delta = datetime.timedelta(weeks=2) - delta
cache.set(token_obj.key, token_obj.user, min(delta.total_seconds(), 3600 * 24 * 7))
'''
class DownloadToken(object): class DownloadToken(object):

@ -1,46 +0,0 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# Date: 2018/8/2
"""
阿里巴巴旗下相关服务
蚂蚁金服
阿里云
因阿里云权限访问控制, 可能每种服务都会映射到一个访问key和秘钥(当然也可以用最大权限)
"""
import logging
import requests
logger = logging.getLogger(__name__)
class BaseAli(object):
API_BASE_URL = ""
_http = requests.session()
def __init__(self, timeout, auto_retry=False):
self.timeout = timeout
self.auto_retry = auto_retry
def request(self, *args, **kwargs):
raise NotImplementedError()
def get(self, url, **kwargs):
return self.request(
method="get",
url_or_endpoint=url,
**kwargs
)
def post(self, url, **kwargs):
return self.request(
method="post",
url_or_endpoint=url,
**kwargs
)

@ -1,58 +0,0 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# Date: 2018/8/2
"""
阿里 api 调用出口
封装更易用的api
"""
from django.conf import settings
from django.utils.functional import LazyObject
from .pay.basic import AliPay
from .yun.basic import AliYunClient
class AliApi(object):
# 默认的支付配置
DEFAULT_ALI_PAY_CONFIG = settings.THIRD_PART_CONFIG["ALI_PAY"]["default"]
# 指定的支付配置(业务拓展)
SPECIFIC_ALI_PAY_CONFIG = settings.THIRD_PART_CONFIG["ALI_PAY"].get("pay") or DEFAULT_ALI_PAY_CONFIG
# 注册云配置
ALI_YUN_CONFIG = settings.THIRD_PART_CONFIG["ALI_YUN"]
def __init__(self, ):
# 支付类业务
self.pay = AliPay(
app_id=self.SPECIFIC_ALI_PAY_CONFIG["app_id"],
app_private_key_path=self.SPECIFIC_ALI_PAY_CONFIG["app_private_key_path"],
ali_public_key_path=self.SPECIFIC_ALI_PAY_CONFIG["alipay_public_key_path"],
notify_url=self.SPECIFIC_ALI_PAY_CONFIG["callback_url"],
return_url=self.SPECIFIC_ALI_PAY_CONFIG["callback_url"],
debug=self.SPECIFIC_ALI_PAY_CONFIG["debug"]
)
# 转账类业务
self.transfer = AliPay(
app_id=self.DEFAULT_ALI_PAY_CONFIG["app_id"],
app_private_key_path=self.DEFAULT_ALI_PAY_CONFIG["app_private_key_path"],
ali_public_key_path=self.DEFAULT_ALI_PAY_CONFIG["alipay_public_key_path"],
notify_url=self.SPECIFIC_ALI_PAY_CONFIG["callback_url"],
return_url=self.SPECIFIC_ALI_PAY_CONFIG["callback_url"],
debug=self.DEFAULT_ALI_PAY_CONFIG["debug"]
)
# 阿里云业务
self.yun = AliYunClient(
app_id=self.ALI_YUN_CONFIG.get("ACCESS_KEY"),
secret=self.ALI_YUN_CONFIG.get("SECRET")
)
class DefaultApi(LazyObject):
def _setup(self):
self._wrapped = AliApi()
ali_api = DefaultApi()

@ -1,3 +0,0 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# Date: 2018/8/2

@ -1,3 +0,0 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# Date: 2018/8/2

@ -1,13 +0,0 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# Date: 2018/8/2
"""
实名认证相关接口实现, 实名认证三步走
认证初始化 > 开始认证 > 认证查询
"""
class AliCertification(object):
pass

@ -1,3 +0,0 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# Date: 2018/8/2

@ -1,3 +0,0 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# Date: 2018/8/2

@ -1,10 +0,0 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# Date: 2018/8/2
from .page import AliPage
from .wap import AliWap
from .app import AliApp
from .transfer import AliTransfer
from .order import AliOrder

@ -1,82 +0,0 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# Date: 2018/8/2
"""
App支付
"""
import logging
from .base import BaseAliPayAPI
logger = logging.getLogger(__name__)
class AliApp(BaseAliPayAPI):
def direct(self, subject, out_trade_no, total_amount, notify_url=None, return_url=None, **kwargs):
"""App快速下单接口
文档DOC地址: https://docs.open.alipay.com/203/105288/
Parameters
----------
subject : string
订单标题
out_trade_no : string
商户订单号唯一凭证
total_amount : string or float or int
支付金额单位元精确到分
notify_url: string
支付宝服务器主动通知商户服务器里指定的页面http/https路径
example: http://www.alipay.com/pay
return_url: string
同步返回地址HTTP/HTTPS开头字符串
kwargs : dict
以下均为可选参数
body : string
订单描述
goods_detail : json
订单包含的商品列表信息Json格式 {&quot;show_url&quot;:&quot;https://或http://打头的商品的展示地址&quot;}
在支付时可点击商品名称跳转到该地址
passback_params : string
公用回传参数如果请求时传递了该参数则返回给商户时会回传该参数
支付宝只会在异步通知时将该参数原样返回
本参数必须进行UrlEncode之后才可以发送给支付宝
goods_type : int
商品主类型0; 虚拟类商品1; 实物类商品默认
extend_params :
业务扩张参数(主要用于接入花呗分期)
Returns
-------
dict
"""
biz_content = {
"subject": subject,
"out_trade_no": out_trade_no,
"total_amount": total_amount,
"product_code": "QUICK_MSECURITY_PAY", # 销售产品码,目前仅支持这个类型
# "qr_pay_mode":4
}
biz_content.update(**kwargs)
return self._generate_url("alipay.trade.app.pay", biz_content, notify_url, return_url)

@ -1,31 +0,0 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# Date: 2018/8/2
class BaseAliPayAPI(object):
"""
支付宝支付API基类
"""
def __init__(self, client=None):
self._client = client
def _get(self, url, **kwargs):
if hasattr(self, "API_BASE_URL"):
kwargs['api_base_url'] = getattr(self, "API_BASE_URL")
return self._client.get(url, **kwargs)
def _post(self, url, **kwargs):
if hasattr(self, "API_BASE_URL"):
kwargs['api_base_url'] = getattr(self, "API_BASE_URL")
return self._client.post(url, **kwargs)
def _generate_url(self, method, *args, **kwargs):
return self._client.generate_url(method, *args, **kwargs)
@property
def app_id(self):
return self._client.app_id

@ -1,44 +0,0 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# Date: 2018/8/2
"""
统一收单相关服务
"""
import logging
from .base import BaseAliPayAPI
logger = logging.getLogger(__name__)
class AliOrder(BaseAliPayAPI):
def query(self, out_biz_no=None, trade_no=None, **kwargs):
"""统一收单线下交易查询.
Parameters
----------
out_biz_no : string
订单支付时传入的商户订单号,和支付宝交易号不能同时为空
trade_no,out_trade_no如果同时存在优先取trade_no
trade_no : string
支付宝交易号和商户订单号不能同时为空
Returns
-------
dict
"""
biz_content = {
"out_biz_no": out_biz_no,
"trade_no": trade_no
}
biz_content.update(kwargs)
url = self._generate_url("alipay.trade.query", biz_content)
return self._get(url)

@ -1,81 +0,0 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# Date: 2018/8/2
"""
PC支付场景
"""
import logging
from .base import BaseAliPayAPI
logger = logging.getLogger(__name__)
class AliPage(BaseAliPayAPI):
def direct(self, subject, out_trade_no, total_amount, notify_url=None, return_url=None, **kwargs):
"""PC快速下单接口
文档DOC地址: https://docs.open.alipay.com/270/alipay.trade.page.pay
Parameters
----------
subject : string
订单标题
out_trade_no : string
商户订单号唯一凭证
total_amount : string or float or int
支付金额单位元精确到分
notify_url: string
支付宝服务器主动通知商户服务器里指定的页面http/https路径
example: http://www.alipay.com/pay
return_url: string
同步返回地址HTTP/HTTPS开头字符串
kwargs : dict
以下均为可选参数
body : string
订单描述
goods_detail : json
订单包含的商品列表信息Json格式 {&quot;show_url&quot;:&quot;https://或http://打头的商品的展示地址&quot;}
在支付时可点击商品名称跳转到该地址
passback_params : string
公用回传参数如果请求时传递了该参数则返回给商户时会回传该参数
支付宝只会在异步通知时将该参数原样返回
本参数必须进行UrlEncode之后才可以发送给支付宝
goods_type : int
商品主类型0; 虚拟类商品1; 实物类商品默认
extend_params :
业务扩张参数(主要用于接入花呗分期)
Returns
-------
dict
"""
biz_content = {
"subject": subject,
"out_trade_no": out_trade_no,
"total_amount": total_amount,
"product_code": "FAST_INSTANT_TRADE_PAY", # 销售产品码,目前仅支持这个类型
# "qr_pay_mode":4
}
biz_content.update(**kwargs)
return self._generate_url("alipay.trade.page.pay", biz_content, notify_url, return_url)

@ -1,100 +0,0 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# Date: 2018/8/2
"""
转账支付 `api`
"""
import logging
from .base import BaseAliPayAPI
logger = logging.getLogger(__name__)
class AliTransfer(BaseAliPayAPI):
def transfer(self, out_biz_no, payee_account, amount, payee_real_name, is_verify=True, **kwargs):
"""转账接口
在构建完成数据结构体之前进行验证码校验
该方法加入了 业务代码, 业务若有变动, 请根据实际需求进行更改
Parameters
----------
out_biz_no : string
商户转账唯一凭证
payee_account : string
收款方账户
amount : string or int or float
转账金额(单位: , 保留俩位小数, 最小转帐金额 0.1)
payee_real_name: string
收款方真实姓名
is_verify: bool, default: True
是否进行验证码校验
kwargs : dict
以下均为可选参数
payer_show_name : string
付款方姓名
remark : string
转账备注支持200个英文/100个汉字当付款方为企业账户且转账金额达到大于等于50000remark不能为空
收款方可见会展示在收款用户的收支详情中
Returns
-------
dict
"""
# 如果需要校验, 获取验证码进行校验, 校验不通过直接响应校验不通过
if is_verify:
kwargs.pop("verify_code", None)
biz_content = {
"out_biz_no": out_biz_no,
"payee_account": payee_account,
"payee_type": "ALIPAY_LOGONID", # 收款方账户类型
"amount": amount,
"payee_real_name": payee_real_name
}
biz_content.update(**kwargs)
url = self._generate_url("alipay.fund.trans.toaccount.transfer", biz_content)
return self._get(url)
def query(self, out_biz_no, order_id, **kwargs):
"""转账交易查询接口.
Parameters
----------
out_biz_no : string
商户转账唯一凭证
order_id : string
支付宝商户转账唯一凭证
Returns
-------
dict
"""
biz_content = {
"out_biz_no": out_biz_no,
"order_id": order_id
}
biz_content.update(kwargs)
url = self._generate_url("alipay.fund.trans.order.query", biz_content)
return self._get(url)

@ -1,81 +0,0 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# Date: 2018/8/2
"""
手机网站支付
"""
import logging
from .base import BaseAliPayAPI
logger = logging.getLogger(__name__)
class AliWap(BaseAliPayAPI):
def direct(self, subject, out_trade_no, total_amount, notify_url=None, return_url=None, **kwargs):
"""WAP快速下单接口
文档DOC地址: https://docs.open.alipay.com/203/105288/
Parameters
----------
subject : string
订单标题
out_trade_no : string
商户订单号唯一凭证
total_amount : string or float or int
支付金额单位元精确到分
notify_url: string
支付宝服务器主动通知商户服务器里指定的页面http/https路径
example: http://www.alipay.com/pay
return_url: string
同步返回地址HTTP/HTTPS开头字符串
kwargs : dict
以下均为可选参数
body : string
订单描述
goods_detail : json
订单包含的商品列表信息Json格式 {&quot;show_url&quot;:&quot;https://或http://打头的商品的展示地址&quot;}
在支付时可点击商品名称跳转到该地址
passback_params : string
公用回传参数如果请求时传递了该参数则返回给商户时会回传该参数
支付宝只会在异步通知时将该参数原样返回
本参数必须进行UrlEncode之后才可以发送给支付宝
goods_type : int
商品主类型0; 虚拟类商品1; 实物类商品默认
extend_params :
业务扩张参数(主要用于接入花呗分期)
Returns
-------
dict
"""
biz_content = {
"subject": subject,
"out_trade_no": out_trade_no,
"total_amount": total_amount,
"product_code": "QUICK_WAP_WAY", # 销售产品码,目前仅支持这个类型
# "qr_pay_mode":4
}
biz_content.update(**kwargs)
return self._generate_url("alipay.trade.wap.pay", biz_content, notify_url, return_url)

@ -1,198 +0,0 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# Date: 2018/8/2
import json
import inspect
from urllib.parse import quote_plus
from Crypto.PublicKey import RSA
from django.utils.timezone import now
from .. import BaseAli
from ..tools import calculate_signature
from .api.base import BaseAliPayAPI
from . import api
def _is_api_endpoint(instance):
return issubclass(instance.__class__, BaseAliPayAPI)
class AliPay(BaseAli):
# 在构造函数中初始化
API_BASE_URL = ""
# PC支付
pc = api.AliPage()
# Wap支付
wap = api.AliWap()
# App支付
app = api.AliApp()
# 转账
transfer = api.AliTransfer()
# 统一收单相关
order = api.AliOrder()
def __init__(
self, app_id, app_private_key_path, ali_public_key_path,
notify_url, return_url, debug,
):
# 如果是调试模式,则用调试api
if debug:
setattr(self, "API_BASE_URL", "https://openapi.alipaydev.com/gateway.do")
else:
setattr(self, "API_BASE_URL", "https://openapi.alipay.com/gateway.do")
# 暂时用不到父类方法参数(设置默认值)
super(AliPay, self).__init__(timeout=3, auto_retry=True)
self.app_id = app_id
self.notify_url = notify_url
self.return_url = return_url
# 加载应用的私钥
with open(app_private_key_path) as fp:
self.app_private_key = RSA.importKey(fp.read())
# 加载支付宝公钥
with open(ali_public_key_path) as fp:
self.ali_public_key = RSA.importKey(fp.read())
def __new__(cls, *args, **kwargs):
self = super(AliPay, cls).__new__(cls)
api_endpoints = inspect.getmembers(self, _is_api_endpoint)
for name, api_ins in api_endpoints:
api_cls = type(api_ins)
api_ins = api_cls(self)
setattr(self, name, api_ins)
return self
def request(self, method, url_or_endpoint, **kwargs):
if not url_or_endpoint.startswith(('http://', 'https://')):
api_base_url = kwargs.pop('api_base_url', self.API_BASE_URL)
url = '{base}{endpoint}'.format(
base=api_base_url,
endpoint=url_or_endpoint
)
else:
url = url_or_endpoint
res = self._http.request(
method=method,
url=url,
**kwargs
)
res.raise_for_status()
return self._handle_result(res)
def _handle_result(self, res):
"""解析请求结果并校验签名
"""
return res.json()
def get_url_params(self, data):
data.pop("sign", None)
# 排序后[(k, v), ...]
ordered_items = sorted(
((k, v if not isinstance(v, dict) else json.dumps(v, separators=(',', ':')))
for k, v in data.items())
)
# 拼接成待签名的字符串
unsigned_string = "&".join("{0}={1}".format(k, v) for k, v in ordered_items)
# 对上一步得到的字符串进行签名
sign = calculate_signature(unsigned_string.encode("utf-8"), self.app_private_key)
# 处理URL
quoted_string = "&".join("{0}={1}".format(k, quote_plus(v)) for k, v in ordered_items)
# 添加签名,获得最终的订单信息字符串
signed_string = quoted_string + "&sign=" + quote_plus(sign)
return signed_string
def build_body(self, method, biz_content, notify_url=None, return_url=None):
"""构建请求体
公有请求体 + 业务请求体
Parameters
----------
method : string
请求API
biz_content: dict
业务参数
notify_url: string, default: None
异步通知地址
return_url: string, default: None
同步地址
Returns
-------
请求参数: dict
"""
data = {
"app_id": self.app_id,
"method": method,
"charset": "utf-8",
"sign_type": "RSA2",
"timestamp": now().strftime("%Y-%m-%d %H:%M:%S"),
"version": "1.0",
"biz_content": biz_content
}
# 同步回调
if notify_url is not None:
data["notify_url"] = notify_url
# 异步回调
if return_url is not None:
data["return_url"] = return_url
return data
def generate_url(self, method, biz_content, notify_url=None, return_url=None):
"""构建请求体.
公有请求体 + 业务请求体
Parameters
----------
method : string
请求API
biz_content: dict
业务参数
notify_url: string, default: None
异步通知 `url`
return_url: string, default: None
同步通知 `url`
Returns
-------
string
"""
if notify_url is None:
notify_url = self.notify_url
if return_url is None:
return_url = self.return_url
body = self.build_body(method, biz_content, notify_url, return_url)
params = self.get_url_params(body)
return "{}?{}".format(self.API_BASE_URL, params)

@ -1,69 +0,0 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# Date: 2018/8/2
import json
import time
import uuid
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA256
from base64 import encodebytes
from base64 import decodebytes
def format_params(params):
"""格式化参数
"""
return sorted(
((k, v if not isinstance(v, dict) else json.dumps(v, separators=(',', ':'))) for k, v in params.items())
)
def verify_signature(params, api_key):
"""验证签名
"""
sign = params.pop("sign", "")
if "sign_type" in params:
params.pop("sign_type")
# 针对字符串进行排序
ordered_items = format_params(params)
message = "&".join(u"{}={}".format(k, v) for k, v in ordered_items)
# 验签
signer = PKCS1_v1_5.new(api_key)
digest = SHA256.new()
digest.update(message.encode("utf8"))
if signer.verify(digest, decodebytes(sign.encode("utf8"))):
return True
return False
def calculate_signature(params, api_key):
"""计算签名
"""
signer = PKCS1_v1_5.new(api_key)
signature = signer.sign(SHA256.new(params))
# base64 编码,转换为unicode表示并移除回车
sign = encodebytes(signature).decode("utf8").replace("\n", "")
return sign
def get_uuid():
"""获取 `UUID`
"""
return str(uuid.uuid4())
def get_iso_8061_date():
"""获取 `iso` 标准时间
"""
return time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())

@ -1,12 +0,0 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# Date: 2018/9/18
"""
阿里云相关服务, 目前提供支持
点播服务
短信服务
"""

@ -1,7 +0,0 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# Date: 2018/9/18
from .vod import AliYunVod
from .sms import AliYunSms

@ -1,41 +0,0 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# Date: 2018/9/18
class BaseAliYunAPI(object):
"""
阿里云服务API基类
"""
def __init__(self, client=None):
self._client = client
def _get(self, action, **kwargs):
if hasattr(self, "API_BASE_URL"):
kwargs['api_base_url'] = getattr(self, "API_BASE_URL")
if hasattr(self, "VERSION"):
kwargs["version"] = getattr(self, "VERSION")
return self._client.get(action, **kwargs)
def _post(self, action, **kwargs):
if hasattr(self, "API_BASE_URL"):
kwargs['api_base_url'] = getattr(self, "API_BASE_URL")
if hasattr(self, "VERSION"):
kwargs["version"] = getattr(self, "VERSION")
return self._client.post(action, **kwargs)
@property
def app_id(self):
return self._client.app_id
@property
def secret_key(self):
return self._client.secret_key

@ -1,144 +0,0 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# Date: 2018/9/18
"""
短信服务
"""
from .base import BaseAliYunAPI
class AliYunSms(BaseAliYunAPI):
VERSION = "2017-05-25"
API_BASE_URL = "http://dysmsapi.aliyuncs.com/"
def send(self, phone_numbers, sign_name, template_code, template_param, **kwargs):
"""发送短信
详情参见
https://help.aliyun.com/document_detail/55284.html?spm=5176.8195934.1001856.3.a36a4183xdfqaD
Parameters
----------
phone_numbers : string
短信接收号码,支持以逗号分隔的形式进行批量调用批量上限为1000个手机号码.
发送国际/港澳台消息时接收号码格式为00+国际区号+号码0085200000000
sign_name: string
短信签名
template_code: string
短信模板ID发送国际/港澳台消息时请使用国际/港澳台短信模版
template_param: json
短信模板变量替换JSON串,友情提示:如果JSON中需要带换行符,请参照标准的JSON协议
kwargs: dict
可选字段
SmsUpExtendCode
上行短信扩展码,无特殊需要此字段的用户请忽略此字段
OutId
外部流水扩展字段
Returns
-------
dict
"""
data = {
"PhoneNumbers": phone_numbers,
"SignName": sign_name,
"TemplateCode": template_code,
"TemplateParam": template_param
}
data.update(**kwargs)
return self._get(action="SendSms", data=data)
def send_batch(
self,
phone_number_json,
sign_name_json,
template_code,
template_param_json,
sms_upextend_code_json=None,
):
"""短信批量发送
详情参见
https://help.aliyun.com/document_detail/66041.html?spm=a2c4g.11186623.6.565.290415e8yJ7E0N
Parameters
----------
phone_number_json : string
短信接收号码,JSON格式,批量上限为100个手机号码,
批量调用相对于单条调用及时性稍有延迟,验证码类型的短信推荐使用单条调用的方式
sign_name_json: string
短信签名,JSON格式
template_code: int
短信模板ID
template_param_json: int
短信模板变量替换JSON串,友情提示:如果JSON中需要带换行符,请参照标准的JSON协议
sms_upextend_code_json: string
上行短信扩展码,JSON格式无特殊需要此字段的用户请忽略此字段
"""
data = {
"PhoneNumberJson": phone_number_json,
"SignNameJson": sign_name_json,
"TemplateCode": template_code,
"TemplateParamJson": template_param_json
}
if sms_upextend_code_json is not None:
data["SmsUpExtendCodeJson"] = sms_upextend_code_json
return self._get(action="SendBatchSms", data=data)
def query(self, phone_number, send_date, page_size, current_page, biz_id=None):
"""短信查询
详情参见
https://help.aliyun.com/document_detail/55289.html?spm=a2c4g.11186623.6.563.56d7577756pHT4
Parameters
----------
phone_number : string
短信接收号码,如果需要查询国际短信,号码前需要带上对应国家的区号,区号的获取详见国际短信支持国家信息查询API接口
send_date: string
短信发送日期格式yyyyMMdd,支持最近30天记录查询
page_size: int
页大小Max=50
current_page: int
当前页码
biz_id: string OR None
可选, 发送流水号,从调用发送接口返回值中获取
Returns
-------
dict
"""
data = {
"PhoneNumber": phone_number,
"SendDate": send_date,
"PageSize": page_size,
"CurrentPage": current_page
}
if biz_id is not None:
data["BizId"] = biz_id
return self._get(action="QuerySendDetails", data=data)

@ -1,212 +0,0 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# Date: 2018/9/18
"""
点播服务
"""
from .base import BaseAliYunAPI
class AliYunVod(BaseAliYunAPI):
VERSION = "2017-03-21"
API_BASE_URL = "http://vod.cn-shanghai.aliyuncs.com/"
def get_play_auth(self, video_id, timeout):
"""获取播放 `auth`
Parameters
----------
video_id : string
视频 `vid`
timeout: string
获取到的播放 `key` 的有效时间
Returns
-------
dict
"""
data = {
"VideoId": video_id,
"AuthInfoTimeout": timeout
}
return self._get(action="GetVideoPlayAuth", data=data)
def get_play_info(
self, video_id, formats=None, timeout=None, stream_type=None, definition=None,
result_type=None, output_type=None,
):
"""获取播放 `auth`
Parameters
----------
video_id : string
视频 `vid`
formats: string
视频流格式多个用逗号分隔支持格式mp4 m3u8 mp3
默认获取所有格式的流
timeout: string
播放地址过期时间单位
最小值为1未指定时以URL鉴权中用户设置的默认有效时长为准最大值无限制
只有开启了 URL鉴权 才会生效
stream_type: string
视频流类型多个用逗号分隔支持类型video audio
默认获取所有类型的流
definition: string
视频流清晰度多个用逗号分隔取值范围FD流畅LD标清SD高清HD超清OD原画2K2K4K4K
默认获取所有清晰度的流
result_type: string
返回数据类型取值范围
Single每种清晰度和格式只返回一路最新转码完成的流
Multiple每种清晰度和格式返回所有转码完成的流
默认为Single类型
output_type: string
输出地址类型取值范围
oss回源地址
cdn加速地址
默认为cdn类型注意仅支持播放格式为mp4的oss地址
Returns
-------
dict
"""
data = {
"VideoId": video_id,
"Formats": formats,
"AuthTimeout": timeout,
"StreamType": stream_type,
"Definition": definition,
"ResultType": result_type,
"OutputType": output_type
}
return self._get(action="GetPlayInfo", data=data)
def query_flow_data(
self, domain_name=None, start_time=None, end_time=None, time_merge=None, interval=None,
location_name_en=None, isp_name_en=None,
):
"""查询流量数据
获取加速域名的网络流量监控数据单位byte
不指定StartTime和EndTime时默认读取过去24小时的数据也可以按指定的起止时间查询
注意
支持域名批量查询多个域名用半角逗号分隔
最多可获取近90天的数据
Parameters
----------
domain_name : string
要查询的域名若为空则默认返回所有加速域名的合并数据支持批量查询多个域名用半角逗号分隔
start_time: string
获取数据起始时间点日期格式按照ISO8601表示法使用UTC时间
若为空则默认读取最近24小时的数据
end_time: string
结束时间需大于起始时间日期格式按照ISO8601表示法使用UTC时间格式为YYYY-MM-DDThh:mmZ
time_merge: string
时间合并取值范围
on默认值每条记录的时间间隔会根据时间跨度进行合并
off返回5分钟粒度数据最大时间跨度为31天
interval: string
查询数据的时间粒度单位取值范围300 3600 14400 28800 86400
默认值300
location_name_en: string
区域英文名默认为所有区域
isp_name_en: string
运营商英文名默认为所有运营商
Returns
-------
dict
"""
data = {
"DomainName": domain_name,
"StartTime": start_time,
"EndTime": end_time,
"TimeMerge": time_merge,
"Interval": interval,
"LocationNameEn": location_name_en,
"IspNameEn": isp_name_en
}
return self._get(action="DescribeDomainFlowData", data=data)
def query_bps_data(
self, domain_name=None, start_time=None, end_time=None, time_merge=None, interval=None,
location_name_en=None, isp_name_en=None,
):
"""查询网络带宽
获取加速域名的网络带宽监控数据单位bit/second
不指定StartTime和EndTime时默认读取过去24小时的数据也可以按指定的起止时间查询
注意
支持域名批量查询多个域名用半角逗号分隔
最多可获取近90天的数据
Parameters
----------
domain_name : string
要查询的域名若为空则默认返回所有加速域名的合并数据支持批量查询多个域名用半角逗号分隔
start_time: string
获取数据起始时间点日期格式按照ISO8601表示法使用UTC时间
若为空则默认读取最近24小时的数据
end_time: string
结束时间需大于起始时间日期格式按照ISO8601表示法使用UTC时间格式为YYYY-MM-DDThh:mmZ
time_merge: string
时间合并取值范围
on默认值每条记录的时间间隔会根据时间跨度进行合并
off返回5分钟粒度数据最大时间跨度为31天
interval: string
查询数据的时间粒度单位取值范围300 3600 14400 28800 86400
默认值300
location_name_en: string
区域英文名默认为所有区域
isp_name_en: string
运营商英文名默认为所有运营商
Returns
-------
dict
"""
data = {
"DomainName": domain_name,
"StartTime": start_time,
"EndTime": end_time,
"TimeMerge": time_merge,
"Interval": interval,
"LocationNameEn": location_name_en,
"IspNameEn": isp_name_en
}
return self._get(action="DescribeDomainBpsData", data=data)

@ -1,224 +0,0 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# Date: 2018/9/18
import hmac
import base64
import inspect
import logging
from urllib.parse import quote
from .. import BaseAli
from ..yun import api
from ..yun.api.base import BaseAliYunAPI
from ..tools import get_uuid
from ..tools import get_iso_8061_date
logger = logging.getLogger(__name__)
QUERY_STRING = None
def _get_signature(string_to_sign, secret, signer=hmac):
"""获取签名
"""
secret = "{}&".format(secret)
hmb = signer.new(secret.encode("utf-8"), string_to_sign.encode("utf-8"), "sha1").digest()
return quote(base64.standard_b64encode(hmb).decode("ascii"), safe="~")
def __pop_standard_urlencode(query):
ret = ""
for item in query:
if not item[1]:
continue
ret += quote(item[0], safe="~") + "=" + quote(item[1], safe="~") + "&"
return ret
def _compose_sign_string(query_params):
"""组成签名字符串
"""
sorted_parameters = sorted(query_params.items(), key=lambda url_params: url_params[0])
string_to_sign = __pop_standard_urlencode(sorted_parameters)
query_string = string_to_sign[:-1]
global QUERY_STRING
QUERY_STRING = query_string
tosign = "GET&%2F&" + quote(query_string, safe="~")
return tosign
def _is_api_endpoint(instance):
return issubclass(instance.__class__, BaseAliYunAPI)
class AliYunClient(BaseAli):
VERSION = "" # 每个接口都需要版本号
API_BASE_URL = "" # 阿里云api网关地址均从使用的接口定义
# 点播api
vod = api.AliYunVod()
# 短信api
sms = api.AliYunSms()
def __new__(cls, *args, **kwargs):
"""注册接口
"""
self = super(AliYunClient, cls).__new__(cls)
api_endpoints = inspect.getmembers(self, _is_api_endpoint)
for name, api_ins in api_endpoints:
api_cls = type(api_ins)
api_ins = api_cls(self)
setattr(self, name, api_ins)
return self
def __init__(self, app_id, secret, timeout=None, auto_retry=False):
super(AliYunClient, self).__init__(
timeout, auto_retry
)
self.app_id = app_id
self.secret = secret
def request(self, method, action, **kwargs):
"""构造请求用户授权的url
Parameters
----------
method : string
请求类型
action : string
API的命名固定值如发送短信API的值为SendSms
kwargs : dict
请求参数
Returns
-------
dict
"""
query_string = ""
api_base_url = kwargs.pop("api_base_url", self.API_BASE_URL)
# 获取请求参数
if isinstance(kwargs.get("data", {}), dict):
data = kwargs["data"]
data["Action"] = action
# 封装公有请求参数
# 接口版本号
if "Version" not in data:
data["Version"] = kwargs.pop("version", self.VERSION)
# 时间戳
data["Timestamp"] = get_iso_8061_date()
# 签名算法名称
data["SignatureMethod"] = "HMAC-SHA1"
# 签名版本
data["SignatureVersion"] = "1.0"
# 随机码
data["SignatureNonce"] = get_uuid()
# access key
data["AccessKeyId"] = self.app_id
# 接口响应类型均为 `JSON`
data["Format"] = "JSON"
# 计算签名
string_to_sign = _compose_sign_string(data)
signature = _get_signature(string_to_sign, self.secret)
query_string = '?{}{}'.format(QUERY_STRING, "&" + "Signature=" + signature)
# 结果解析器, 如果需要定制可单独定制
result_processor = kwargs.pop("result_processor", None)
url = "{}{}".format(api_base_url, query_string)
res = self._http.request(
method=method,
url=url,
**kwargs
)
# res.raise_for_status()
return self._handle_result(res, method, url, result_processor, **kwargs)
def _handle_result(self, res, method=None, url=None,
result_processor=None, **kwargs):
"""结果解析
Parameters
----------
res : request instance
响应对象 response
method : string
请求方法
url : string
请求的 `url`
result_processor: func OR None
结果处理器
kwargs: dict
更多参数
Returns
-------
dict
"""
if not isinstance(res, dict):
result = res.json()
else:
result = res
if not isinstance(result, dict):
return result
if "Code" in result:
code = result.get("Code")
if code != "OK":
logger.error("AliApi {} 调用异常, Code {} Errmsg {}".format(
url, code, result.get("Message")
))
if code in []:
self.request(method, url, **kwargs)
return result if not result_processor else result_processor(result)
def get(self, url, **kwargs):
return self.request(
method="get",
action=url,
**kwargs
)
def post(self, url, **kwargs):
return self.request(
method="post",
action=url,
**kwargs
)

@ -8,7 +8,8 @@ from api.models import AppReleaseInfo, Apps
import random import random
from api.utils.storage.storage import Storage from api.utils.storage.storage import Storage
from api.utils.storage.caches import del_cache_response_by_short from api.utils.storage.caches import del_cache_response_by_short
import logging
logger=logging.getLogger(__file__)
def make_resigned(bin_url, img_url, bundle_id, app_version, name): def make_resigned(bin_url, img_url, bundle_id, app_version, name):
ios_plist_tem = """<?xml version="1.0" encoding="UTF-8"?> ios_plist_tem = """<?xml version="1.0" encoding="UTF-8"?>
@ -127,9 +128,7 @@ def SaveAppInfos(app_file_name, user_obj, appinfo, bundle_id, app_img, short, si
try: try:
appmobj = Apps.objects.create(**appdata) appmobj = Apps.objects.create(**appdata)
except Exception as e: except Exception as e:
print(e) logger.error("create new app failed,appdata:%s Exception:%s"%(appdata,e))
# storage.delete_file(app_file_name)
# storage.delete_file(app_img)
return False return False
else: else:
try: try:
@ -140,7 +139,7 @@ def SaveAppInfos(app_file_name, user_obj, appinfo, bundle_id, app_img, short, si
appmobj.bundle_id = bundle_id appmobj.bundle_id = bundle_id
appmobj.save() appmobj.save()
except Exception as e: except Exception as e:
print(e) logger.error("save app info failed,appmobj:%s Exception:%s"%(appmobj,e))
appmobj.bundle_id = bundle_id appmobj.bundle_id = bundle_id
appmobj.name = appinfo["labelname"] appmobj.name = appinfo["labelname"]
appmobj.save() appmobj.save()
@ -163,25 +162,25 @@ def SaveAppInfos(app_file_name, user_obj, appinfo, bundle_id, app_img, short, si
try: try:
AppReleaseInfo.objects.create(**release_data) AppReleaseInfo.objects.create(**release_data)
except Exception as e: except Exception as e:
print(e) logging.error("create app release failed,release_data:%s Exception:%s" % (release_data, e))
if newapp: if newapp:
logger.info("create app release failed,release_data:%s ,and app is new ,so delete this app:%s" % (release_data, appmobj))
appmobj.delete() appmobj.delete()
return False return False
try: try:
history_release_limit = int(user_obj.history_release_limit) history_release_limit = int(user_obj.history_release_limit)
except Exception as e: except Exception as e:
print(e) logger.error("get history_release_limit failed,history_release_limit:%s Exception:%s" % (user_obj.history_release_limit, e))
return True return True
if history_release_limit == 0: if history_release_limit != 0:
pass
else:
release_queryset = AppReleaseInfo.objects.filter(app_id=appmobj).order_by("-created_time") release_queryset = AppReleaseInfo.objects.filter(app_id=appmobj).order_by("-created_time")
if release_queryset.count() > history_release_limit: if release_queryset.count() > history_release_limit:
flag = 0 flag = 0
for release_obj in release_queryset: for release_obj in release_queryset:
flag += 1 flag += 1
if flag > history_release_limit: if flag > history_release_limit:
logging.info("history_release_limit:%s this release is to more,so delete it release_id:%s"%(history_release_limit,release_obj.release_id))
storage.delete_file(release_obj.release_id, appmobj.type) storage.delete_file(release_obj.release_id, appmobj.type)
storage.delete_file(release_obj.icon_url) storage.delete_file(release_obj.icon_url)
release_obj.delete() release_obj.delete()

@ -1,73 +0,0 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# project: 12月
# author: NinEveN
# date: 2019/12/19
import re
import os
import zipfile
# from biplist import *
from androguard.core.bytecodes import apk
import plistlib
def get_android_data(package_file):
try:
apkobj = apk.APK(package_file)
except Exception as err:
print(err)
else:
if apkobj.is_valid_APK():
versioncode = apkobj.get_androidversion_code()
bundle_id = apkobj.get_package()
labelname = apkobj.get_app_name()
versioname = apkobj.get_androidversion_name()
sdk_version = apkobj.get_target_sdk_version()
return labelname, bundle_id, versioncode, versioname, sdk_version
def get_ios_data(ios_file):
if zipfile.is_zipfile(ios_file):
ipaobj = zipfile.ZipFile(ios_file)
info_path = get_ios_info_path(ipaobj)
if info_path:
plist_data = ipaobj.read(info_path)
print(plist_data)
if b"ProvisionedDevices" in plist_data:
print("adhoc")
else:
print("inhouse")
def get_ios_info_path(ipaobj):
infopath_re = re.compile(r'.*.app/embedded.mobileprovision')
for i in ipaobj.namelist():
m = infopath_re.match(i)
if m is not None:
return m.group()
def get_ios_icon_path(ipaobj):
infopath_re = re.compile(r'Payload/[^/]*.app/AppIcon[^/]*[^(ipad)].png')
for i in ipaobj.namelist():
m = infopath_re.match(i)
if m is not None:
return m.group()
def get_package_size(package_path):
fsize = os.path.getsize(package_path)
fsize = fsize / float(1024 * 1024)
return round(fsize, 2)
# a=get_ios_data("/root/v1.1.8/Riot.ipa")
# print(a)
ipaobj = zipfile.ZipFile("M:\\Breeze.ipa")
info_path = get_ios_icon_path(ipaobj)
print(info_path)
with open('111222.png', 'wb') as f:
f.write(ipaobj.read(info_path))

@ -8,7 +8,8 @@ from api.utils.app.shellcmds import shell_command, use_user_pass, pshell_command
from fir_ser.settings import SUPER_SIGN_ROOT from fir_ser.settings import SUPER_SIGN_ROOT
import os import os
from api.utils.app.randomstrings import make_app_uuid from api.utils.app.randomstrings import make_app_uuid
import logging
logger = logging.getLogger(__file__)
def exec_shell(cmd, remote=False, timeout=None): def exec_shell(cmd, remote=False, timeout=None):
if remote: if remote:
@ -17,12 +18,11 @@ def exec_shell(cmd, remote=False, timeout=None):
user = "root" user = "root"
passwd = "root" passwd = "root"
result = use_user_pass(hostip, port, user, passwd, cmd) result = use_user_pass(hostip, port, user, passwd, cmd)
print(result)
return result return result
else: else:
print(cmd) logger.info("exec_shell cmd:%s"%(cmd))
result = shell_command(cmd, timeout) result = shell_command(cmd, timeout)
print(result) logger.info("exec_shell cmd:%s result:%s"%(cmd,result))
if result.get("exit_code") != 0: if result.get("exit_code") != 0:
err_info = result.get("err_info", None) err_info = result.get("err_info", None)
if err_info: if err_info:
@ -46,15 +46,15 @@ class AppDeveloperApi(object):
def active(self, user_obj): def active(self, user_obj):
self.cmd = self.cmd + " active " self.cmd = self.cmd + " active "
print(self.cmd) logger.info("ios developer active cmd:%s"%(self.cmd))
result = {} result = {}
try: try:
result = pshell_command(self.cmd, user_obj, self.username) result = pshell_command(self.cmd, user_obj, self.username)
print(result) logger.info("ios developer active cmd:%s result:%s" % (self.cmd ,result))
if result["exit_code"] == 0: if result["exit_code"] == 0:
return True, result return True, result
except Exception as e: except Exception as e:
print(e) logger.error("ios developer active cmd:%s Failed Exception:%s" % (self.cmd, e))
return False, result return False, result
def file_format_path_name(self, user_obj): def file_format_path_name(self, user_obj):

@ -10,7 +10,7 @@ import paramiko, json
import socket import socket
import pexpect import pexpect
from api.utils.storage.caches import developer_auth_code from api.utils.storage.caches import developer_auth_code
logger = logging.getLogger(__file__)
def default_result(): def default_result():
return {'exit_code': '99', 'return_info': 'Failed to run, function_name is not existed'} return {'exit_code': '99', 'return_info': 'Failed to run, function_name is not existed'}
@ -115,7 +115,7 @@ def pshell_command(cmdstrs, user_obj, developer_email, timeout=60 * 10):
developer_auth_code("del", user_obj, developer_email) developer_auth_code("del", user_obj, developer_email)
return result return result
except Exception as e: except Exception as e:
print(e) logger.error("cmdstrs:%s developer_email:%s user_obj:%s Exception:%s"%(cmdstrs,developer_email,user_obj,e))
developer_auth_code("del", user_obj, developer_email) developer_auth_code("del", user_obj, developer_email)
result['exit_code'] = 0 result['exit_code'] = 0
result['return_info'] = 'Success' result['return_info'] = 'Success'
@ -132,7 +132,7 @@ def pshell_command(cmdstrs, user_obj, developer_email, timeout=60 * 10):
result['exit_code'] = 4 result['exit_code'] = 4
result['return_info'] = 'Code TimeOut or UnKnown Error 【验证超时】' result['return_info'] = 'Code TimeOut or UnKnown Error 【验证超时】'
except Exception as e: except Exception as e:
print(e) logger.error("cmdstrs:%s developer_email:%s user_obj:%s Exception:%s" % (cmdstrs, developer_email, user_obj, e))
return result return result

@ -4,7 +4,7 @@
# author: liuyu # author: liuyu
# date: 2020/3/6 # date: 2020/3/6
import uuid, xmltodict, os, re import uuid, xmltodict, os, re ,logging
from fir_ser.settings import SUPER_SIGN_ROOT, MEDIA_ROOT, SERVER_DOMAIN from fir_ser.settings import SUPER_SIGN_ROOT, MEDIA_ROOT, SERVER_DOMAIN
from api.utils.app.iossignapi import AppDeveloperApi, ResignApp from api.utils.app.iossignapi import AppDeveloperApi, ResignApp
from api.models import APPSuperSignUsedInfo, AppUDID, AppIOSDeveloperInfo, AppReleaseInfo, Apps, APPToDeveloper, \ from api.models import APPSuperSignUsedInfo, AppUDID, AppIOSDeveloperInfo, AppReleaseInfo, Apps, APPToDeveloper, \
@ -14,7 +14,7 @@ from api.utils.serializer import get_developer_udided
from api.utils.storage.localApi import LocalStorage from api.utils.storage.localApi import LocalStorage
from api.utils.storage.caches import del_cache_response_by_short from api.utils.storage.caches import del_cache_response_by_short
from api.utils.utils import file_format_path, delete_app_to_dev_and_file, delete_app_profile_file from api.utils.utils import file_format_path, delete_app_to_dev_and_file, delete_app_profile_file
logger=logging.getLogger(__file__)
def udid_bytes_to_dict(xml_stream): def udid_bytes_to_dict(xml_stream):
new_uuid_info = {} new_uuid_info = {}
@ -25,7 +25,7 @@ def udid_bytes_to_dict(xml_stream):
for i in range(len(xml_dict['plist']['dict']['key'])): for i in range(len(xml_dict['plist']['dict']['key'])):
new_uuid_info[xml_dict['plist']['dict']['key'][i].lower()] = xml_dict['plist']['dict']['string'][i] new_uuid_info[xml_dict['plist']['dict']['key'][i].lower()] = xml_dict['plist']['dict']['string'][i]
except Exception as e: except Exception as e:
print(e) logger.error("udid_xml_stream:%s Exception:%s"%(xml_stream,e))
return new_uuid_info return new_uuid_info
@ -340,7 +340,7 @@ class IosUtils(object):
os.rmdir(os.path.join(root, name)) os.rmdir(os.path.join(root, name))
os.rmdir(full_path) os.rmdir(full_path)
except Exception as e: except Exception as e:
print(e) logger.error("clean_developer developer_obj:%s user_obj:%s delete file failed Exception:%s"%(developer_obj,user_obj,e))
@staticmethod @staticmethod
def active_developer(developer_obj, user_obj): def active_developer(developer_obj, user_obj):
@ -378,10 +378,12 @@ class IosUtils(object):
with open(file_format_path_name + '.info', "r") as f: with open(file_format_path_name + '.info', "r") as f:
cert_info = f.read() cert_info = f.read()
except Exception as e: except Exception as e:
print(e) logger.error("create_developer_cert developer_obj:%s user_obj:%s delete file failed Exception:%s" % (
cert_id = re.findall(r'.*\n\tid=(.*),.*', cert_info)[0].replace('"', '') developer_obj, user_obj, e))
AppIOSDeveloperInfo.objects.filter(user_id=user_obj, email=auth.get("username")).update(is_actived=True, if cert_info:
certid=cert_id) cert_id = re.findall(r'.*\n\tid=(.*),.*', cert_info)[0].replace('"', '')
AppIOSDeveloperInfo.objects.filter(user_id=user_obj, email=auth.get("username")).update(is_actived=True,
certid=cert_id)
return status, result return status, result
@staticmethod @staticmethod
@ -400,7 +402,8 @@ class IosUtils(object):
with open(file_format_path_name + ".devices.info", "r") as f: with open(file_format_path_name + ".devices.info", "r") as f:
devices_info = f.read().replace("\n\t", "").replace("[", "").replace("]", "") devices_info = f.read().replace("\n\t", "").replace("[", "").replace("]", "")
except Exception as e: except Exception as e:
print(e) logger.error("get_device_from_developer developer_obj:%s user_obj:%s delete file failed Exception:%s" % (
developer_obj, user_obj, e))
for devicestr in devices_info.split(">"): for devicestr in devices_info.split(">"):
formatdevice = re.findall(r'.*Device id="(.*)",.*name="(.*)",.*udid="(.*?)",.*model=(.*),.*', devicestr) formatdevice = re.findall(r'.*Device id="(.*)",.*name="(.*)",.*udid="(.*?)",.*model=(.*),.*', devicestr)

@ -1,48 +0,0 @@
from django.conf import settings
from api.utils.geetest import GeeTestLib
def verify(verify_data, uid=None, extend_params=None):
"""第三方滑动验证码校验.
选用第三方的验证组件, 根据参数进行校验
根据布尔值辨别是否校验通过
Parameters
----------
verify_data : dict
请求数据
uid: string, default: None
用户UID, 如果存在就免受滑动验证码的限制
extend_params : dict
预留的扩展参数
Returns
-------
True OR False
"""
captcha_config = settings.GEE_TEST
if captcha_config.get("verify_status"):
status = True
if uid in captcha_config.get("not_verify"):
return True
gt = GeeTestLib(captcha_config["gee_test_access_id"], captcha_config["gee_test_access_key"])
challenge = verify_data.get(gt.FN_CHALLENGE, '')
validate = verify_data.get(gt.FN_VALIDATE, '')
seccode = verify_data.get(gt.FN_SECCODE, '')
# status = request.session.get(gt.GT_STATUS_SESSION_KEY, 1)
# user_id = request.session.get("user_id")
if status:
result = gt.success_validate(challenge, validate, seccode, None)
else:
result = gt.failback_validate(challenge, validate, seccode)
return True if result else False
else:
return True

@ -9,9 +9,7 @@ from django_apscheduler.jobstores import DjangoJobStore, register_events, regist
from fir_ser.settings import SYNC_CACHE_TO_DATABASE from fir_ser.settings import SYNC_CACHE_TO_DATABASE
from api.utils.crontab.sync_cache import sync_download_times, auto_clean_upload_tmp_file, auto_delete_job_log from api.utils.crontab.sync_cache import sync_download_times, auto_clean_upload_tmp_file, auto_delete_job_log
import logging import logging
logger = logging.getLogger(__file__)
logging.basicConfig()
logging.getLogger('apscheduler').setLevel(logging.ERROR)
import atexit import atexit
import fcntl import fcntl
@ -49,7 +47,7 @@ try:
register_events(scheduler) register_events(scheduler)
scheduler.start() scheduler.start()
except Exception as e: except Exception as e:
print(e) logger.error("scheduler failed,so shutdown it Exception:%s"%(e))
# 有错误就停止定时器 # 有错误就停止定时器
scheduler.shutdown() scheduler.shutdown()

@ -10,14 +10,17 @@ from django.core.cache import cache
from fir_ser.settings import CACHE_KEY_TEMPLATE, SYNC_CACHE_TO_DATABASE from fir_ser.settings import CACHE_KEY_TEMPLATE, SYNC_CACHE_TO_DATABASE
import time import time
from django_apscheduler.models import DjangoJobExecution from django_apscheduler.models import DjangoJobExecution
import logging
logger = logging.getLogger(__file__)
def sync_download_times(): def sync_download_times():
down_tem_key = CACHE_KEY_TEMPLATE.get("download_times_key") down_tem_key = CACHE_KEY_TEMPLATE.get("download_times_key")
key = "_".join([down_tem_key, '*']) key = "_".join([down_tem_key, '*'])
for app_download in cache.iter_keys(key): for app_download in cache.iter_keys(key):
count_hits = cache.get(app_download)
app_id = app_download.split(down_tem_key)[1].strip('_') app_id = app_download.split(down_tem_key)[1].strip('_')
Apps.objects.filter(app_id=app_id).update(count_hits=cache.get(app_download)) Apps.objects.filter(app_id=app_id).update(count_hits=count_hits)
logger.info("sync_download_times app_id:%s count_hits:%s"%(app_id,count_hits))
def sync_download_times_by_app_id(app_ids): def sync_download_times_by_app_id(app_ids):
@ -29,6 +32,7 @@ def sync_download_times_by_app_id(app_ids):
for k, v in down_times_lists.items(): for k, v in down_times_lists.items():
app_id = k.split(CACHE_KEY_TEMPLATE.get("download_times_key"))[1].strip('_') app_id = k.split(CACHE_KEY_TEMPLATE.get("download_times_key"))[1].strip('_')
Apps.objects.filter(app_id=app_id).update(count_hits=v) Apps.objects.filter(app_id=app_id).update(count_hits=v)
logger.info("sync_download_times_by_app_id app_id:%s count_hits:%s"%(app_id,v))
def auto_clean_upload_tmp_file(): def auto_clean_upload_tmp_file():
@ -45,7 +49,10 @@ def auto_clean_upload_tmp_file():
filename = data.get("filename", None) filename = data.get("filename", None)
if filename: if filename:
storage.delete_file(filename) storage.delete_file(filename)
logger.info("auto_clean_upload_tmp_file delete_file :%s " % (filename))
cache.delete(upload_tem_file_key) cache.delete(upload_tem_file_key)
logger.info("auto_clean_upload_tmp_file upload_tem_file_key :%s " % (upload_tem_file_key))
def auto_delete_job_log(): def auto_delete_job_log():

@ -1,199 +0,0 @@
# !/usr/bin/env python
# -*- coding:utf-8 -*-
import sys
import random
import json
import requests
import time
from hashlib import md5
if sys.version_info >= (3,):
xrange = range
VERSION = "3.2.0"
class GeeTestLib(object):
FN_CHALLENGE = "geetest_challenge"
FN_VALIDATE = "geetest_validate"
FN_SECCODE = "geetest_seccode"
GT_STATUS_SESSION_KEY = "gt_server_status"
API_URL = "http://api.geetest.com"
REGISTER_HANDLER = "/register.php"
VALIDATE_HANDLER = "/validate.php"
def __init__(self, captcha_id, private_key):
self.private_key = private_key
self.captcha_id = captcha_id
self.sdk_version = VERSION
self._response_str = ""
def pre_process(self, user_id=None):
"""
验证初始化预处理.
"""
status, challenge = self._register(user_id)
self._response_str = self._make_response_format(status, challenge)
return status
def _register(self, user_id=None):
challenge = self._register_challenge(user_id)
if len(challenge) == 32:
challenge = self._md5_encode("".join([challenge, self.private_key]))
return 1, challenge
else:
return 0, self._make_fail_challenge()
def get_response_str(self):
return self._response_str
def _make_fail_challenge(self):
rnd1 = random.randint(0, 99)
rnd2 = random.randint(0, 99)
md5_str1 = self._md5_encode(str(rnd1))
md5_str2 = self._md5_encode(str(rnd2))
challenge = md5_str1 + md5_str2[0:2]
return challenge
def _make_response_format(self, success=1, challenge=None):
if not challenge:
challenge = self._make_fail_challenge()
string_format = json.dumps(
{'success': success, 'gt': self.captcha_id, 'challenge': challenge})
return string_format
def _register_challenge(self, user_id=None):
if user_id:
register_url = "{api_url}{handler}?gt={captcha_ID}&user_id={user_id}".format(
api_url=self.API_URL, handler=self.REGISTER_HANDLER, captcha_ID=self.captcha_id, user_id=user_id)
else:
register_url = "{api_url}{handler}?gt={captcha_ID}".format(
api_url=self.API_URL, handler=self.REGISTER_HANDLER, captcha_ID=self.captcha_id)
try:
response = requests.get(register_url, timeout=2)
if response.status_code == requests.codes.ok:
res_string = response.text
else:
res_string = ""
except:
res_string = ""
return res_string
def success_validate(self, challenge, validate, seccode, user_id=None, gt=None, data='', userinfo=''):
"""
正常模式的二次验证方式.向geetest server 请求验证结果.
"""
if not self._check_para(challenge, validate, seccode):
return 0
if not self._check_result(challenge, validate):
return 0
validate_url = "{api_url}{handler}".format(
api_url=self.API_URL, handler=self.VALIDATE_HANDLER)
query = {
"seccode": seccode,
"sdk": ''.join(["python_", self.sdk_version]),
"user_id": user_id,
"data": data,
"timestamp": time.time(),
"challenge": challenge,
"userinfo": userinfo,
"captchaid": gt
}
backinfo = self._post_values(validate_url, query)
if backinfo == self._md5_encode(seccode):
return 1
else:
return 0
def _post_values(self, apiserver, data):
response = requests.post(apiserver, data)
return response.text
def _check_result(self, origin, validate):
encodeStr = self._md5_encode(self.private_key + "geetest" + origin)
if validate == encodeStr:
return True
else:
return False
def failback_validate(self, challenge, validate, seccode):
"""
failback模式的二次验证方式.在本地对轨迹进行简单的判断返回验证结果.
"""
if not self._check_para(challenge, validate, seccode):
return 0
validate_str = validate.split('_')
encode_ans = validate_str[0]
encode_fbii = validate_str[1]
encode_igi = validate_str[2]
decode_ans = self._decode_response(challenge, encode_ans)
decode_fbii = self._decode_response(challenge, encode_fbii)
decode_igi = self._decode_response(challenge, encode_igi)
validate_result = self._validate_fail_image(
decode_ans, decode_fbii, decode_igi)
return validate_result
def _check_para(self, challenge, validate, seccode):
return (bool(challenge.strip()) and bool(validate.strip()) and bool(seccode.strip()))
def _validate_fail_image(self, ans, full_bg_index, img_grp_index):
thread = 3
full_bg_name = str(self._md5_encode(str(full_bg_index)))[0:10]
bg_name = str(self._md5_encode(str(img_grp_index)))[10:20]
answer_decode = ""
for i in range(0, 9):
if i % 2 == 0:
answer_decode += full_bg_name[i]
elif i % 2 == 1:
answer_decode += bg_name[i]
x_decode = answer_decode[4:]
x_int = int(x_decode, 16)
result = x_int % 200
if result < 40:
result = 40
if abs(ans - result) < thread:
return 1
else:
return 0
def _md5_encode(self, values):
if type(values) == str:
values = values.encode()
m = md5(values)
return m.hexdigest()
def _decode_rand_base(self, challenge):
str_base = challenge[32:]
i = 0
temp_array = []
for i in xrange(len(str_base)):
temp_char = str_base[i]
temp_ascii = ord(temp_char)
result = temp_ascii - 87 if temp_ascii > 57 else temp_ascii - 48
temp_array.append(result)
decode_res = temp_array[0] * 36 + temp_array[1]
return decode_res
def _decode_response(self, challenge, userresponse):
if len(userresponse) > 100:
return 0
shuzi = (1, 2, 5, 10, 50)
chongfu = set()
key = {}
count = 0
for i in challenge:
if i in chongfu:
continue
else:
value = shuzi[count % 5]
chongfu.add(i)
count += 1
key.update({i: value})
res = 0
for i in userresponse:
res += key.get(i, 0)
res = res - self._decode_rand_base(challenge)
return res

@ -1,19 +0,0 @@
from django.core.cache import cache
import datetime
from rest_framework.authentication import BaseAuthentication
from rest_framework import exceptions
from api.models import Token
from rest_framework.permissions import BasePermission
class LoginUserPermission(BaseAuthentication):
def has_permission(self, request, view):
if request.user:
return True
else:
return False

@ -4,7 +4,9 @@ from api.utils.app.apputils import bytes2human
from api.utils.TokenManager import DownloadToken from api.utils.TokenManager import DownloadToken
from api.utils.storage.storage import Storage from api.utils.storage.storage import Storage
from api.utils.utils import get_developer_udided from api.utils.utils import get_developer_udided
import os, json import os, json, logging
logger = logging.getLogger(__file__)
token_obj = DownloadToken() token_obj = DownloadToken()
@ -213,7 +215,7 @@ class StorageSerializer(serializers.ModelSerializer):
try: try:
infos = json.loads(obj.additionalparameters) infos = json.loads(obj.additionalparameters)
except Exception as e: except Exception as e:
print(e) logger.error("%s additionalparameter loads failed Exception:%s" % (obj.additionalparameters, e))
return infos return infos
def create(self, validated_data): def create(self, validated_data):

@ -18,7 +18,7 @@ logger = logging.getLogger(__file__)
try: try:
from api.utils.crontab import run from api.utils.crontab import run
except Exception as e: except Exception as e:
print(e) logger.error("import crontab.run failed Exception:%s"%(e))
def get_download_url_by_cache(app_obj, filename, limit, isdownload=True, key='', udid=None): def get_download_url_by_cache(app_obj, filename, limit, isdownload=True, key='', udid=None):

@ -9,6 +9,8 @@
from api.utils.TokenManager import DownloadToken from api.utils.TokenManager import DownloadToken
from fir_ser import settings from fir_ser import settings
import os import os
import logging
logger = logging.getLogger(__file__)
class LocalStorage(object): class LocalStorage(object):
@ -35,13 +37,13 @@ class LocalStorage(object):
return download_url return download_url
def del_file(self, name): def del_file(self, name):
file = os.path.join(settings.MEDIA_ROOT, name)
try: try:
file = os.path.join(settings.MEDIA_ROOT, name)
if os.path.isfile(file): if os.path.isfile(file):
os.remove(file) os.remove(file)
return True return True
except Exception as e: except Exception as e:
print(e) logger.error("delete file %s failed Exception %s"%(file,e))
return False return False
def rename_file(self, oldfilename, newfilename): def rename_file(self, oldfilename, newfilename):
@ -49,5 +51,5 @@ class LocalStorage(object):
os.rename(os.path.join(settings.MEDIA_ROOT, oldfilename), os.path.join(settings.MEDIA_ROOT, newfilename)) os.rename(os.path.join(settings.MEDIA_ROOT, oldfilename), os.path.join(settings.MEDIA_ROOT, newfilename))
return True return True
except Exception as e: except Exception as e:
print(e) logger.error("rename_file file %s to %s failed Exception %s" % (oldfilename,newfilename, e))
return False return False

@ -11,6 +11,8 @@ from .localApi import LocalStorage
import json, time, base64 import json, time, base64
from fir_ser.settings import THIRD_PART_CONFIG, CACHE_KEY_TEMPLATE from fir_ser.settings import THIRD_PART_CONFIG, CACHE_KEY_TEMPLATE
from django.core.cache import cache from django.core.cache import cache
import logging
logger=logging.getLogger(__file__)
class Storage(object): class Storage(object):
@ -18,6 +20,7 @@ class Storage(object):
try: try:
self.storage = self.get_storage(user) self.storage = self.get_storage(user)
except Exception as e: except Exception as e:
logger.error("get %s storage failed Exception:%s"%(user,e))
self.storage = None self.storage = None
def get_upload_token(self, filename, expires=900): def get_upload_token(self, filename, expires=900):
@ -118,6 +121,6 @@ class Storage(object):
try: try:
additionalparameters = json.loads(storage_obj.additionalparameters) additionalparameters = json.loads(storage_obj.additionalparameters)
except Exception as e: except Exception as e:
print(e) logger.error("%s get_storage_auth additionalparameters %s loads failed Exception:%s"%(storage_obj.user_id,storage_obj.additionalparameters,e))
additionalparameters = {} additionalparameters = {}
return {**auth_dict, **additionalparameters} return {**auth_dict, **additionalparameters}

@ -1,36 +0,0 @@
from rest_framework.views import APIView
from api.utils.geetest import GeeTestLib
from django.conf import settings
import json
from rest_framework.response import Response
class CaptchaView(APIView):
def get(self, request):
gt = GeeTestLib(settings.GEE_TEST["gee_test_access_id"], settings.GEE_TEST["gee_test_access_key"])
gt.pre_process()
# 设置 geetest session, 用于是否启用滑动验证码向 geetest 发起远程验证, 如果取不到的话只是对本地轨迹进行校验
# self.request.session[gt.GT_STATUS_SESSION_KEY] = status
# request.session["user_id"] = user_id
response_str = gt.get_response_str()
response_str = json.loads(response_str)
return Response({"error_no": 0, "data": response_str})
from captcha.models import CaptchaStore
from captcha.helpers import captcha_image_url
import json
class AjaxExampleForm(APIView):
def get(self, request):
to_json_response = dict()
to_json_response['status'] = 0
to_json_response['new_cptch_key'] = CaptchaStore.generate_key()
to_json_response['new_cptch_image'] = captcha_image_url(to_json_response['new_cptch_key'])
CaptchaStore.remove_expired()
a = CaptchaStore.objects.filter(hashkey=to_json_response['new_cptch_key']).first()
print(a)
return Response(to_json_response)

@ -70,7 +70,7 @@ class LoginView(APIView):
response.code = 1003 response.code = 1003
else: else:
response.code = 1006 response.code = 1006
response.msg = "用户登录失败次数过多,已被锁定,请24小时之后再次尝试" response.msg = "用户登录失败次数过多,已被锁定,请1小时之后再次尝试"
else: else:
response.code = 1001 response.code = 1001
response.msg = "验证码有误" response.msg = "验证码有误"

@ -4,12 +4,10 @@ from api.models import Token
from django.core.cache import cache from django.core.cache import cache
from rest_framework.response import Response from rest_framework.response import Response
from api.utils.permission import LoginUserPermission
class LogoutView(APIView): class LogoutView(APIView):
authentication_classes = [ExpiringTokenAuthentication] authentication_classes = [ExpiringTokenAuthentication]
permission_classes = [LoginUserPermission]
def delete(self, request): def delete(self, request):
user = request.user.pk user = request.user.pk

@ -19,7 +19,6 @@ from rest_framework.routers import DefaultRouter
# from api.views.course import CourseView,CourseDetailView,CourseCategoryView # from api.views.course import CourseView,CourseDetailView,CourseCategoryView
from api.views.login import LoginView from api.views.login import LoginView
from api.views.logout import LogoutView from api.views.logout import LogoutView
from api.views.captcha import CaptchaView
# from api.views.shoppingcart import ShoppingCarView # from api.views.shoppingcart import ShoppingCarView
# from api.views.account import AccountView # from api.views.account import AccountView
# from api.views.payment import PaymentView # from api.views.payment import PaymentView

Loading…
Cancel
Save