def monitor_by_email(self, users): mail_service = AppSetting.get_default('mail_service', {}) body = [ f'告警名称:{self.title}', f'告警对象:{self.target}', f'{"告警" if self.event == "1" else "恢复"}时间:{human_datetime()}', f'告警描述:{self.message}' ] if self.event == '2': body.append('故障持续:' + self.duration) if mail_service.get('server'): event_map = {'1': '监控告警通知', '2': '告警恢复通知'} subject = f'{event_map[self.event]}-{self.title}' mail = Mail(**mail_service) mail.send_text_mail(users, subject, '\r\n'.join(body) + '\r\n\r\n自动发送,请勿回复。') elif self.spug_key: data = { 'token': self.spug_key, 'event': self.event, 'subject': self.title, 'body': '\r\n'.join(body), 'users': list(users) } self.handle_request(f'{spug_server}/apis/notify/mail/', data, 'spug') else: Notify.make_monitor_notify('发送报警信息失败', '未配置报警服务调用凭据,请在系统管理/系统设置/报警服务设置中配置。')
def handle_user_info(user, x_real_ip): cache.delete(user.username) token_isvalid = user.access_token and len( user.access_token) == 32 and user.token_expired >= time.time() user.access_token = user.access_token if token_isvalid else uuid.uuid4( ).hex user.token_expired = time.time() + 8 * 60 * 60 user.last_login = human_datetime() user.last_ip = x_real_ip user.save() History.objects.create(user=user, ip=x_real_ip) verify_ip = AppSetting.get_default('verify_ip', 'True') == 'True' return json_response({ 'access_token': user.access_token, 'nickname': user.nickname, 'is_supper': user.is_supper, 'has_real_ip': x_real_ip and ipaddress.ip_address(x_real_ip).is_global if verify_ip else True, 'host_perms': [] if user.is_supper else user.host_perms, 'permissions': [] if user.is_supper else user.page_perms })
def notify_by_email(event, subject, grp): spug_key, u_ids = _parse_args(grp) users = set( x.email for x in Contact.objects.filter(id__in=u_ids, email__isnull=False)) if users: mail_service = json.loads(AppSetting.get_default('mail_service', '{}')) if mail_service.get('server'): event_map = {'1': '告警', '2': '恢复'} subject = f'{event_map[event]}-{subject}' mail = Mail(**mail_service) mail.send_text_mail(users, subject, f'{subject}\r\n\r\n自动发送,请勿回复。') elif spug_key: data = { 'token': spug_key, 'event': event, 'subject': subject, 'users': list(users) } requests.post(f'{spug_server}/apis/notify/mail/', json=data) else: Notify.make_notify(notify_source, '1', '发送报警信息失败', '未配置报警服务调用凭据,请在系统管理/系统设置/报警服务设置中配置。') else: Notify.make_notify(notify_source, '1', '发送报警信息失败', '未找到可用的通知对象,请确保设置了相关报警联系人的邮件地址。')
def notify_by_email(event, obj): spug_key, u_ids = _parse_args(obj.grp) users = set( x.email for x in Contact.objects.filter(id__in=u_ids, email__isnull=False)) if users: mail_service = json.loads(AppSetting.get_default('mail_service', '{}')) body = [ '告警名称:' + obj.name, '告警时间:' + human_datetime(), '告警描述:' + obj.out ] if event == '2': body.append('故障持续:' + obj.duration) if mail_service.get('server'): event_map = {'1': '告警发生', '2': '告警恢复'} subject = f'{event_map[event]}-{obj.name}' mail = Mail(**mail_service) mail.send_text_mail(users, subject, '\r\n'.join(body) + '\r\n\r\n自动发送,请勿回复。') elif spug_key: data = { 'token': spug_key, 'event': event, 'subject': obj.name, 'body': '\r\n'.join(body), 'users': list(users) } requests.post(f'{spug_server}/apis/notify/mail/', json=data) else: Notify.make_notify(notify_source, '1', '发送报警信息失败', '未配置报警服务调用凭据,请在系统管理/系统设置/报警服务设置中配置。') else: Notify.make_notify(notify_source, '1', '发送报警信息失败', '未找到可用的通知对象,请确保设置了相关报警联系人的邮件地址。')
def handle_user_info(request, user, captcha): cache.delete(user.username) key = f'{user.username}:code' if captcha: code = cache.get(key) if not code: return json_response(error='验证码已失效,请重新获取') if code != captcha: ttl = cache.ttl(key) cache.expire(key, ttl - 100) return json_response(error='验证码错误') cache.delete(key) else: mfa = AppSetting.get_default('MFA', {'enable': False}) if mfa['enable']: if not user.wx_token: return json_response(error='已启用登录双重认证,但您的账户未配置微信Token,请联系管理员') code = generate_random_str(6) send_login_wx_code(user.wx_token, code) cache.set(key, code, 300) return json_response({'required_mfa': True}) x_real_ip = get_request_real_ip(request.headers) token_isvalid = user.access_token and len( user.access_token) == 32 and user.token_expired >= time.time() user.access_token = user.access_token if token_isvalid else uuid.uuid4( ).hex user.token_expired = time.time() + 8 * 60 * 60 user.last_login = human_datetime() user.last_ip = x_real_ip user.save() History.objects.create(user=user, ip=x_real_ip) verify_ip = AppSetting.get_default('verify_ip', True) return json_response({ 'id': user.id, 'access_token': user.access_token, 'nickname': user.nickname, 'is_supper': user.is_supper, 'has_real_ip': x_real_ip and ipaddress.ip_address(x_real_ip).is_global if verify_ip else True, 'permissions': [] if user.is_supper else list(user.page_perms) })
def _parse_args(grp): spug_key = AppSetting.get_default('spug_key') if not spug_key: Notify.make_notify(notify_source, '1', '发送报警信息失败', '未配置报警服务调用凭据,请在系统管理/系统设置/报警服务设置中配置。') return None, None return spug_key, sum( [json.loads(x.contacts) for x in Group.objects.filter(id__in=grp)], [])
def send_login_wx_code(wx_token, code): url = f'{spug_server}/apis/login/wx/' spug_key = AppSetting.get_default('spug_key') res = requests.post(url, json={'token': spug_key, 'user': wx_token, 'code': code}, timeout=30) if res.status_code != 200: raise Exception(f'status code: {res.status_code}') res = res.json() if res.get('error'): raise Exception(res['error'])
def __init__(self, grp, event, target, title, message, duration): self.grp = grp self.event = event self.title = title self.target = target self.message = message self.duration = duration self.spug_key = AppSetting.get_default('spug_key') self.u_ids = []
def verify_user(self, scope, headers): close_old_connections() query_string = scope['query_string'].decode() x_real_ip = self.get_real_ip(headers) token = parse_qs(query_string).get('x-token', [''])[0] if token and len(token) == 32: user = User.objects.filter(access_token=token).first() if user and user.token_expired >= time.time() and user.is_active: if x_real_ip == user.last_ip or AppSetting.get_default( 'bind_ip') is False: scope['user'] = user return True, None return False, f'Verify failed: {x_real_ip} <> {user.last_ip if user else None}' return False, 'Token is invalid'
def post(self, request): form, error = JsonParser( Argument('id', type=int, required=False), Argument('name', help='请输入任务名称'), Argument('group', help='请选择任务分组'), Argument('targets', type=list, filter=lambda x: len(x), help='请输入监控地址'), Argument('type', filter=lambda x: x in dict(Detection.TYPES), help='请选择监控类型'), Argument('extra', required=False), Argument('desc', required=False), Argument('rate', type=int, default=5), Argument('threshold', type=int, default=3), Argument('quiet', type=int, default=24 * 60), Argument('notify_grp', type=list, help='请选择报警联系组'), Argument('notify_mode', type=list, help='请选择报警方式'), ).parse(request.body) if error is None: if set(form.notify_mode).intersection(['1', '2', '4']): if not AppSetting.get_default('spug_key'): return json_response( error='报警方式 微信、短信、邮件需要配置调用凭据(系统设置/基本设置),请配置后再启用该报警方式。') form.targets = json.dumps(form.targets) form.notify_grp = json.dumps(form.notify_grp) form.notify_mode = json.dumps(form.notify_mode) if form.id: Detection.objects.filter(pk=form.id).update( updated_at=human_datetime(), updated_by=request.user, **form) task = Detection.objects.filter(pk=form.id).first() if task and task.is_active: form.action = 'modify' rds_cli = get_redis_connection() rds_cli.lpush(settings.MONITOR_KEY, json.dumps(form)) else: dtt = Detection.objects.create(created_by=request.user, **form) form.action = 'add' form.id = dtt.id rds_cli = get_redis_connection() rds_cli.lpush(settings.MONITOR_KEY, json.dumps(form)) return json_response(error=error)
def _parse_params(request): app, env_id = None, None api_token = request.GET.get('apiToken') if api_token: rds = get_redis_connection() content = rds.get(api_token) if content: app_id, env_id = content.decode().split(',') app = App.objects.filter(pk=app_id).first() else: api_key = AppSetting.get_default('api_key') if api_key and request.GET.get('apiKey') == api_key: app_key = request.GET.get('app') env_key = request.GET.get('env') if app_key and env_key: app = App.objects.filter(key=app_key).first() env = Environment.objects.filter(key=env_key).first() if env: env_id = env.id return app, env_id, request.GET.get('noPrefix')
def _is_valid_token(request): api_key = AppSetting.get_default('api_key') # Gitlab Gitee Aliyun(Codeup) token = request.headers.get('X-Gitlab-Token') token = token or request.headers.get('X-Gitee-Token') token = token or request.headers.get('X-Codeup-Token') # Compatible the old version of gitlab token = token or request.GET.get('token') if token: return token == api_key # Gogs Github token = request.headers.get('X-Gogs-Signature') token = token or request.headers.get('X-Hub-Signature-256', '').replace( 'sha256=', '') if token: return token == hmac.new(api_key.encode(), request.body, hashlib.sha256).hexdigest() return False
def notify_by_email(event, subject, grp): spug_key, u_ids = _parse_args(grp) if u_ids is None: return users = set( x.email for x in Contact.objects.filter(id__in=u_ids, email__isnull=False)) if users: mail_service = json.loads(AppSetting.get_default('mail_service', '{}')) if mail_service.get('server'): event_map = {'1': '告警', '2': '恢复'} subject = f'{event_map[event]}-{subject}' mail = Mail(**mail_service) mail.send_text_mail(users, subject, f'{subject}\r\n\r\n自动发送,请勿回复。') else: data = { 'token': spug_key, 'event': event, 'subject': subject, 'users': list(users) } requests.post(f'{spug_server}/apis/notify/mail/', json=data)
def login(request): form, error = JsonParser(Argument('username', help='请输入用户名'), Argument('password', help='请输入密码'), Argument('captcha', required=False), Argument('type', required=False)).parse(request.body) if error is None: user = User.objects.filter(username=form.username, type=form.type).first() if user and not user.is_active: return json_response(error="账户已被系统禁用") if form.type == 'ldap': config = AppSetting.get_default('ldap_service') if not config: return json_response(error='请在系统设置中配置LDAP后再尝试通过该方式登录') ldap = LDAP(**config) is_success, message = ldap.valid_user(form.username, form.password) if is_success: if not user: user = User.objects.create(username=form.username, nickname=form.username, type=form.type) return handle_user_info(request, user, form.captcha) elif message: return json_response(error=message) else: if user and user.deleted_by is None: if user.verify_password(form.password): return handle_user_info(request, user, form.captcha) value = cache.get_or_set(form.username, 0, 86400) if value >= 3: if user and user.is_active: user.is_active = False user.save() return json_response(error='账户已被系统禁用') cache.set(form.username, value + 1, 86400) return json_response(error="用户名或密码错误,连续多次错误账户将会被禁用") return json_response(error=error)
def process_request(self, request): if request.path in settings.AUTHENTICATION_EXCLUDES: return None if any( x.match(request.path) for x in settings.AUTHENTICATION_EXCLUDES if hasattr(x, 'match')): return None access_token = request.headers.get('x-token') or request.GET.get( 'x-token') if access_token and len(access_token) == 32: x_real_ip = get_request_real_ip(request.headers) user = User.objects.filter(access_token=access_token).first() if user and user.token_expired >= time.time() and user.is_active: if x_real_ip == user.last_ip or AppSetting.get_default( 'bind_ip') is False: request.user = user user.token_expired = time.time() + 8 * 60 * 60 user.save() return None response = json_response(error="验证失败,请重新登录") response.status_code = 401 return response
def _parse_args(grp): spug_key = AppSetting.get_default('spug_key') return spug_key, sum( [json.loads(x.contacts) for x in Group.objects.filter(id__in=grp)], [])
def fetch_repo(deploy_id, git_repo): repo_dir = os.path.join(settings.REPOS_DIR, str(deploy_id)) pkey = AppSetting.get_default('private_key') with Git(git_repo, repo_dir, pkey) as git: return git.fetch_branches_tags()
def fetch_versions(deploy: Deploy): git_repo = deploy.extend_obj.git_repo repo_dir = os.path.join(settings.REPOS_DIR, str(deploy.id)) pkey = AppSetting.get_default('private_key') with Git(git_repo, repo_dir, pkey) as git: return git.fetch_branches_tags()
def kit_key(request): api_key = AppSetting.get_default('api_key') return json_response(api_key)