コード例 #1
0
    def test_encrypt_message(self):
        origin_crypto = _crypto.PrpCrypto
        _crypto.PrpCrypto = PrpCryptoMock

        nonce = 'nEXhMP4r'
        timestamp = '1445827045067'
        msg = """{"EventType":"check_create_suite_url","Random":"LPIdSnlF","TestSuiteKey":"suite4xxxxxxxxxxxxxxx"}"""

        expected = {
            'msg_signature':
            'bcf6dcefa4ce2dbaf7b0666c7264d46fd9aad4bd',
            'encrypt':
            '5DJFWzjRNOQk+5GSZxW+VrFMDWCIidPjEjg3//gm5x556BedVi62rDj1F9uXU97a4jw1R4FACUv9RCpoDobNqxhxRB2Yt'
            'W901k4KHbP1/wpFJ3xdLG0n0A8U1VhENg80zKJd+YROR0YMGum4WYuoXJ6J98vt0ihYeIFoapNddLML5MyNAGM9saSpko'
            'uDMSvD+iU14i7V8ix1ia1Tb9ogog==',
            'timeStamp':
            '1445827045067',
            'nonce':
            'nEXhMP4r'
        }
        crypto = DingTalkCrypto(self.token, self.encoding_aes_key,
                                self.suite_key)
        encrypted = crypto.encrypt_message(msg, nonce, timestamp)

        _crypto.PrpCrypto = origin_crypto

        self.assertEqual(expected.keys(), encrypted.keys())
        for key in expected.keys():
            self.assertEqual(expected[key], encrypted[key])
コード例 #2
0
 def __init__(self,
              suite_key,
              suite_secret,
              token=None,
              aes_key=None,
              storage=None,
              timeout=None,
              auto_retry=True):
     super(ISVClient, self).__init__(storage, timeout, auto_retry)
     self.suite_key = suite_key
     self.suite_secret = suite_secret
     self.cache = ISVCache(self.storage, 'isv:' + self.suite_key)
     self.crypto = DingTalkCrypto(token, aes_key, suite_key)
コード例 #3
0
    def test_decrypt_encrypt_str(self):
        from dingtalk.core.utils import to_text
        signature = '5a65ceeef9aab2d149439f82dc191dd6c5cbe2c0'
        timestamp = '1445827045067'
        nonce = 'nEXhMP4r'
        encrypt_str = '1a3NBxmCFwkCJvfoQ7WhJHB+iX3qHPsc9JbaDznE1i03peOk1LaOQoRz3+nlyGNhwmwJ3vDMG+OzrHMeiZI7gTRWVdUBm' \
                      'fxjZ8Ej23JVYa9VrYeJ5as7XM/ZpulX8NEQis44w53h1qAgnC3PRzM7Zc/D6Ibr0rgUathB6zRHP8PYrfgnNOS9PhSBdH' \
                      'legK+AGGanfwjXuQ9+0pZcy0w9lQ=='

        crypto = DingTalkCrypto(self.token, self.encoding_aes_key,
                                self.suite_key)
        msg = crypto.decrypt_encrypt_str(signature, timestamp, nonce,
                                         encrypt_str)
        msg_dict = json.loads(to_text(msg))
        self.assertEqual('check_create_suite_url', msg_dict['EventType'])
        self.assertEqual('LPIdSnlF', msg_dict['Random'])
        self.assertEqual(self.suite_key, msg_dict['TestSuiteKey'])
コード例 #4
0
 def __init__(self,
              corp_id,
              corp_secret,
              token=None,
              aes_key=None,
              storage=None,
              timeout=None,
              auto_retry=True):
     super(SecretClient, self).__init__(corp_id, 'secret:' + corp_id,
                                        storage, timeout, auto_retry)
     self.corp_secret = corp_secret
     self.crypto = DingTalkCrypto(token, aes_key, corp_id)
コード例 #5
0
    def test_decrypt_encrypt_str_should_fail(self):
        from dingtalk.core.exceptions import InvalidSignatureException
        signature = '5a65ceeef9aab2d149439f82dc191dd6c5cbe2c0'
        timestamp = '1445827045067'
        nonce = 'xxxxx'
        encrypt_str = b'1a3NBxmCFwkCJvfoQ7WhJHB+iX3qHPsc9JbaDznE1i03peOk1LaOQoRz3+nlyGNhwmwJ3vDMG+OzrHMeiZI7gTRWVdUB' \
                      b'mfxjZ8Ej23JVYa9VrYeJ5as7XM/ZpulX8NEQis44w53h1qAgnC3PRzM7Zc/D6Ibr0rgUathB6zRHP8PYrfgnNOS9PhSB' \
                      b'dHlegK+AGGanfwjXuQ9+0pZcy0w9lQ=='

        crypto = DingTalkCrypto(self.token, self.encoding_aes_key,
                                self.suite_key)

        self.assertRaises(InvalidSignatureException,
                          crypto.decrypt_encrypt_str, signature, timestamp,
                          nonce, encrypt_str)
コード例 #6
0
class ISVClient(BaseClient):
    def __init__(self,
                 suite_key,
                 suite_secret,
                 token=None,
                 aes_key=None,
                 storage=None,
                 timeout=None,
                 auto_retry=True):
        super(ISVClient, self).__init__(storage, timeout, auto_retry)
        self.suite_key = suite_key
        self.suite_secret = suite_secret
        self.cache = ISVCache(self.storage, 'isv:' + self.suite_key)
        self.crypto = DingTalkCrypto(token, aes_key, suite_key)

    def _handle_pre_request(self, method, uri, kwargs):
        if 'suite_access_token=' in uri or 'suite_access_token' in kwargs.get(
                'params', {}):
            raise ValueError("suite_access_token: " + uri)
        uri = '%s%ssuite_access_token=%s' % (uri, '&' if '?' in uri else '?',
                                             self.suite_access_token)
        return method, uri, kwargs

    def _handle_request_except(self, e, func, *args, **kwargs):
        if e.errcode in (33001, 40001, 42001, 40014):
            self.cache.suite_access_token.delete()
            if self.auto_retry:
                return func(*args, **kwargs)
        raise e

    def set_suite_ticket(self, suite_ticket):
        self.cache.suite_ticket.set(value=suite_ticket)

    @property
    def suite_access_token(self):
        self.cache.suite_access_token.get()
        token = self.cache.suite_access_token.get()
        if token is None:
            ret = self.get_suite_access_token()
            token = ret['suite_access_token']
            expires_in = ret.get('expires_in', 7200)
            self.cache.suite_access_token.set(value=token, ttl=expires_in)
        return token

    def _handle_permanent_code(self, permanent_code_data):
        permanent_code = permanent_code_data.get('permanent_code', None)
        ch_permanent_code = permanent_code_data.get('ch_permanent_code', None)
        corp_id = permanent_code_data.get('auth_corp_info',
                                          {}).get('corpid', None)
        if corp_id is None:
            return
        if permanent_code is not None:
            self.cache.permanent_code.set(corp_id, permanent_code)
        if ch_permanent_code is not None:
            self.cache.ch_permanent_code.set(corp_id, ch_permanent_code)

    def get_dingtalk_client(self, corp_id):
        return ISVDingTalkClient(corp_id, self)

    def get_channel_client(self, corp_id):
        return ISVChannelClient(corp_id, self)

    def proc_message(self, message):
        if not isinstance(message, dict):
            return
        event_type = message.get('EventType', None)

        if event_type == SuitePushType.SUITE_TICKET.value:
            suite_ticket = message.get('SuiteTicket', None)
            if suite_ticket:
                self.set_suite_ticket(suite_ticket)
            return
        elif event_type == SuitePushType.TMP_AUTH_CODE.value:
            auth_code = message.get('AuthCode')
            permanent_code_data = self.get_permanent_code(auth_code)
            message['__permanent_code_data'] = permanent_code_data
            return
        elif event_type == SuitePushType.SUITE_RELIEVE.value:
            corp_id = message.get('AuthCorpId')
            self.cache.permanent_code.delete(corp_id)
            self.cache.ch_permanent_code.delete(corp_id)
            return
        else:
            return

    def parse_message(self, msg, signature, timestamp, nonce):
        message = self.crypto.decrypt_message(msg, signature, timestamp, nonce)
        try:
            message = json.loads(to_text(message))
            self.proc_message(message)
        except Exception as e:
            logger.error("proc_message error %s %s", message, e)
        return message

    def get_ch_permanent_code_from_cache(self, corp_id):
        return self.cache.ch_permanent_code.get(corp_id)

    def get_permanent_code_from_cache(self, corp_id):
        return self.cache.permanent_code.get(corp_id)

    def get_suite_access_token(self):
        """
        获取应用套件令牌Token
        :return:
        """
        return self._request('post',
                             '/service/get_suite_token',
                             data={
                                 "suite_key": self.suite_key,
                                 "suite_secret": self.suite_secret,
                                 "suite_ticket": self.cache.suite_ticket.get()
                             })

    def get_permanent_code(self, tmp_auth_code):
        """
        获取企业授权的永久授权码
        :param tmp_auth_code: 回调接口(tmp_auth_code)获取的临时授权码
        :return:
        """
        permanent_code_data = self.post('/service/get_permanent_code',
                                        {'tmp_auth_code': tmp_auth_code})
        self._handle_permanent_code(permanent_code_data)
        return permanent_code_data

    def activate_suite(self, corp_id):
        """
        激活套件
        :param corp_id: 授权方corpid
        :return:
        """
        return self.post(
            '/service/activate_suite', {
                'suite_key': self.suite_key,
                'auth_corpid': corp_id,
                'permanent_code': self.cache.permanent_code.get(corp_id)
            })

    def get_access_token_by_corpid(self, corp_id):
        """
        获取企业授权的凭证
        :param corp_id: 授权方corpid
        :return:
        """
        return self.post(
            '/service/get_corp_token', {
                'auth_corpid': corp_id,
                'permanent_code': self.cache.permanent_code.get(corp_id)
            })

    def get_auth_info(self, corp_id):
        """
        获取企业基本信息
        :param corp_id: 授权方corpid
        :return:
        """
        return self.post('/service/get_auth_info', {
            'auth_corpid': corp_id,
            'suite_key': self.suite_key
        })

    def get_agent(self, corp_id, agent_id):
        """
        获取企业的应用信息
        :param corp_id: 授权方corpid
        :param agent_id: 授权方应用id
        :return:
        """
        return self.post(
            '/service/get_agent', {
                'suite_key': self.suite_key,
                'auth_corpid': corp_id,
                'agentid': agent_id,
                'permanent_code': self.get_permanent_code_from_cache(corp_id)
            })

    def get_unactive_corp(self, app_id):
        """
        获取应用未激活的企业列表
        :param app_id: 套件下的微应用ID
        :return:
        """
        return self.post('/service/get_unactive_corp', {'app_id': app_id})

    def reauth_corp(self, app_id, corpid_list):
        """
        重新授权未激活应用的企业
        :param app_id: 套件下的微应用ID
        :param corpid_list: 未激活的corpid列表
        :return:
        """
        return self.post('/service/reauth_corp', {
            'app_id': app_id,
            'corpid_list': corpid_list
        })

    def set_corp_ipwhitelist(self, corp_id, ip_whitelist):
        """
        ISV为授权方的企业单独设置IP白名单
        :param corp_id: 授权方corpid
        :param ip_whitelist: 要为其设置的IP白名单,格式支持IP段,用星号表示,注意:仅支持后两段设置为星号
        :return:
        """
        return self.post('/service/set_corp_ipwhitelist', {
            'auth_corpid': corp_id,
            'ip_whitelist': ip_whitelist
        })

    def get_channel_token_by_corpid(self, corp_id):
        """
        ISV获取企业服务窗接口调用TOKEN
        :param corp_id: 授权方corpid
        :return:
        """
        return self.post(
            '/service/get_channel_corp_token', {
                'auth_corpid': corp_id,
                'ch_permanent_code':
                self.get_ch_permanent_code_from_cache(corp_id)
            })