mirror of https://github.com/jumpserver/jumpserver
72 lines
2.3 KiB
Python
72 lines
2.3 KiB
Python
# -*- coding: utf-8 -*-
|
||
#
|
||
import base64
|
||
from Cryptodome.PublicKey import RSA
|
||
from Cryptodome.Cipher import PKCS1_v1_5
|
||
from Cryptodome import Random
|
||
|
||
from django.conf import settings
|
||
from .notifications import DifferentCityLoginMessage
|
||
from audits.models import UserLoginLog
|
||
from audits.const import DEFAULT_CITY
|
||
from common.utils import validate_ip, get_ip_city, get_request_ip
|
||
from common.utils import get_logger
|
||
|
||
logger = get_logger(__file__)
|
||
|
||
|
||
def gen_key_pair():
|
||
""" 生成加密key
|
||
用于登录页面提交用户名/密码时,对密码进行加密(前端)/解密(后端)
|
||
"""
|
||
random_generator = Random.new().read
|
||
rsa = RSA.generate(1024, random_generator)
|
||
rsa_private_key = rsa.exportKey().decode()
|
||
rsa_public_key = rsa.publickey().exportKey().decode()
|
||
return rsa_private_key, rsa_public_key
|
||
|
||
|
||
def rsa_encrypt(message, rsa_public_key):
|
||
""" 加密登录密码 """
|
||
key = RSA.importKey(rsa_public_key)
|
||
cipher = PKCS1_v1_5.new(key)
|
||
cipher_text = base64.b64encode(cipher.encrypt(message.encode())).decode()
|
||
return cipher_text
|
||
|
||
|
||
def rsa_decrypt(cipher_text, rsa_private_key=None):
|
||
""" 解密登录密码 """
|
||
if rsa_private_key is None:
|
||
# rsa_private_key 为 None,可以能是API请求认证,不需要解密
|
||
return cipher_text
|
||
|
||
key = RSA.importKey(rsa_private_key)
|
||
cipher = PKCS1_v1_5.new(key)
|
||
cipher_decoded = base64.b64decode(cipher_text.encode())
|
||
# Todo: 弄明白为何要以下这么写,https://xbuba.com/questions/57035263
|
||
if len(cipher_decoded) == 127:
|
||
hex_fixed = '00' + cipher_decoded.hex()
|
||
cipher_decoded = base64.b16decode(hex_fixed.upper())
|
||
message = cipher.decrypt(cipher_decoded, b'error').decode()
|
||
return message
|
||
|
||
|
||
def check_different_city_login_if_need(user, request):
|
||
if not settings.SECURITY_CHECK_DIFFERENT_CITY_LOGIN:
|
||
return
|
||
|
||
ip = get_request_ip(request) or '0.0.0.0'
|
||
|
||
if not (ip and validate_ip(ip)):
|
||
city = DEFAULT_CITY
|
||
else:
|
||
city = get_ip_city(ip) or DEFAULT_CITY
|
||
|
||
city_white = ['LAN', ]
|
||
if city not in city_white:
|
||
last_user_login = UserLoginLog.objects.exclude(city__in=city_white) \
|
||
.filter(username=user.username, status=True).first()
|
||
|
||
if last_user_login and last_user_login.city != city:
|
||
DifferentCityLoginMessage(user, ip, city).publish_async()
|