Novo Ambiente | Atualização 4

This commit is contained in:
Vitoria 2025-02-13 15:56:30 -03:00
parent 003a6c7e98
commit d89c202ad5
58 changed files with 981 additions and 43 deletions

17
.env
View File

@ -10,6 +10,7 @@ SMTP_PASSWORD=j5j@QaSB\Z4<)W]M|hOYbC\605zfGcv:
SMTP_HOST=mail.itguys.com.br SMTP_HOST=mail.itguys.com.br
SMTP_PORT=465 SMTP_PORT=465
SMTP_RECIPIENT=comercial@itguys.com.br SMTP_RECIPIENT=comercial@itguys.com.br
# Configurações LDAP (Windows AD) # Configurações LDAP (Windows AD)
LDAP_SERVER=10.10.253.199/itguys.com.br LDAP_SERVER=10.10.253.199/itguys.com.br
LDAP_DOMAIN=itguys.com.br LDAP_DOMAIN=itguys.com.br
@ -17,7 +18,21 @@ LDAP_BASE_DN=dc=itguys,dc=com,dc=br
LDAP_USER=itguys\teste.dev LDAP_USER=itguys\teste.dev
LDAP_PASSWORD=123Mudar LDAP_PASSWORD=123Mudar
ZAMMAD_API=http://10.10.253.59/api/v1/ #API ZAMMAD
ZAMMAD_API= https://zammad.itguys.com.br/api/v1
ZAMMAD_USERNAME=teste.dev@itguys.com.br ZAMMAD_USERNAME=teste.dev@itguys.com.br
ZAMMAD_PASSWORD=123Mudar ZAMMAD_PASSWORD=123Mudar
ZAMMAD_TOKEN =QiFbQ7txT0BS_3N8GrwOzAS6f7ziVTa1VqcGGpaPFscvdcfnBVjgq699fFj6NpQW #Token expira em 2065
#API Inter
CLIENT_ID = bfedfb96-7caf-4310-8632-a924c5daa7e1
CLIENT_SECRET = 502d577e-b324-4b93-9624-e6b082588dc5
CERT_PATH = InterAPI_Certificado.crt
CERT_KEY_PATH = keyinter.pem
#API ZABBIX
ZABBIX_URL = https://mimir.itguys.com.br/zabbix/api_jsonrpc.php
TOKEN_ZABBIX = 10925e9e452cade5270f4d930feb3b5e1aa2cc9b366c1c5b4d72996212b12c93
ZABBIX_USER = vitoria.oliveira
ZABBIX_PASSWORD = 123Mudar

27
InterAPI_Certificado.crt Normal file
View File

@ -0,0 +1,27 @@
-----BEGIN CERTIFICATE-----
MIIEljCCA36gAwIBAgIQJ18cUeVWL5QojTvvnDiLyTANBgkqhkiG9w0BAQsFADCB
ijELMAkGA1UEBhMCQlIxFTATBgNVBAgMDE1pbmFzIEdlcmFpczEXMBUGA1UEBwwO
QmVsbyBIb3Jpem9udGUxDDAKBgNVBAoMA0FQSTELMAkGA1UECwwCSVQxMDAuBgNV
BAMMJ0FQSSBJbnRlcm1lZGlhdGUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5CTAeFw0y
NTAxMjcxOTAyNTlaFw0yNjAxMjcyMDAyNTlaMIGrMQswCQYDVQQGEwJCUjELMAkG
A1UECBMCUkoxFzAVBgNVBAcTDlJJTyBERSBKQU5FSVJPMS0wKwYDVQQLEyRjMzI3
NWVhZi04NDA2LTQzMDAtOTMzNC04OTRlZTRhMWYyOGIxDTALBgNVBAoTBG51bGwx
ODA2BgNVBAMTL1IgUk9DQU5DT1VSVCBDQVZBREFTIENPTlNVTFRPUklBIEVNIElO
Rk9STUFUSUNBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAl8fvYOJe
kMJ1BH9m95lQO9zLEG153PZuoSBgEvCJ522tJlAPp1oo+SgC1LCSRLaDOxhlJbIo
0BIC5/ule6QmAMtaoC+qt+e8QzT8PKm7IX/SzpjziV7HNHKlEiNCeGC047iYTOWv
c843uUVicMBZfSJXodzE9RYIC4oTZnB83gvlaVk7xVyP4Auimg09F4dZTQjeI06T
RBgiPNJDn0+ilKWRUX2HGs0wnD2JX7wGPB+mkV0z5Rsv0F1D7IsIa3TdMsyBdzxX
0haz/bSB/R5ZxMTHZ3bzYoPWd5cSKenYu1FyFTKHebFhIFy2Vz6kbakVOgrWZDFx
yg8dzuTnKUzdWwIDAQABo4HUMIHRMAkGA1UdEwQCMAAwHwYDVR0jBBgwFoAUFBVp
/TT0EQj/WbtOGcyVlyKK4DwwHQYDVR0OBBYEFHQ+z6vbCts4TrDS5s+hIVHbh6rz
MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw
VQYDVR0fBE4wTDBKoEigRoZEaHR0cDovL2NybC1hcGkuYmkubG9jYWwvY3JsLzE5
MzY0ZTc2LWM0YmUtNDBiNi05YzcxLWEzYTdiNDA0NzRhNC5jcmwwDQYJKoZIhvcN
AQELBQADggEBAHbjYT794YA7W9KsX+uXQIxXvd5IBVt+xzQw787/PgQ3elJNS36R
Yq5FdFjdvYDXTyFEi2YS+egqW+4wdBIvMUcM+86HhuhcKbkAjeMu1yM6vcORuuTV
BJ47vbR3hQiABGYhzOeq00CazFcpnDgydxx0sIhzWsEYrKOozUcXqdPFxVCpeR0X
rzEJgyrJd1l6fI+X8z/n3BCqYfCk+OJ8HYgTT8wpAJBVynuRNJRjYTIU3yySyEal
Fyny4CZxltqbnS+gZedyJZYf9aEPxQKNXcdpqGdvnmLv62EuWU129Z97FJ9rWB39
uFVdK6Uz+Klv+DqP3hDLatxqDsp30QrdwG0=
-----END CERTIFICATE-----

View File

@ -9,6 +9,13 @@ from .routes.perfil import perfil
from .routes.montagem import montagem from .routes.montagem import montagem
from .routes.zabbix import zabbix from .routes.zabbix import zabbix
from .routes.integrator import zammad from .routes.integrator import zammad
from.routes.boletos import boletos
from.routes.upload_img import imagem
from.routes.servicos import servicos
from.routes.empresas import empresas
from.routes.newuser import newuser
from.routes.integrazabbix import integra
# Inicializa o MySQL # Inicializa o MySQL
mysql = MySQL() mysql = MySQL()
@ -33,7 +40,14 @@ def create_app():
app.register_blueprint(perfil) app.register_blueprint(perfil)
app.register_blueprint(montagem) app.register_blueprint(montagem)
app.register_blueprint(zabbix) app.register_blueprint(zabbix)
app.register_blueprint(integra)
app.register_blueprint(zammad) app.register_blueprint(zammad)
app.register_blueprint(boletos)
app.register_blueprint(imagem)
app.register_blueprint(servicos)
app.register_blueprint(empresas)
app.register_blueprint(newuser)
@app.route('/') @app.route('/')
def home(): def home():

View File

@ -17,7 +17,7 @@ class Config:
MYSQL_DB = os.getenv('MYSQL_DB', 'itguys') MYSQL_DB = os.getenv('MYSQL_DB', 'itguys')
MYSQL_CURSORCLASS = 'DictCursor' MYSQL_CURSORCLASS = 'DictCursor'
# Configurações do LDAP (Windows AD) # Configurações do LDAP (Windows AD)
LDAP_SERVER = os.getenv('LDAP_SERVER', 'ldap://itguys.com.br') # IP/Hostname do servidor LDAP LDAP_SERVER = os.getenv('LDAP_SERVER', 'ldap://itguys.com.br') # IP/Hostname do servidor LDAP
LDAP_DOMAIN = os.getenv('LDAP_DOMAIN', 'itguys.com.br') # Domínio do AD (FQDN) LDAP_DOMAIN = os.getenv('LDAP_DOMAIN', 'itguys.com.br') # Domínio do AD (FQDN)
LDAP_BASE_DN = os.getenv('LDAP_BASE_DN', 'dc=itguys,dc=com,dc=br') # Distinguished Name (DN) LDAP_BASE_DN = os.getenv('LDAP_BASE_DN', 'dc=itguys,dc=com,dc=br') # Distinguished Name (DN)
@ -25,8 +25,14 @@ class Config:
LDAP_PASSWORD = os.getenv('LDAP_PASSWORD', '123Mudar') # Senha do usuário LDAP LDAP_PASSWORD = os.getenv('LDAP_PASSWORD', '123Mudar') # Senha do usuário LDAP
#Api Zammad #Api Zammad
zammad_api_url = 'http://zammad.itguys.com.br/api/v1' zammad_api_url = os.getenv('zammad_api_url','http://zammad.itguys.com.br/api/v1')
zammad_token = 'L081vJ19kood2uDlTSSt59LWBaewT9-a-MH_VKno8RY' zammad_token = os.getenv('zammad_token','L081vJ19kood2uDlTSSt59LWBaewT9-a-MH_VKno8RY')
#ID Inter
CLIENT_ID = os.getenv('CLIENT_ID',"bfedfb96-7caf-4310-8632-a924c5daa7e1")
CLIENT_SECRET = os.getenv ('CLIENT_SECRET',"502d577e-b324-4b93-9624-e6b082588dc5")
CERT_PATH = os.getenv('CERT_PATH',"InterAPI_Certificado.crt")
CERT_KEY_PATH = os.getenv('CERT_KEY_PATH',"keyinter.pem")

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -5,8 +5,8 @@ import re
import ldap3 import ldap3
from ldap3.core.exceptions import LDAPSocketOpenError, LDAPException from ldap3.core.exceptions import LDAPSocketOpenError, LDAPException
from functools import wraps from functools import wraps
from flask_mysqldb import MySQL
import logging import logging
from flask_mysqldb import MySQL
# Configuração de logging para depuração # Configuração de logging para depuração
logging.basicConfig(level=logging.DEBUG) logging.basicConfig(level=logging.DEBUG)
@ -14,7 +14,6 @@ logging.basicConfig(level=logging.DEBUG)
auth = Blueprint('auth', __name__) auth = Blueprint('auth', __name__)
mysql = MySQL() mysql = MySQL()
# Decorador para validar o token JWT # Decorador para validar o token JWT
def token_required(f): def token_required(f):
@wraps(f) @wraps(f)
@ -26,22 +25,7 @@ def token_required(f):
try: try:
data = jwt.decode(token, current_app.config['SECRET_KEY'], algorithms=["HS256"]) data = jwt.decode(token, current_app.config['SECRET_KEY'], algorithms=["HS256"])
except jwt.ExpiredSignatureError: except jwt.ExpiredSignatureError:
# Caso o token esteja expirado, gere um novo token return jsonify({'msg': 'Token expirado!'}), 401
try:
# Obter o payload original para criar um novo token
payload = jwt.decode(token, current_app.config['SECRET_KEY'], algorithms=["HS256"], options={"verify_exp": False})
# Gere um novo token com nova validade
new_token = jwt.encode({
'user_id': payload['user_id'],
'exp': datetime.datetime.utcnow() + datetime.timedelta(hours=1)
}, current_app.config['SECRET_KEY'], algorithm="HS256")
response = jsonify({'msg': 'Token expirado! Novo token gerado.', 'new_token': new_token})
response.status_code = 401
return response
except Exception as e:
return jsonify({'msg': 'Erro ao processar o token expirado.', 'error': str(e)}), 401
except jwt.InvalidTokenError: except jwt.InvalidTokenError:
return jsonify({'msg': 'Token inválido!'}), 401 return jsonify({'msg': 'Token inválido!'}), 401
@ -84,31 +68,20 @@ def login():
except ValueError: except ValueError:
return jsonify({'msg': 'Formato de usuário inválido. Use "usuario@dominio.com".'}), 400 return jsonify({'msg': 'Formato de usuário inválido. Use "usuario@dominio.com".'}), 400
# Buscar informações de domínio no banco de dados # Verificar se o usuário está associado à empresa no MySQL
try: try:
with mysql.connection.cursor() as cur:
cur.execute("SELECT idempresa, ip_dominio FROM empresa WHERE dominio = %s", (domain,))
empresa_result = cur.fetchone()
if not empresa_result:
return jsonify({'msg': 'Domínio não encontrado no banco de dados'}), 404
id_empresa, ip_dominio = empresa_result
# Verificar se o usuário está associado à empresa no MySQL
with mysql.connection.cursor() as cur: with mysql.connection.cursor() as cur:
cur.execute("SELECT empresa_id, dominio FROM view_usuario_empresa WHERE usuario = %s AND dominio = %s", (username, domain)) cur.execute("SELECT empresa_id, dominio FROM view_usuario_empresa WHERE usuario = %s AND dominio = %s", (username, domain))
result = cur.fetchone() result = cur.fetchone()
if not result: if not result:
return jsonify({'msg': 'Usuário não associado à empresa'}), 404 return jsonify({'msg': 'Usuário não associado à empresa'}), 404
except Exception as e: except Exception as e:
logging.error(f"Erro no banco de dados: {str(e)}") logging.error(f"Erro no banco de dados: {str(e)}")
return jsonify({'msg': 'Erro no banco de dados'}), 500 return jsonify({'msg': 'Erro no banco de dados'}), 500
# Conexão LDAP com autenticação # Autenticação LDAP usando domínio extraído
ldap_server = f'ldap://{"itguys.com.br:389"}' ldap_server = f'ldap://{domain}:389'
ldap_user = f'{domain}\\{username}' ldap_user = f'{domain}\\{username}'
try: try:
@ -144,6 +117,3 @@ def login():
except Exception as e: except Exception as e:
logging.error(f"Erro inesperado: {str(e)}") logging.error(f"Erro inesperado: {str(e)}")
return jsonify({'msg': 'Erro inesperado durante a autenticação.'}), 500 return jsonify({'msg': 'Erro inesperado durante a autenticação.'}), 500

334
app/routes/boletos.py Normal file
View File

@ -0,0 +1,334 @@
import os
import json
import requests
from time import time
from functools import wraps
from base64 import b64decode
from datetime import datetime, timedelta
from flask import Flask, Blueprint, jsonify, request, Response
from flask_mysqldb import MySQL
from flask_cors import CORS
from .auth import token_required
from dotenv import load_dotenv
from flask import send_file
import io
load_dotenv()
# Configurações da API do Banco Inter
CLIENT_ID = os.environ.get("CLIENT_ID")
CLIENT_SECRET = os.environ.get("CLIENT_SECRET")
CERT_PATH = os.environ.get("CERT_PATH")
CERT_KEY_PATH = os.environ.get("CERT_KEY_PATH")
ACCOUNT = os.environ.get("ACCOUNT", None)
API_BASE_URL = "https://cdpj.partners.bancointer.com.br"
boletos = Blueprint('boletos', __name__)
app = Flask(__name__)
cors = CORS(app, resources={r"/v1/boletos/*": {"origins": "*", "methods": ["GET", "POST", "PUT", "OPTIONS"]}})
app.config["CORS_HEADERS"] = ["Content-Type", "Authorization", "Content-Disposition", "Content-Length"]
MYSQL_HOST = os.environ.get('MYSQL_HOST')
MYSQL_PORT = os.environ.get('MYSQL_PORT')
MYSQL_USER = os.environ.get('MYSQL_USER')
MYSQL_PASSWORD = os.environ.get('MYSQL_PASSWORD')
MYSQL_DB = os.environ.get('MYSQL_DB')
MYSQL_CURSORCLASS = os.environ.get("MYSQL_CURSORCLASS")
mysql = MySQL()
token_cache = {}
def intercept_options(f):
@wraps(f)
def decorated(*args, **kwargs):
if request.method == "OPTIONS":
response = jsonify({"status": "ok"})
response.headers.add("Access-Control-Allow-Origin", "*")
response.headers.add("Access-Control-Allow-Methods", "GET,POST,PUT,OPTIONS")
response.headers.add("Access-Control-Allow-Headers", "Content-Type,Authorization,Content-Disposition,Content-Length")
return response, 200
return f(*args, **kwargs)
return decorated
def obter_token(scopes=["boleto-cobranca.write", "boleto-cobranca.read"]):
"""Obtem um token de acesso para a API do Banco Inter."""
scopes_param = " ".join(scopes)
if token_cache.get(scopes_param):
cached_token = token_cache.get(scopes_param)
# token is still valid
if cached_token.get("expires_at") > int(time()):
return cached_token["token"]
try:
request_string = f"client_id={CLIENT_ID}&client_secret={CLIENT_SECRET}&scope={scopes_param}&grant_type=client_credentials"
print("request_string", request_string)
response = requests.post(url=f"{API_BASE_URL}/oauth/v2/token",
headers={"Content-Type": "application/x-www-form-urlencoded"},
cert=(CERT_PATH, CERT_KEY_PATH),
data=request_string)
data_json = response.json()
token = data_json.get("access_token")
token_cache[scopes_param] = {
"token": token,
"expires_at": data_json.get("expires_in") + int(time()),
}
return token
except Exception as e:
print(f"Erro ao obter token de acesso: {e}")
return None
def emitir_cobranca(token, dados_cobranca):
"""Emite uma cobrança para o Banco Inter de forma assíncrona."""
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json",
"Accept": "application/json"
}
try:
response = requests.post(
f"{API_BASE_URL}/cobranca/v3/cobrancas",
headers=headers,
cert=(CERT_PATH, CERT_KEY_PATH),
json=dados_cobranca
)
# Captura a resposta completa
resposta_json = response.json()
# Exibe detalhes da resposta para debug
print("Código de status:", response.status_code)
print("Resposta da API:", json.dumps(resposta_json, indent=4, ensure_ascii=False))
return resposta_json
except Exception as e:
print(f"Erro ao emitir cobrança: {e}")
return None
def obter_cobranca(token, codigo_solicitacao):
"""Obtem uma cobrança."""
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "Application/json",
}
try:
response = requests.get(f"{API_BASE_URL}/cobranca/v3/cobrancas/{codigo_solicitacao}",
headers=headers,
cert=(CERT_PATH, CERT_KEY_PATH))
return response.json()
except Exception as e:
print(f"Erro ao emitir cobrança:{e}")
return None
def obter_cobranca_pdf(token, codigo_solicitacao):
"""Obtem o PDF de uma cobrança."""
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "Application/json",
}
try:
# Certifique-se de que o codigo_solicitacao seja inserido corretamente na URL
url = f"{API_BASE_URL}/cobranca/v3/cobrancas/{codigo_solicitacao}/pdf"
response = requests.get(url,
headers=headers,
cert=(CERT_PATH, CERT_KEY_PATH))
return response.json()
except Exception as e:
print(f"Erro ao emitir cobrança:{e}")
return None
def processar_cobranca_cliente(cliente, token):
"""
Processa a emissão da cobrança para um cliente específico,
retornando os dados relevantes.
"""
id_empresa = cliente["idempresa"]
hoje = datetime.now()
vencimento = (hoje + timedelta(days=5)).strftime("%Y-%m-%d")
dados_cobranca = {
"seuNumero": f"boleto-{id_empresa}",
"valorNominal": str(cliente["valor_servico"]),
"dataVencimento": vencimento,
"numDiasAgenda": 30,
"pagador": {
"cpfCnpj": cliente["cpf_cnpj"],
"tipoPessoa": cliente["tipo_pessoa"],
"nome": cliente["nome"],
"telefone": cliente["telefone"],
"endereco": cliente["endereco"],
"cidade": cliente["cidade"],
"uf": cliente["uf"],
"cep": cliente["cep"],
},
"formasRecebimento": ["BOLETO", "PIX"],
}
emissao_cobranca = emitir_cobranca(token, dados_cobranca)
codigo_solicitacao = emissao_cobranca.get("codigoSolicitacao") if emissao_cobranca else None
if not codigo_solicitacao:
return {
"cliente": cliente,
"status": "erro",
"mensagem": "Falha ao emitir cobrança."
}
cobranca = obter_cobranca(token, codigo_solicitacao)
if not cobranca:
return {
"cliente": cliente,
"status": "erro",
"mensagem": "Falha ao obter cobrança."
}
boleto_data = cobranca.get("cobranca", {}).get("boleto", {})
codigo_barras = boleto_data.get("codigoBarras")
linha_digitavel = cobranca.get("boleto", {}).get("linhaDigitavel")
pix_data = cobranca.get("pix", {})
pix_copia_e_cola = pix_data.get("pixCopiaECola")
cobranca_pdf = obter_cobranca_pdf(token, codigo_solicitacao)
if not cobranca_pdf or "pdf" not in cobranca_pdf:
return {
"cliente": cliente,
"status": "erro",
"mensagem": "Falha ao obter PDF da cobrança."
}
return {
"cliente": cliente,
"status": "sucesso",
"codigo_solicitacao": codigo_solicitacao,
"codigo_barras": codigo_barras,
"linha_digitavel": linha_digitavel,
"pix_copia_e_cola": pix_copia_e_cola,
"pdf": cobranca_pdf["pdf"],
}
@boletos.route('/', methods=['POST', 'OPTIONS'])
@intercept_options
@token_required
def gerar_boletos(data):
domain = data.get('domain')
escopos = data.get('scopes', [])
escopos.append("boleto-cobranca.write")
escopos.append("boleto-cobranca.read")
print("data", data)
print(domain)
print(escopos)
if 'boleto-cobranca.write' not in escopos:
return jsonify({"erro": "Permissão necessária: boleto-cobranca.write"}), 403
if not domain:
return jsonify({"error": "Domínio não encontrado no token"}), 400
hoje = datetime.now()
if hoje.day > 12:
return jsonify({"erro": "Boletos só podem ser gerados até o dia 12 de cada mês."}), 403
try:
cur = mysql.connection.cursor()
cur.execute(
"SELECT idempresa, nome, cpf_cnpj, tipo_pessoa, telefone, endereco, cidade, uf, cep, valor_servico FROM empresa WHERE dominio = %s",
(domain,)
)
clientes = cur.fetchall()
cur.close()
if not clientes:
return jsonify({"erro": "Nenhum cliente encontrado."}), 404
except Exception as e:
print(f"Erro ao acessar o banco de dados: {e}")
return jsonify({"erro": "Erro ao acessar o banco de dados."}), 500
token = obter_token(escopos)
if not token:
return jsonify({"erro": "Falha ao obter o token de acesso."}), 401
resultados = []
for cliente in clientes:
resultado = processar_cobranca_cliente(cliente, token)
resultados.append(resultado)
return jsonify({"resultados": resultados}), 200
@boletos.route('/<codigo_solicitacao>', methods=['GET', 'OPTIONS'])
@intercept_options
@token_required
def recuperar_cobranca(token_data, codigo_solicitacao):
print("codigo_solicitacao", codigo_solicitacao)
scopes = token_data.get('scopes', [])
print("token_data", token_data)
if 'boleto-cobranca.read' not in scopes:
return jsonify({"erro": "Permissao necessaria: boleto-cobranca.read"}), 403
token = obter_token(scopes)
if not token:
return jsonify({"erro": "Falha ao obter o token de acesso"}), 401
cobranca = obter_cobranca(token, codigo_solicitacao)
if cobranca is None:
return jsonify({"erro": "Erro ao obter PDF"}), 404
try:
codigo_barras = cobranca.get("boleto").get("codigoBarras")
linha_digitavel = cobranca.get("boleto").get("linhaDigitavel")
pix_copia_e_cola = cobranca.get("pix").get("pixCopiaECola")
return jsonify({
"codigo_solicitacao": codigo_solicitacao,
"codigo_barras": codigo_barras,
"linha_digitavel": linha_digitavel,
"pix_copia_e_cola": pix_copia_e_cola,
}), 200
except Exception as e:
return jsonify({"erro": f"Erro ao buscar cobranca: {e}"}), 500
@boletos.route('/<codigo_solicitacao>/pdf', methods=['GET', 'OPTIONS'])
@intercept_options
@token_required
def recuperar_boleto(token_data, codigo_solicitacao):
print("codigo_solicitacao", codigo_solicitacao)
scopes = token_data.get('scopes', [])
print("token_data", token_data)
if 'boleto-cobranca.read' not in scopes:
return jsonify({"erro": "Permissao necessaria: boleto-cobranca.read"}), 403
token = obter_token(scopes)
if not token:
return jsonify({"erro": "Falha ao obter o token de acesso"}), 401
cobranca_pdf = obter_cobranca_pdf(token, codigo_solicitacao)
if cobranca_pdf is None:
return jsonify({"erro": "Erro ao obter PDF"}), 404
try:
pdf_content_base64 = cobranca_pdf["pdf"]
pdf_content_bytes = b64decode(pdf_content_base64, validate=True)
return Response(pdf_content_bytes,
mimetype='application/pdf',
headers={
"Content-Disposition": "inline; filename=boleto.pdf",
"Content-Type": "application/pdf",
"Content-Length": len(pdf_content_bytes)
})
except Exception as e:
return jsonify({"erro": f"Erro ao decodificar PDF: {e}"}), 500
if __name__ == "__main__":
app.register_blueprint(boletos)
app.run(port=5000, debug=True)

27
app/routes/client.py Normal file
View File

@ -0,0 +1,27 @@
import os
import sys
import requests
from dotenv import load_dotenv
from flask import Blueprint
load_dotenv()
codigo_solicitacao = "<ALGUM_CODIGO_DE_SOLICITACAO>"
API_BASE_URL = "https://dev.itguys.com.br"
url = f"{API_BASE_URL}/v1/boletos/{codigo_solicitacao}/pdf"
headers = {
"Authorization": "Bearer <JWT_SECRET>",
"Content-Type": "application/json"
}
try:
response = requests.get(url, headers=headers)
if response.status_code != 200:
print("Erro obtendo o PDF")
sys.exit(1)
# salva o conteudo da resposta em um arquivo, pois ja retorna como bytes
with open(f"{codigo_solicitacao}-cobranca.pdf", "wb") as pdf_file:
pdf_file.write(response.content)
print(f"PDF salvo em {codigo_solicitacao}-cobranca.pdf")
except Exception as e:
print(e)
sys.exit(1)

View File

@ -5,7 +5,7 @@ from dotenv import load_dotenv
load_dotenv() load_dotenv()
class Config: class Config:
# Configurações Gerais # Configurações Gerais
SECRET_KEY = os.getenv('SECRET_KEY', 'd702717e2361ba1a31ce3b98d28ee3e24e2e6a9be8e2afd8e004f842563bacbd') SECRET_KEY = os.getenv('SECRET_KEY', 'd702717e2361ba1a31ce3b98d28ee3e24e2e6a9be8e2afd8e004f842563bacbd')
DEBUG = os.getenv('DEBUG', 'True') == 'True' DEBUG = os.getenv('DEBUG', 'True') == 'True'
JSON_SORT_KEYS = False JSON_SORT_KEYS = False

25
app/routes/empresas.py Normal file
View File

@ -0,0 +1,25 @@
import logging
from flask import Blueprint, jsonify
from flask_mysqldb import MySQL
from .auth import token_required # Importando o token_required
empresas = Blueprint('empresas', __name__) # Criando o Blueprint
mysql = MySQL() # Criando a instância do MySQL
@empresas.route('/empresas', methods=['GET'])
@token_required
def listar_empresas(data): # Agora aceita o argumento 'data'
try:
cur = mysql.connection.cursor()
cur.execute("SELECT idempresa, nome, dominio FROM empresa")
resultados = cur.fetchall()
# Ajuste aqui: Adicionando o 'id_empresa' no dicionário
empresas_list = [{"idempresa": row['idempresa'], "nome": row['nome'], "dominio": row['dominio']} for row in resultados]
return jsonify(empresas_list), 200
except Exception:
return jsonify({"erro": "Erro interno no servidor"}), 500

124
app/routes/extrato.py Normal file
View File

@ -0,0 +1,124 @@
import os
from time import time
from functools import wraps
from datetime import date
import requests
from dotenv import load_dotenv
# Carregar variáveis de ambiente do arquivo .env
load_dotenv()
# Definição das credenciais e URL base da API
CLIENT_ID = os.environ.get("CLIENT_ID")
CLIENT_SECRET = os.environ.get("CLIENT_SECRET")
CERT_PATH = os.environ.get("CERT_PATH")
CERT_KEY_PATH = os.environ.get("CERT_KEY_PATH")
ACCOUNT = os.environ.get("ACCOUNT", None)
API_BASE_URL = "https://cdpj.partners.bancointer.com.br"
# Cache para tokens de acesso
token_cache = {}
def token_required(f):
@wraps(f)
def decorated(*args, **kwargs):
data = {
"domain": "example.com",
"scopes": ["boleto-cobranca.write", "boleto-cobranca.read"]
}
return f(data, *args, **kwargs)
return decorated
def obter_token(scopes=["boleto-cobranca.write", "boleto-cobranca.read"]):
"""Obtem um token de acesso para a API do Banco Inter."""
scopes_param = " ".join(scopes)
if token_cache.get(scopes_param):
cached_token = token_cache.get(scopes_param)
# token is still valid
if cached_token.get("expires_at") > int(time()):
return cached_token["token"]
try:
request_string = f"client_id={CLIENT_ID}&client_secret={CLIENT_SECRET}&scope={scopes_param}&grant_type=client_credentials"
print("request_string", request_string)
response = requests.post(url=f"{API_BASE_URL}/oauth/v2/token",
headers={"Content-Type": "application/x-www-form-urlencoded"},
cert=(CERT_PATH, CERT_KEY_PATH),
data=request_string)
# Verificar o status da resposta
if response.status_code != 200:
print(f"Erro na requisição: {response.status_code}")
print("Resposta bruta:", response.text) # Imprime a resposta bruta para debugar
data_json = response.json()
print("Resposta JSON:", data_json) # Imprimir o JSON da resposta
token = data_json.get("access_token")
# Cache do token
token_cache[scopes_param] = {
"token": token,
"expires_at": data_json.get("expires_in") + int(time()),
}
return token
except Exception as e:
print(f"Erro ao obter token de acesso: {e}")
return None
def get_balance():
"""Obtém o saldo da conta no Banco Inter."""
token = obter_token(["saldo.read"])
if not token:
print("Erro: não foi possível obter o token de acesso.")
return None
try:
response = requests.get(
f"{API_BASE_URL}/banking/v2/saldo",
headers={"Authorization": f"Bearer {token}"},
cert=(CERT_PATH, CERT_KEY_PATH)
)
response.raise_for_status()
return response.json()
except requests.RequestException as e:
print(f"Erro ao obter saldo: {e}")
return None
def get_statements(start_date: str, end_date: str):
"""Obtém o extrato da conta no Banco Inter entre as datas informadas."""
token = obter_token(["extrato.read"])
if not token:
print("Erro: não foi possível obter o token de acesso.")
return None
try:
response = requests.get(
f"{API_BASE_URL}/banking/v2/extrato",
params={"dataInicio": start_date, "dataFim": end_date},
headers={"Authorization": f"Bearer {token}"},
cert=(CERT_PATH, CERT_KEY_PATH)
)
response.raise_for_status()
return response.json()
except requests.RequestException as e:
print(f"Erro ao obter extrato: {e}")
return None
if __name__ == "__main__":
time_now = time()
yesterday = date.fromtimestamp(time_now - 60 * 60 * 24).strftime("%Y-%m-%d")
today = date.fromtimestamp(time_now).strftime("%Y-%m-%d")
print(f"Obtendo informações financeiras para o período: {yesterday} - {today}")
# Obter saldo
balance_data = get_balance()
print("Saldo:", balance_data)
# Obter extrato
statements_data = get_statements(yesterday, today)
print("Extrato:", statements_data)

View File

@ -0,0 +1,45 @@
from flask import Blueprint, jsonify
from .auth import token_required # Importa o decorador de autenticação
from .newzabbix import zapi # Importa a conexão Zabbix
integra = Blueprint('integra', __name__)
def obter_dados_zabbix():
try:
grupos = zapi.hostgroup.get(output="extend")
resultado = []
for grupo in grupos:
hosts = zapi.host.get(groupids=grupo['groupid'], output="extend")
hosts_info = []
for host in hosts:
itens = zapi.item.get(hostids=host['hostid'], output="extend",
filter={"key_": ["system.uptime", "net.if.in", "net.if.out", "vm.memory.size", "vfs.fs.size"]})
metricas = {item['key_']: item.get('lastvalue', 'N/A') for item in itens}
packet_loss = zapi.item.get(hostids=host['hostid'], filter={"key_": "net.ping.loss"}, output="extend")
metricas["net.ping.loss"] = packet_loss[0]['lastvalue'] if packet_loss else 'N/A'
hosts_info.append({
"host_name": host['name'],
"metrics": metricas
})
resultado.append({
"group_id": grupo['groupid'],
"group_name": grupo['name'],
"hosts": hosts_info
})
return resultado, 200
except Exception as e:
return {"error": "Erro ao buscar dados do Zabbix", "details": str(e)}, 500
@integra.route('/zabbix/hosts', methods=['GET'])
@token_required
def hosts_e_metricas(_):
dados, status_code = obter_dados_zabbix()
return jsonify(dados), status_code

44
app/routes/newuser.py Normal file
View File

@ -0,0 +1,44 @@
import logging
from flask import Blueprint, jsonify, request
from .auth import token_required
from flask_mysqldb import MySQL
newuser = Blueprint('newuser', __name__)
mysql = MySQL()
# Configuração de logging
logging.basicConfig(level=logging.DEBUG) # Log no nível de debug
@newuser.route('/inserir', methods=['POST'])
@token_required
def inserir_dados(get): # Recebe current_user do decorador
data = request.get_json()
nome_completo = data.get('nome_completo')
usuario_ad = data.get('usuario_ad')
empresa = data.get('empresa')
dominio_empresa = data.get('dominio_empresa')
if not nome_completo or not usuario_ad or not empresa or not dominio_empresa:
return jsonify({'erro': 'Todos os campos são obrigatórios'}), 400
conn = mysql.connection
cursor = conn.cursor()
try:
query = """
INSERT INTO usuarios (nome, usuario, empresa, dominio)
VALUES (%s, %s, %s, %s)
"""
cursor.execute(query, (nome_completo, usuario_ad, empresa, dominio_empresa))
conn.commit()
return jsonify({'message': 'Dados inseridos com sucesso!'}), 200
except Exception as err:
logging.error(f"Erro ao inserir dados: {str(err)}", exc_info=True) # Logando erro com traceback
return jsonify({'erro': f'Erro ao inserir dados: {str(err)}'}), 500
finally:
cursor.close()

48
app/routes/newzabbix.py Normal file
View File

@ -0,0 +1,48 @@
from pyzabbix import ZabbixAPI
# Connect to the Zabbix server
zapi = ZabbixAPI("https://mimir.itguys.com.br/zabbix/api_jsonrpc.php")
# Login to the Zabbix API
zapi.login(token="10925e9e452cade5270f4d930feb3b5e1aa2cc9b366c1c5b4d72996212b12c93")
# Retrieve a list of host groups (not hosts themselves)
groups = zapi.hostgroup.get(output="extend")
# Print group information and metrics
for group in groups:
print(f"Group ID: {group['groupid']}, Group Name: {group['name']}")
# Retrieve hosts in this group
hosts = zapi.host.get(groupids=group['groupid'], output="extend")
for host in hosts:
print(f" Host Name: {host['name']}")
# Retrieve items (metrics) for each host
items = zapi.item.get(hostids=host['hostid'], output="extend",
filter={"key_": ["system.uptime", "net.if.in", "net.if.out", "vm.memory.size", "vfs.fs.size"]})
# Print metrics for each host
for item in items:
# Check which metric it corresponds to and print it
if item['key_'] == "system.uptime":
print(f" Uptime: {item['lastvalue']} seconds")
elif item['key_'] == "net.if.in":
print(f" Network In: {item['lastvalue']} bytes")
elif item['key_'] == "net.if.out":
print(f" Network Out: {item['lastvalue']} bytes")
elif item['key_'] == "vm.memory.size":
print(f" Memory Usage: {item['lastvalue']} bytes")
elif item['key_'] == "vfs.fs.size":
print(f" Disk Usage: {item['lastvalue']} bytes")
# Retrieve the network packet loss (example metric)
# This can vary depending on your Zabbix configuration for ping or similar metrics
network_packet_loss = zapi.item.get(hostids=host['hostid'],
filter={"key_": "net.ping.loss"}, output="extend")
for loss in network_packet_loss:
print(f" Packet Loss: {loss['lastvalue']} %")
# Logout from the Zabbix API
zapi.user.logout()

55
app/routes/servicos.py Normal file
View File

@ -0,0 +1,55 @@
from flask import Blueprint, jsonify
from flask_mysqldb import MySQL
from .auth import token_required
servicos = Blueprint('servicos', __name__)
mysql = MySQL() # Instância do MySQL será configurada no app principal
@servicos.route('/servicos', methods=['GET'])
@token_required
def listar_servicos(data):
try:
domain = data.get('domain', '') # Obtém o domínio do usuário do token
if not domain:
return jsonify({"status": "error", "message": "Usuário não autenticado!"}), 401
# Conecta ao banco de dados e consulta os serviços
cur = mysql.connection.cursor()
query = """
SELECT `servico1`, `servico2`, `servico3`, `servico4`, `servico5`,
`servico6`, `servico9`, `servico12`
FROM `servicos` WHERE `dominio` = %s
"""
cur.execute(query, (domain,))
results = cur.fetchall()
cur.close()
# Verificando se resultados foram retornados
if results:
# Quando a consulta retorna uma tupla com dicionário, acessamos o primeiro item da tupla
row = results[0] # A primeira linha é um dicionário
servicos_prestados = {
"servico1": row.get('servico1'),
"servico2": row.get('servico2'),
"servico3": row.get('servico3'),
"servico4": row.get('servico4'),
"servico5": row.get('servico5'),
"servico6": row.get('servico6'),
"servico9": row.get('servico9'),
"servico12": row.get('servico12'),
}
return jsonify(servicos_prestados), 200
else:
return jsonify({"erro": "Nenhum serviço encontrado"}), 404
except Exception as e:
print(f"Erro interno: {e}") # Print detalhado do erro
return jsonify({"status": "error", "message": "Erro interno"}), 500

88
app/routes/upload_img.py Normal file
View File

@ -0,0 +1,88 @@
from flask_mysqldb import MySQL
from flask import Flask, Blueprint, jsonify, request
from .auth import token_required
import os
import traceback
import MySQLdb
imagem = Blueprint('imagem', __name__)
mysql = MySQL()
CAMINHO_PERFIL = "/var/www/Backend/itguys/ambiente_python/repositorio_img/perfil/"
CAMINHO_FUNDOS = "/var/www/Backend/itguys/ambiente_python/repositorio_img/fundos/"
def salvar_imagem(arquivo, tipo_imagem, nome_usuario):
"""Salva a imagem no diretório correspondente e retorna o caminho relativo"""
nome_arquivo = f"{nome_usuario}.jpg"
if tipo_imagem == "perfil":
caminho_diretorio = CAMINHO_PERFIL
caminho_relativo = f"perfil/{nome_arquivo}"
else:
caminho_diretorio = CAMINHO_FUNDOS
caminho_relativo = f"fundos/{nome_arquivo}"
caminho_completo = os.path.join(caminho_diretorio, nome_arquivo)
# Garante que o diretório existe
os.makedirs(caminho_diretorio, exist_ok=True)
# Salva a imagem
arquivo.save(caminho_completo)
return caminho_relativo # Retorna o caminho relativo para o banco de dados
def get_db_connection():
"""Verifica e retorna uma conexão válida com o banco de dados"""
try:
conn = mysql.connection
conn.ping() # Verifica se a conexão está ativa
return conn
except MySQLdb.OperationalError:
return mysql.connection # Tenta criar uma nova conexão
@imagem.route('/imagem', methods=['POST'])
@token_required
def receber_imagem(data):
try:
nome_usuario = data.get('user', '') # Separa o usuário do dominío
if not nome_usuario:
return jsonify({"status": "error", "message": "Usuário não autenticado!"}), 405
nome_usuario = nome_usuario.split('@')[0]
imagem_perfil = request.files.get('perfil')
imagem_foto_fundo = request.files.get('foto_fundo')
# Verifica se as imagens foram enviadas corretamente
if not imagem_perfil or not imagem_foto_fundo:
return jsonify({"status": "error", "message": "Imagens não enviadas corretamente!"}), 400
# Salva as imagens e obtém os caminhos relativos
caminho_perfil = salvar_imagem(imagem_perfil, "perfil", nome_usuario)
caminho_foto_fundo = salvar_imagem(imagem_foto_fundo, "fundo", nome_usuario)
# Conecta-se ao banco e executa a query de atualização
conn = get_db_connection()
cursor = conn.cursor()
query = """
UPDATE usuarios
SET img_perfil = %s, img_fundo = %s
WHERE usuario = %s
"""
valores = (caminho_perfil, caminho_foto_fundo, nome_usuario)
cursor.execute(query, valores)
conn.commit()
cursor.close()
return jsonify({"status": "success", "message": "Imagens enviadas e salvas com sucesso!"}), 200
except MySQLdb.OperationalError as e:
return jsonify({"status": "error", "message": f"Erro de conexão com o banco de dados: {str(e)}"}), 500
except Exception as e:
traceback.print_exc()
return jsonify({"status": "error", "message": str(e)}), 500

View File

@ -1,9 +1,12 @@
import requests import requests
from dotenv import load_dotenv
base_url = "http://zammad.itguys.com.br/api/v1" load_dotenv()
zammad_token = "kT0IXO8aVhPoTLcMRNL290rqd9jbRhhM0zf8MgBo3n00NLChToSU6rOGnMgWA0M2"
def listar_tickets(domain): base_url = "https://zammad.itguys.com.br/api/v1"
zammad_token = "QiFbQ7txT0BS_3N8GrwOzAS6f7ziVTa1VqcGGpaPFscvdcfnBVjgq699fFj6NpQW" #Token expira em 2065
def listar_tickets(domain, limit=500, offset=0):
try: try:
headers = { headers = {
"Authorization": f"Token token={zammad_token}", "Authorization": f"Token token={zammad_token}",

28
keyinter.pem Normal file
View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCXx+9g4l6QwnUE
f2b3mVA73MsQbXnc9m6hIGAS8Innba0mUA+nWij5KALUsJJEtoM7GGUlsijQEgLn
+6V7pCYAy1qgL6q357xDNPw8qbshf9LOmPOJXsc0cqUSI0J4YLTjuJhM5a9zzje5
RWJwwFl9Ileh3MT1FggLihNmcHzeC+VpWTvFXI/gC6KaDT0Xh1lNCN4jTpNEGCI8
0kOfT6KUpZFRfYcazTCcPYlfvAY8H6aRXTPlGy/QXUPsiwhrdN0yzIF3PFfSFrP9
tIH9HlnExMdndvNig9Z3lxIp6di7UXIVMod5sWEgXLZXPqRtqRU6CtZkMXHKDx3O
5OcpTN1bAgMBAAECggEAC9e4SEVxXnclvTuZk6EdPwZ7u6TnGMQLnrvRczjccbe/
hllB12tz/fjOu7ypNP5On/pHzhioEZAONP6QC2Uj5/T19cCyX9YPfOjx82PE65i3
IJKTkfjYrzFwyskAgzb8djYtf/Z96ZnCBE0zIJwJf3eCAemhXoQhDZFw8RG+1G5X
YtOoItBE5oIAXuUe3pYTaMY/1XnGe/vynFKeIcU9O2v6E3au8oueevqppmhfHkiM
a6gtNhjU3wpii3ZJk/L4Cpka752CjbXrZCaU1qMXB4hNkSuOi1Hq9clU91Fz4PXw
MHzeAZInlH3J29uxvDlGoMwTvpFIL2iRnrVzr40AfQKBgQC6+q31kAi818ciXxvh
ZxyEJEwQw/q5x/pTZQ2VRJB3kBpt7Lq570IZfDpaOsPg2wB/4SbE8XHpX7FzJAMd
BDCAzkBl8+fREbfL57/KKxV2EoHRfazSx23w8f5N5R+/OcXErgOAGUzcF2T53yXU
TXDpzgjTOEU/4p+h7wqceSenNwKBgQDPzxB0Xk8oYHWejIWVRuLV0US+kTxFiLX4
rrRppdk52oEzZFKJ0rosf00fHtxIyqW2NdPQlkphmyMjRUw3fPedK/FvNU8PnTo6
3MJ61QRgGSAi6/YMIs9K/Y83iFRKTBynZi36UCOUZbEncpZXuiOmplJWWE17FmHj
5IFItd5E/QKBgQCVD/oVVcGRg1iO71HTzZcvRZyalRLSfznyuBIvGN0vZGOdlOd8
CeEhXidK/aRhI1bvm/iDc5UDnzVhfKk6vbdJSKSQYvVBeKWVWmlM7DIM0k5KS622
0CS2vMWnJe28Tnt7A9toiUL8B26Jwbtv2FkXHBlvAmI6vxnSSDambfQN2wKBgQCm
IYqtDUxJIjxFwV91xJLJjyBfHSrLCA06PyjaIQ11c9rAZB6cMkxGEItuKrS+uMsb
zRKF+fCC8Yx4wQi6f3xROXUti7el6vNHZX9QxYVW8h8/69XrQ9Tmxai+I44HS6vI
pCZzq6eWFmo2+CN7BMNFkkfW4YcntPATSXWV1FdaXQKBgQC3mKzwS/3GZ4NOarCL
ISXGef+QZLPYj4eV08ccmRYXjlBR6rA2BNn9vPayB1E/IqG91Rj2tENLiE/NjVkG
ZuAss8FdQS19oiPRPEA+u11+pNy0RfJ9uxjrP9l//x8lA0cw/Pv6S/m2c+1DSjVd
UD2LwbNvaS6W4Vhy53LNGpbwmQ==
-----END PRIVATE KEY-----

28
privkeyinter.pem Normal file
View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDLXKbJUo6/xfnj
1f6Pt/wKw4Ko4tS0WiK+DSfzXBuEStHtXvcB5PPbnMJ5KNGQiPcFq5rkcwlERg8F
Z/+hjhuyn1as4fMxquKTBH7FpYHMRbuURSXtp9aZGMf6oMc1lzWF3aVQEgGPcAi4
Pbp9ddFb4vhu/INe+At4WiQvWK0mD+TfX2XFdUcl1cNUQCz0VfeuBGpnjKApIqd3
2ed2wF7U7bYBic2p9TA4Fw+VYArng12AbV5f9BQWuUUhjRSM7rYFs/R2bOHhB3y0
5EP72jwqwYnXVZMKGOomq4Vhrdj0VmUjxC2r3iui+tH2HteHCNzNMrcoTOn+ag1/
lHfTZK41AgMBAAECggEAJ80wtI70suqB09qGeeT5zraAvGK23DyW96j2BH6mwQ/u
wd1YDVYc90LZWiLHz1jLNiAlzugH7IWku3tlEB7S43Ulnu0TLsmiEkGrOS5BNvR/
989H0tmKWgj8XNx6WM4JMvPUPtVjWkpEXqDwPs1gJjKISpqf8KauAgZsdhrOOrhA
w+2qmOd/5w7oZCNu9sm53XoR6pSifdpRl+AjY+XRK+/hfyD3DqLJoZcW5al2ZHsh
iUWgfDDexFXVEeSc9OSyh5vTVXweXv8WVbpxAcD3l7Bsi7hltPW4bxyUcXjVfNy4
rjITSASeVOgI4Kwguwl4WuTd4iMHgopPsKxZqP+1QQKBgQDs5ka//ie79V0I+wDY
Y5vLSRRb9rLg0MDQxNUs9Gsg/+cYiaJrBEh1V+RTKWVEfxHS/hcUvMPgmW73EHRb
vVp652bwcGd3RVY0cOoID6267lqoWim8h0hv5yF82tcRVr5TJO/6DUlpXKgDiDyi
Zqe1Sf/j3mCE0opnByQrX+2MdQKBgQDbwiR6MryH1xZR0O+OFKmnpcxoda3xSoZi
JNxlw/d3U69iPKnV0w7YN4a5ytG2+fLvb2X8FUrvpGBn2TCTOCMvCFHWN9FrAUqA
HhTGHq3HGhA1DnGby+sE6Wn1kLfBYTS/PCusnqXgSVb/NpBqV4uSprweLVwfr2mN
bt9zHkViwQKBgQDbHIIDwkduCZtrWv2FJ1xJweYaySrZ1TsB3YxucANGGmrcvzCC
WwvJvOlqIbeQixcpV+pxO8bQThncWlPFJnYxhyYm7VBFeNQq3OUZX6cIZr1jSUGh
Jl9RYS4QFTkmyFxw+pEbbn6f/RtJaRDsBJbJjxAm6t/K+hEZCfniRG+qoQKBgEyb
axfmI+6+vhsbWMcQ0OuOUql/jHl2303LR8F6BQRl+denChVuE9iv0pll6KF+lH9/
N/AehBbyGGFbRyGrCijVH6IrpydENfJfiiJeg3nKzieQt232MiFuNO/T2Rrihf68
PQVZ8L01E8y3+rP3fMJMuXtTmK+6+HLDWcXJoaqBAoGAdHcfcm1S1NNpizSlpAvv
WGmCBxSa4qz5/22RnuL0tSnOd59Uiwp0u6SKSSc+fhw7oMpWQYq8QnsAXjsit0P4
GRmb5Ox/fHR0oF6IclmWmZin6c5ZeIDYDuGBig1/c6doG1j6WkHJO7xVQ04t7CcA
jk4uwg6pRoaTCArAU3+1Pzk=
-----END PRIVATE KEY-----

28
python/keyinter.pem Normal file
View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCXx+9g4l6QwnUE
f2b3mVA73MsQbXnc9m6hIGAS8Innba0mUA+nWij5KALUsJJEtoM7GGUlsijQEgLn
+6V7pCYAy1qgL6q357xDNPw8qbshf9LOmPOJXsc0cqUSI0J4YLTjuJhM5a9zzje5
RWJwwFl9Ileh3MT1FggLihNmcHzeC+VpWTvFXI/gC6KaDT0Xh1lNCN4jTpNEGCI8
0kOfT6KUpZFRfYcazTCcPYlfvAY8H6aRXTPlGy/QXUPsiwhrdN0yzIF3PFfSFrP9
tIH9HlnExMdndvNig9Z3lxIp6di7UXIVMod5sWEgXLZXPqRtqRU6CtZkMXHKDx3O
5OcpTN1bAgMBAAECggEAC9e4SEVxXnclvTuZk6EdPwZ7u6TnGMQLnrvRczjccbe/
hllB12tz/fjOu7ypNP5On/pHzhioEZAONP6QC2Uj5/T19cCyX9YPfOjx82PE65i3
IJKTkfjYrzFwyskAgzb8djYtf/Z96ZnCBE0zIJwJf3eCAemhXoQhDZFw8RG+1G5X
YtOoItBE5oIAXuUe3pYTaMY/1XnGe/vynFKeIcU9O2v6E3au8oueevqppmhfHkiM
a6gtNhjU3wpii3ZJk/L4Cpka752CjbXrZCaU1qMXB4hNkSuOi1Hq9clU91Fz4PXw
MHzeAZInlH3J29uxvDlGoMwTvpFIL2iRnrVzr40AfQKBgQC6+q31kAi818ciXxvh
ZxyEJEwQw/q5x/pTZQ2VRJB3kBpt7Lq570IZfDpaOsPg2wB/4SbE8XHpX7FzJAMd
BDCAzkBl8+fREbfL57/KKxV2EoHRfazSx23w8f5N5R+/OcXErgOAGUzcF2T53yXU
TXDpzgjTOEU/4p+h7wqceSenNwKBgQDPzxB0Xk8oYHWejIWVRuLV0US+kTxFiLX4
rrRppdk52oEzZFKJ0rosf00fHtxIyqW2NdPQlkphmyMjRUw3fPedK/FvNU8PnTo6
3MJ61QRgGSAi6/YMIs9K/Y83iFRKTBynZi36UCOUZbEncpZXuiOmplJWWE17FmHj
5IFItd5E/QKBgQCVD/oVVcGRg1iO71HTzZcvRZyalRLSfznyuBIvGN0vZGOdlOd8
CeEhXidK/aRhI1bvm/iDc5UDnzVhfKk6vbdJSKSQYvVBeKWVWmlM7DIM0k5KS622
0CS2vMWnJe28Tnt7A9toiUL8B26Jwbtv2FkXHBlvAmI6vxnSSDambfQN2wKBgQCm
IYqtDUxJIjxFwV91xJLJjyBfHSrLCA06PyjaIQ11c9rAZB6cMkxGEItuKrS+uMsb
zRKF+fCC8Yx4wQi6f3xROXUti7el6vNHZX9QxYVW8h8/69XrQ9Tmxai+I44HS6vI
pCZzq6eWFmo2+CN7BMNFkkfW4YcntPATSXWV1FdaXQKBgQC3mKzwS/3GZ4NOarCL
ISXGef+QZLPYj4eV08ccmRYXjlBR6rA2BNn9vPayB1E/IqG91Rj2tENLiE/NjVkG
ZuAss8FdQS19oiPRPEA+u11+pNy0RfJ9uxjrP9l//x8lA0cw/Pv6S/m2c+1DSjVd
UD2LwbNvaS6W4Vhy53LNGpbwmQ==
-----END PRIVATE KEY-----

28
python/privkeyinter.pem Normal file
View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDLXKbJUo6/xfnj
1f6Pt/wKw4Ko4tS0WiK+DSfzXBuEStHtXvcB5PPbnMJ5KNGQiPcFq5rkcwlERg8F
Z/+hjhuyn1as4fMxquKTBH7FpYHMRbuURSXtp9aZGMf6oMc1lzWF3aVQEgGPcAi4
Pbp9ddFb4vhu/INe+At4WiQvWK0mD+TfX2XFdUcl1cNUQCz0VfeuBGpnjKApIqd3
2ed2wF7U7bYBic2p9TA4Fw+VYArng12AbV5f9BQWuUUhjRSM7rYFs/R2bOHhB3y0
5EP72jwqwYnXVZMKGOomq4Vhrdj0VmUjxC2r3iui+tH2HteHCNzNMrcoTOn+ag1/
lHfTZK41AgMBAAECggEAJ80wtI70suqB09qGeeT5zraAvGK23DyW96j2BH6mwQ/u
wd1YDVYc90LZWiLHz1jLNiAlzugH7IWku3tlEB7S43Ulnu0TLsmiEkGrOS5BNvR/
989H0tmKWgj8XNx6WM4JMvPUPtVjWkpEXqDwPs1gJjKISpqf8KauAgZsdhrOOrhA
w+2qmOd/5w7oZCNu9sm53XoR6pSifdpRl+AjY+XRK+/hfyD3DqLJoZcW5al2ZHsh
iUWgfDDexFXVEeSc9OSyh5vTVXweXv8WVbpxAcD3l7Bsi7hltPW4bxyUcXjVfNy4
rjITSASeVOgI4Kwguwl4WuTd4iMHgopPsKxZqP+1QQKBgQDs5ka//ie79V0I+wDY
Y5vLSRRb9rLg0MDQxNUs9Gsg/+cYiaJrBEh1V+RTKWVEfxHS/hcUvMPgmW73EHRb
vVp652bwcGd3RVY0cOoID6267lqoWim8h0hv5yF82tcRVr5TJO/6DUlpXKgDiDyi
Zqe1Sf/j3mCE0opnByQrX+2MdQKBgQDbwiR6MryH1xZR0O+OFKmnpcxoda3xSoZi
JNxlw/d3U69iPKnV0w7YN4a5ytG2+fLvb2X8FUrvpGBn2TCTOCMvCFHWN9FrAUqA
HhTGHq3HGhA1DnGby+sE6Wn1kLfBYTS/PCusnqXgSVb/NpBqV4uSprweLVwfr2mN
bt9zHkViwQKBgQDbHIIDwkduCZtrWv2FJ1xJweYaySrZ1TsB3YxucANGGmrcvzCC
WwvJvOlqIbeQixcpV+pxO8bQThncWlPFJnYxhyYm7VBFeNQq3OUZX6cIZr1jSUGh
Jl9RYS4QFTkmyFxw+pEbbn6f/RtJaRDsBJbJjxAm6t/K+hEZCfniRG+qoQKBgEyb
axfmI+6+vhsbWMcQ0OuOUql/jHl2303LR8F6BQRl+denChVuE9iv0pll6KF+lH9/
N/AehBbyGGFbRyGrCijVH6IrpydENfJfiiJeg3nKzieQt232MiFuNO/T2Rrihf68
PQVZ8L01E8y3+rP3fMJMuXtTmK+6+HLDWcXJoaqBAoGAdHcfcm1S1NNpizSlpAvv
WGmCBxSa4qz5/22RnuL0tSnOd59Uiwp0u6SKSSc+fhw7oMpWQYq8QnsAXjsit0P4
GRmb5Ox/fHR0oF6IclmWmZin6c5ZeIDYDuGBig1/c6doG1j6WkHJO7xVQ04t7CcA
jk4uwg6pRoaTCArAU3+1Pzk=
-----END PRIVATE KEY-----

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 198 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 56 KiB

1
tokeninter.txt Normal file
View File

@ -0,0 +1 @@
49a8c9c3-aac6-44fe-bc8d-f295677b96a6