Binbox es un servicio que permite acortar links y crear pastes, ambas cosas generan dinero para el usuario final. Desde hace mucho he querido usar su API pero no entendía nada de REST, ni de las peticiones POST, GET, etcétera.
Así que lo olvidé por unos meses o años, y ayer recordé que nunca pude hacerlo. Lo intenté de nuevo y ahora sí pude hacerlo. Además, lo implementé en Python, ya que hacerlo en Javascript es muy fácil (ellos proveen la librería y las capas de abstracción superiores).
Lo que me pareció más difícil es que (y no sé la razón) los datos se deben encriptar usando la librería sjcl. Eso es fácil si estás en javascript, ¿pero y en Python? así que me puse a investigar y al final encontré una que tenía un error, el cual solucioné aquí.
Una vez teniendo la librería, tuve que decodificar los datos. Ya que la librería los devolvía con una b al inicio. Es decir, eran bytes. Por lo que regresaba algo como b’hola mundo’ en lugar de un simple ‘hola mundo’. Para solucionarlo, decodifiqué cada cosa codificada: el vector, el texto cifrado y la sal
texto_encriptado = SJCL().encrypt(texto, sal) texto_encriptado['ct'] = texto_encriptado['ct'].decode('utf-8') texto_encriptado['iv'] = texto_encriptado['iv'].decode('utf-8') texto_encriptado['salt'] = texto_encriptado['salt'].decode('utf-8')
Una vez hecho eso, me enfrenté a que el objeto JSON no debería tener espacios en blanco, y debía usar comillas dobles ” en lugar de comillas simples ‘. Para ello modifiqué los separadores y los mandé como argumento a json.dumps, quedando así:
texto_encriptado_como_json = json.dumps(texto_encriptado, separators=(',', ':'))
Ahora, para terminar, tenía que codificar los datos en base64:
texto_como_json_codificado = b64encode(texto_encriptado_como_json.encode('utf-8'))
Debido a que base64 devuelve un objeto codificado, tuve que, de nuevo, decodificarlo para remover la b al inicio:
texto_base64_decodificado = texto_como_json_codificado.decode('utf-8')
Y ahora sí pude hacer la petición:
datos = { 'data': texto_base64_decodificado, 'title': titulo, } peticion = requests.post(self.url_api, data = datos)
Para crear links no encontré ningún problema, ya que los datos se mandan en texto plano.
Finalmente para ahorrar dolores de cabeza a alguien que quiera usar la api desde Python, hice una pequeña clase que puede crear pastes y links acortados.
Es fácil de usar. Simplemente creas una instancia con tu nombre de usuario. Luego, puedes llamar a crear_paste o acortar_link. Ambos métodos devolverán el link del paste junto con la clave de acceso y el link acortado respectivamente.
"""
API de Binbox escrita en Python
Requisitos:
* requests
* sjcl
Para instalar requests:
pip install requests
Para instalar sjcl (Stanford Javascript Crypto Library) ir a https://github.com/berlincode/sjcl/blob/master/sjcl/sjcl.py
descargar el fichero en la carpeta en donde esté este archivo, y en la línea 170 cambiar:
ciphertext = cipher.encrypt(plaintext)
Por:
ciphertext = cipher.encrypt(plaintext.encode("utf-8"))
"""
import requests
import json
import string
import random
from sjcl import SJCL
from base64 import b64encode
class BB:
def __init__(self, nombre_de_usuario):
self.url_api = "http://{}.binbox.io/submit.json".format(nombre_de_usuario)
def obtener_link_o_lanzar_error(self, peticion, sal = None):
respuesta_decodificada = json.loads(peticion.text)
if respuesta_decodificada['ok'] is True:
link = "https://binbox.io/{}".format(respuesta_decodificada['id'])
if sal is not None:
link += "#{}".format(sal)
return link
else:
raise ValueError("Link o usuario inválido. Mensaje original: {}".format(peticion.text))
def cadena_aleatoria(self, longitud = 8):
"""
Devuelve una cadena aleatoria de 8 caracteres para ser utilizada como sal.
Nota: esto no es seguro criptográficamente, pero sí aleatoriamente
Nota 2: no intentes cambiar la longitud
"""
return ''.join(random.choices(string.ascii_uppercase + string.digits, k=longitud))
def acortar_link(self, link, titulo = None):
"""
Devuelve un link acortado
Por ejemplo, algo como binbox.io/asdf
"""
datos = {
'url': link,
'title': titulo
}
peticion = requests.post(self.url_api, data = datos)
return self.obtener_link_o_lanzar_error(peticion)
def crear_paste(self, titulo, texto, sal = None):
"""
Devuelve el link del paste, con su respectivo hash e id.
Por ejemplo, algo como http://binbox.io/asdf#asdw
Para el título puedes incluir links como https://ejemplo.com pero
no HTML como <a href="https://ejemplo.com">Link</a>
Y para saltos de línea utiliza \n, no intentes utilizar <br>
"""
if sal is None:
sal = self.cadena_aleatoria()
texto_encriptado = SJCL().encrypt(texto, sal)
texto_encriptado['ct'] = texto_encriptado['ct'].decode('utf-8')
texto_encriptado['iv'] = texto_encriptado['iv'].decode('utf-8')
texto_encriptado['salt'] = texto_encriptado['salt'].decode('utf-8')
texto_encriptado_como_json = json.dumps(texto_encriptado, separators=(',', ':'))
texto_como_json_codificado = b64encode(texto_encriptado_como_json.encode('utf-8'))
texto_base64_decodificado = texto_como_json_codificado.decode('utf-8')
datos = {
'data': texto_base64_decodificado,
'title': titulo,
}
peticion = requests.post(self.url_api, data = datos)
return self.obtener_link_o_lanzar_error(peticion, sal)
""" Ejemplos """
binbox = BB("parzibyte")
link_paste = binbox.crear_paste("El título del paste", "El contenido que puede\nllevar saltos de\nlínea y también https://parzibyte.me/ enlaces")
link_acortado = binbox.acortar_link("https://parzibyte.me/", "Este es el título del link")
print(link_paste)
print(link_acortado)
Para probar el código, podemos usar esto:
""" Ejemplos """ binbox = BB("parzibyte") link_paste = binbox.crear_paste("Paste desde parzibyte.me!", "Hola. Este es un paste que fue creado en parzibyte.me/blog :)") link_acortado = binbox.acortar_link("https://parzibyte.me/", "Link acortado desde parzibyte.me") print("El link del paste: {}".format(link_paste)) print("El link acortado: {}".format(link_acortado))
Aquí la captura:
Con el link acortado pasa lo mismo:
Y así fue como pude implementar la api de binbox.io en Python, sin muchas complicaciones más que las que ofrece la librería sjcl.
Hoy te voy a presentar un creador de credenciales que acabo de programar y que…
Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…
En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…
En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…
Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…
En este artículo te voy a enseñar cómo usar un "top level await" esperando a…
Esta web usa cookies.