apis

Api de binbox.io en Python

Introducción

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).

Creando pastes

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)

Creando links

Para crear links no encontré ningún problema, ya que los datos se mandan en texto plano.

Código

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)

Implementación

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:

Si visito el link del paste, efectivamente sale el texto que mandé desde Python:

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.

Estoy aquí para ayudarte 🤝💻


Estoy aquí para ayudarte en todo lo que necesites. Si requieres alguna modificación en lo presentado en este post, deseas asistencia con tu tarea, proyecto o precisas desarrollar un software a medida, no dudes en contactarme. Estoy comprometido a brindarte el apoyo necesario para que logres tus objetivos. Mi correo es parzibyte(arroba)gmail.com, estoy como@parzibyte en Telegram o en mi página de contacto

No te pierdas ninguno de mis posts 🚀🔔

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.
parzibyte

Programador freelancer listo para trabajar contigo. Aplicaciones web, móviles y de escritorio. PHP, Java, Go, Python, JavaScript, Kotlin y más :) https://parzibyte.me/blog/software-creado-por-parzibyte/

Entradas recientes

Creador de credenciales web – Aplicación gratuita

Hoy te voy a presentar un creador de credenciales que acabo de programar y que…

1 semana hace

Desplegar PWA creada con Vue 3, Vite y SQLite3 en Apache

Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…

2 semanas hace

Arquitectura para wasm con Go, Vue 3, Pinia y Vite

En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…

2 semanas hace

Vue 3 y Vite: crear PWA (Progressive Web App)

En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…

2 semanas hace

Errores de Comlink y algunas soluciones

Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…

2 semanas hace

Esperar promesa para inicializar Store de Pinia con Vue 3

En este artículo te voy a enseñar cómo usar un "top level await" esperando a…

2 semanas hace

Esta web usa cookies.