parent
							
								
									d9b0d3718c
								
							
						
					
					
						commit
						9f21a2f51e
					
				| @ -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格式: {"show_url":"https://或http://打头的商品的展示地址"} | ||||
|                 在支付时,可点击商品名称跳转到该地址 | ||||
| 
 | ||||
|             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格式: {"show_url":"https://或http://打头的商品的展示地址"} | ||||
|                 在支付时,可点击商品名称跳转到该地址 | ||||
| 
 | ||||
|             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个汉字)。当付款方为企业账户,且转账金额达到(大于等于)50000元,remark不能为空。 | ||||
|                 收款方可见,会展示在收款用户的收支详情中。 | ||||
| 
 | ||||
|         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格式: {"show_url":"https://或http://打头的商品的展示地址"} | ||||
|                 在支付时,可点击商品名称跳转到该地址 | ||||
| 
 | ||||
|             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(原画)2K(2K)4K(4K) | ||||
|             默认获取所有清晰度的流。 | ||||
| 
 | ||||
|         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 | ||||
|         ) | ||||
| @ -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)) | ||||
| @ -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 | ||||
| @ -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 | ||||
| @ -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) | ||||
					Loading…
					
					
				
		Reference in new issue