api.py 9.29 KB
import base64
import hashlib
import hmac
import json
import sys
from datetime import datetime, date

import requests
from pyramid.i18n import TranslationStringFactory
from pyramid_rpc.jsonrpc import JsonRpcError

from opensipkd.tools import get_settings, get_random_number

LIMIT = 1000
CODE_OK = 0
MSG_OK = 'Data Submitted'

import logging

log = logging.getLogger(__name__)
_ = TranslationStringFactory('json_error')


class JsonRpcOtherError(JsonRpcError):
    code = -32604
    message = _('Other Error')


# error terkait database
class JsonRpcNotImplementedError(JsonRpcError):
    code = -40000
    message = _("Method Not Implemented")


class JsonRpcDbUrlNotFoundError(JsonRpcError):
    code = -40001
    message = _("DB URL Connection Not Found")


class JsonRpcDbConnectionError(JsonRpcError):
    code = -40002
    message = _("DB Connection Not Found")


class JsonRpcDataNotFoundError(JsonRpcError):
    code = -40003
    message = _("Error Data Not Found")


class JsonRpcDataFoundError(JsonRpcError):
    code = -40004
    message = _("Error Data Already Found")


class JsonRpcInvalidLoginError(JsonRpcError):
    code = -41001
    message = _("Invalid RPC User/Password")


class JsonRpcInvalidNikError(JsonRpcError):
    code = -41002
    message = _('Invalid NIK')


class JsonRpcNikFoundError(JsonRpcError):
    code = -41003
    message = _('NIK already found')


class JsonRpcMobileFoundError(JsonRpcError):
    code = -41004
    message = _('Mobile number already found')


class JsonRpcInvalidMobileError(JsonRpcError):
    code = -41004
    message = _('Invalid Mobile Number')


class JsonRpcInvalidDataError(JsonRpcError):
    code = -41005
    message = _('Data Invalid')


class JsonRpcInvalidData(JsonRpcError):
    code = -41005
    message = _('Invalid Data')


class JsonRpcEmailFound(JsonRpcError):
    code = -41006
    message = _('e-mail already found')


class JsonRpcEmailFoundError(JsonRpcEmailFound):
    """Compatibilty"""


class JsonRpcInvalidEmailError(JsonRpcError):
    code = -41007
    message = _('Invalid e-mail')


class JsonRpcMailError(JsonRpcError):
    code = -41008
    message = 'Gagal autentikasi mail server'


class JsonRpcUserFound(JsonRpcError):
    code = -41009
    message = _('User already found')


class JsonRpcUserFoundError(JsonRpcUserFound):
    """Compatibity """


class JsonRpcRegisterFailError(JsonRpcError):
    code = -41010
    message = _('User Registration Failed ')


class JsonRpcProfileFail(JsonRpcError):
    code = -41011
    message = _('Update Profile Failed')


class JsonRpcProfileFailError(JsonRpcError):
    """Portabitas"""


class JsonRpcGetPasswordError(JsonRpcError):
    code = -41012
    message = 'Gagal Request Password'


class JsonRpcUserNotFoundError(JsonRpcError):
    code = -41013
    message = 'User Tidak Ada'


class JsonRpcInvalidTimeError(JsonRpcError):
    code = -41014
    message = 'Periksa Date Time Server'


class JsonRpcPermissionError(JsonRpcError):
    code = -41015
    message = 'Hak Akses dibatasi'


# error terkait transaksi
class JsonRpcInvalidInvoiceError(JsonRpcError):
    code = -50001
    message = 'Invalid No Bayar'


class JsonRpcBankNotFoundError(JsonRpcError):
    code = -51001
    message = 'Bank Not Found'


class JsonRpcBillNotFoundError(JsonRpcError):
    code = -52001
    message = 'Bill Not Found'


# class JsonRpcDataNotFoundError(JsonRpcError):
#     code = -52001
#     message = 'Data Not Found'


class JsonRpcBillAllreadyPaidError(JsonRpcError):
    code = -52002
    message = 'Bill Allready Paid'


class JsonRpcBillDifferentError(JsonRpcError):
    code = -52003
    message = 'Bill Amount Different'


class JsonRpcNtbNotFoundError(JsonRpcError):
    code = -53001
    message = 'NTB Not Found'


class JsonRpcNtbNotValidError(JsonRpcError):
    code = -53002
    message = 'NTB Not Valid'


# Reversal Message
class JsonRpcPaymentNotFoundError(JsonRpcError):
    code = -54001
    message = 'Payment Not Found'


class JsonRpcPaymentNotOwnerError(JsonRpcError):
    code = -54002
    message = 'Not Your Payment'


class JsonRpcPaymentOpenError(JsonRpcError):
    code = -54003
    message = 'Payment Open'


class JsonRpcReversedError(JsonRpcError):
    code = -54004
    message = 'Payment Reversed'


class JsonRpcReversalError(JsonRpcError):
    code = -54005
    message = 'Cannot Reversed'


class JsonRpcPaymentFoundError(JsonRpcError):
    code = -54006
    message = 'Payment Found with same invoice and ntb'


# Biller Status
class JsonRpcBillerNotFoundError(JsonRpcError):
    code = -55001
    message = 'Biller Not Found'


class JsonRpcBillerNetworkError(JsonRpcError):
    code = -55002
    message = 'Biller Network unrecognized'


class JsonRpcBillerError(JsonRpcError):
    code = -55000
    message = 'Biller Other Error'


class JsonRpcProdukNotFoundError(JsonRpcError):
    code = -56001
    message = _('Items Not Found')


# Biller Status
class JsonRpcCaNotRegisteredError(JsonRpcError):
    code = -56001
    message = 'CA Not Registered'


def custom_error(code, message):
    cls = JsonRpcError()
    cls.code = code
    cls.message = message
    return cls


begin_unix_time = datetime(1970, 1, 1)


def get_seconds(current_time=None):
    """
    Digunakan untuk menghitung jumlah detik sampai dengan waktu sekarang
    :param current_time: optional waktu yang akan dihitung
    :return:
    """

    if not current_time:
        current_time = datetime.utcnow()
    durasi = current_time - begin_unix_time
    log.info(f"{current_time} - {begin_unix_time}")
    return int(durasi.total_seconds())


def json_rpc_header(userid, password, key=None):
    """

    Digunakan untuk membuat header autentikasi saat akan mengirim request

    :param userid: string,
    :param password: string,
    :param key: optional string berisi kode enkripsi
    :return: {
        userid string,
        signature=string,
        key=string
        }

    """

    if not key:
        key = str(get_seconds())
    value = '&'.join([str(userid), str(key)])
    password = str(password)
    signature = hmac.new(key=str.encode(password), msg=str.encode(value),
                         digestmod=hashlib.sha256).digest()

    if sys.version < '3':
        encoded_signature = base64.encodestring(signature).replace('\n', '')
    else:
        encoded_signature = base64.encodebytes(signature).decode().replace('\n',
                                                                           '')
    return dict(userid=userid, signature=encoded_signature, key=key)


def get_mandatory(data, values):
    for value in values:
        if value not in data or not data[value]:
            raise JsonRpcDataInvalid(message="{} Not Found".format(value))


def validate_time(request):
    global lima_menit
    env = request.environ
    time_stamp = int(env['HTTP_KEY'])
    now = get_seconds()
    settings = get_settings()
    if 'diff_server_time' in settings and settings["diff_server_time"]:
        lima_menit = int(settings["diff_server_time"])

    if not request.devel and abs(now - time_stamp) > lima_menit:
        log.info(f"req time {time_stamp} server time {now}")
        raise JsonRpcInvalidTimeError

    return time_stamp


def get_jsonrpc(method, params, **kwargs):
    rid = kwargs.get("id") or int(get_random_number(6))
    return dict(jsonrpc='2.0', method=method, params=params,
                id=rid)


def send_rpc(auth, message):
    """
    Digunakan untuk mengirim data dengan methode JSONRPC 2.0 with os-auth
    :param auth: Dict
        {"user": user,
        "url": url,
        "key": key,
        "method": method,
        "timeout": optional,
        }
    :param message: Dict
    :return: Dict
    """
    userid = auth['user']
    password = auth['key']
    url = auth['url']
    headers = json_rpc_header(userid, password)
    params = dict(data=message)
    data = get_jsonrpc(auth["method"], params)
    timeout = 'timeout' in auth and int(auth['timeout']) or 5
    log.info("URL:{} timeout:{} detik".format(url, timeout))
    log.warning("REQUEST {}".format(data))
    try:
        results = requests.post(url, json=data, headers=headers,
                                timeout=timeout)  # data=jsondata,
    except Exception as e:
        log.warning(str(e))
        return
    if results.status_code != 200:
        log.info(results)
        log.info(results.text)
        return
    rows = results.text and json.loads(results.text) or None
    log.warning("RESPONSE {}".format(rows))
    return rows


##############################
# Web Service Authentication #
##############################
lima_menit = 300


def json_serial(obj):
    """JSON serializer for objects not serializable by default json code"""

    if isinstance(obj, (datetime, date)):
        return obj.isoformat()
    raise TypeError("Type %s not serializable" % type(obj))

def pars_rpc_url(params, method=None):
    values = params.split("@")
    user, key = values[0].split(":")
    url = values[1]
    resp = dict(
        url=url,
        user=user,
        key=key
    )
    if method:
        resp["method"] = method
    return resp