jueves, 9 de septiembre de 2021

OverTheWire

 

Over the wire es un plataforma de juegos de guerra ayudando a la comunidad con conceptos de seguridad a traves de juegos, la dinamica es a traves de niveles y categorias.

 

Bandit 

Hoy quiero compartirles no tanto como solucionar estos retos, sino como alcansar los comandos indicados para facilitar su comprension. A medida que vaya avanzando en los niveles se ira profundizando mas los comandos.


Reto 0:

El objetivo de este nivel es que te conectes al juego usando SSH. El host al que debes conectarte es bandit.labs.overthewire.org, en el puerto 2220. El nombre de usuario es bandit0 y la contraseña es bandit0. Una vez conectado, ve a la página del Nivel 1 para saber cómo superar el Nivel 1.


ssh:

Para ingresar a traves de ssh necesitas los siguientes parametros

shh {usuario}@{hostname} -p{puerto} ssh bandit0@bandit.labs.overthewire.org -p 2220


Reto->1:

La contraseña para el siguiente nivel se almacena en un archivo llamado readme ubicado en el directorio home. Usa esta contraseña para entrar en bandit1 usando SSH. Siempre que encuentres una contraseña para un nivel, usa SSH (en el puerto 2220) para entrar en ese nivel y continuar el juego.

ls

 Es un comando que se utiliza para enumerar directorios y archivos

ls {ruta}
ls		//directorio actual
ls /		//directirio raiz
ls ..		//directorio padre
ls ../..	//directorio dos niveles arriba

  

cat

 Es un comando muy versatil que permite fusionar,crear y leer archivos

cat {ruta} {archivo}
cat file	//lee en archivo file

  

Reto->2:

La contraseña para el siguiente nivel se almacena en un archivo llamado - ubicado en el directorio de inicio.

cat

 Utilizando en un archivo con nombre "-" accede a la funcion STDIN (standar input) que permite leer por consola la entrada de texto. Para acceder al contenido hay que anteponerle al archivo

cat ./{file}

  

Reto->3:

La contraseña para el siguiente nivel se almacena en un archivo llamado espacios en este nombre de archivo situado en el directorio de inicio.

cat

 Utilizando en un archivo con nombre espacios en el nombre para acceder hay que colocar el nombre dentro de comillas

cat "a b"

  

Reto->4:

La contraseña para el siguiente nivel se almacena en un archivo oculto en el directorio inhere.

ls

 Un archivo que se le antepone un punto al comienzo del nombre es considerado archivo oculto, para listarlo hay que pasarle -a como parametro

ls -a

  

Reto->5:

La contraseña para el siguiente nivel se almacena en el único archivo legible por humanos en el directorio inhere. Consejo: si su terminal está desordenada, pruebe el comando "reset".

file

 Este comando brinda informacion sobre el tipo de ficheros, teniendo en cuenta que todos comienzan con -

file {opcion} {archivo/directorio}
file ./*

  

Reto->6:

La contraseña para el siguiente nivel se almacena en un archivo en algún lugar del directorio inhere y tiene todas las siguientes propiedades: legible para el ser humano, 1033 bytes de tamaño, no ejecutable.

find

 Es una herramienta estremadamente potente y precisa al buscar ficheros y directorios de manera recursiva

find {ruta} {opcion}
find . -size 1033c		//busca en la carpeta actual un archivo que pese exactamente 1033 bytes
find . -exacutable		//Busca un archivo que sea ejecutable
find . ! -exacutable -size 1033c //Busca un archivo no ejecutable y un peso exacto

  

Reto->7:

La contraseña para el siguiente nivel se almacena en algún lugar del servidor y tiene todas las siguientes propiedades: propiedad del usuario bandit7, propiedad del grupo bandit6, 33 bytes de tamaño.

find

 Similar al problema anterior pero ahora busca en sistema

find / -size 33c	//busca que pese 33 bytes
find / -user bandit7	//Busca que pertenesca a un usuario
find / -group bandit6	//Busca que pertenesca a un grupo

  

Reto->8:

La contraseña para el siguiente nivel se almacena en el archivo data.txt junto a la palabra millonésima.

grep

 Es una herramienta del sistema que permite encontrar patrones tanto en archivos como directorios

grep '{patron a buscar}' {archivo(s)}
grep -i patron} {file}		//imprime las coincidencias ignorando las mayus minus
grep -n {patron} {file}		//enumera e imprime el resultado de las coincidencias

  

Reto->9:

La contraseña para el siguiente nivel se almacena en el archivo data.txt y es la única línea de texto que aparece una sola vez.

sort y uniq

 Sort es ideal para ordenar, ordenar por fechas, por inverso y uniq mostrar resultados de un archivo al ser unicos, considerando como repetido en lineas subyacentes por lo tanto se suele trabajar con ambos comandos

sort {file} | uniq	//ordena y muestra los resultados unicos
sort {file} | uniq -i	//Ordena ignora si son mayus o minus
sort {file} | uniq -c 	//Muestra el numero de ocurrencias 
sort {file} | uniq -u 	//Muestra los resultados unicos 

  

Reto->10:

La contraseña para el siguiente nivel se almacena en el archivo data.txt en una de las pocas cadenas legibles para el ser humano, precedida por varios caracteres "=".

strings

 Este comando es especialmente util cuando se quiere extraer cadenas de un archivo binario, ya que la mayoria de programas para trabajar con archivos de texto suelen fallar porque se encuentran con caracteres no imprimibles. strings extrae cadenas o fragmentos de texto imprimibles

strings {file} 
strings -n {file}	//extrae las cadenas con un numero minimo de caracteres imprimibles
strings {file} | grep == //extrae las cadenas que cuenten con ese patron

  

Reto->11:

La contraseña para el siguiente nivel se almacena en el archivo data.txt, que contiene datos codificados en base64.

base64

 Este comando permite codificar y decodificar cadenas en base64 desde la consola

base64 {file} //codifica el contenido de un archivo a base64
base64 -d {file}	//convierte el contenido del archivo en base64 a texto legible
echo "Welcome to overthewire - bytefate" | base64 //codifica directamente la linea de texto
echo "V2VsY29tZSB0byBvdmVydGhld2lyZSAtIGJ5dGVmYXRl" | base64 -d //codifica directamente la linea de texto

  

Reto->12:

La contraseña para el siguiente nivel se almacena en el archivo data.txt, donde todas las letras minúsculas (a-z) y mayúsculas (A-Z) han sido rotadas en 13 posiciones.

tr

 El comando tr significa translate, trabajando directamente con stdio, np permitiendo trabajar directamente con el archivo, puede manipular, transformar eliminar, cambiar letras, limitadores entre otros. tr trabaja con un conjunto de opciones, que por defecto se puede dejar en blanco, el set1 son los caracteres que se buscaran en el texto, el set2 son el conjunto de caracteres que se usara para modificarlos En este caso particular necesita mover 13 posiciones todas las letras siendo a convertida en m, b en n,...

tr {option} {set1} {set2} 
tr A-Za-z N-ZA-Nn-za-m //Rota la posicion de las letras 13 posiciones
tr -c 'as' 'dd'	//Remplazara todo lo demas que no coincida con set1 con set2

  

Reto->10:

La contraseña para el siguiente nivel se almacena en el archivo data.txt en una de las pocas cadenas legibles para el ser humano, precedida por varios caracteres "=".

strings

 Este comando es especialmente util cuando se queire extraer cadenas de un archivo binario, ya que la mayoria de programas para trabajar con archivos de texto suelen fallar porque se encuentran con caracteres no imprimibles. strings extrae cadenas o fragmentos de texto imprimibles

strings {file} 
strings -n {file}	//extrae las cadenas con un numero minimo de caracteres imprimibles
strings {file} | grep == //extrae las cadenas que cuenten con ese patron

  

Reto->10:

La contraseña para el siguiente nivel se almacena en el archivo data.txt en una de las pocas cadenas legibles para el ser humano, precedida por varios caracteres "=".

strings

 Este comando es especialmente util cuando se queire extraer cadenas de un archivo binario, ya que la mayoria de programas para trabajar con archivos de texto suelen fallar porque se encuentran con caracteres no imprimibles. strings extrae cadenas o fragmentos de texto imprimibles

strings {file} 
strings -n {file}	//extrae las cadenas con un numero minimo de caracteres imprimibles
strings {file} | grep == //extrae las cadenas que cuenten con ese patron

  

Reto->10:

La contraseña para el siguiente nivel se almacena en el archivo data.txt en una de las pocas cadenas legibles para el ser humano, precedida por varios caracteres "=".

strings

 Este comando es especialmente util cuando se queire extraer cadenas de un archivo binario, ya que la mayoria de programas para trabajar con archivos de texto suelen fallar porque se encuentran con caracteres no imprimibles. strings extrae cadenas o fragmentos de texto imprimibles

strings {file} 
strings -n {file}	//extrae las cadenas con un numero minimo de caracteres imprimibles
strings {file} | grep == //extrae las cadenas que cuenten con ese patron

  

Reto->10:

La contraseña para el siguiente nivel se almacena en el archivo data.txt en una de las pocas cadenas legibles para el ser humano, precedida por varios caracteres "=".

strings

 Este comando es especialmente util cuando se queire extraer cadenas de un archivo binario, ya que la mayoria de programas para trabajar con archivos de texto suelen fallar porque se encuentran con caracteres no imprimibles. strings extrae cadenas o fragmentos de texto imprimibles

strings {file} 
strings -n {file}	//extrae las cadenas con un numero minimo de caracteres imprimibles
strings {file} | grep == //extrae las cadenas que cuenten con ese patron

  

Reto->10:

La contraseña para el siguiente nivel se almacena en el archivo data.txt en una de las pocas cadenas legibles para el ser humano, precedida por varios caracteres "=".

strings

 Este comando es especialmente util cuando se queire extraer cadenas de un archivo binario, ya que la mayoria de programas para trabajar con archivos de texto suelen fallar porque se encuentran con caracteres no imprimibles. strings extrae cadenas o fragmentos de texto imprimibles

strings {file} 
strings -n {file}	//extrae las cadenas con un numero minimo de caracteres imprimibles
strings {file} | grep == //extrae las cadenas que cuenten con ese patron

  

Reto->10:

La contraseña para el siguiente nivel se almacena en el archivo data.txt en una de las pocas cadenas legibles para el ser humano, precedida por varios caracteres "=".

strings

 Este comando es especialmente util cuando se queire extraer cadenas de un archivo binario, ya que la mayoria de programas para trabajar con archivos de texto suelen fallar porque se encuentran con caracteres no imprimibles. strings extrae cadenas o fragmentos de texto imprimibles

strings {file} 
strings -n {file}	//extrae las cadenas con un numero minimo de caracteres imprimibles
strings {file} | grep == //extrae las cadenas que cuenten con ese patron

  

Reto->10:

La contraseña para el siguiente nivel se almacena en el archivo data.txt en una de las pocas cadenas legibles para el ser humano, precedida por varios caracteres "=".

strings

 Este comando es especialmente util cuando se queire extraer cadenas de un archivo binario, ya que la mayoria de programas para trabajar con archivos de texto suelen fallar porque se encuentran con caracteres no imprimibles. strings extrae cadenas o fragmentos de texto imprimibles

strings {file} 
strings -n {file}	//extrae las cadenas con un numero minimo de caracteres imprimibles
strings {file} | grep == //extrae las cadenas que cuenten con ese patron

  

martes, 17 de agosto de 2021

Introduccion a Arquitectura x86 y x64


CPU

Se encarga de procesar todas las instrucciones del dispositivo, que son interpretadas en lenguaje maquina (binarios), para facilitar el entendimiento de estas instrucciones es necesario traducirlo a un lenguaje mnemotécnico llamado Assembly (ASM).

 

Los assembler más populares son:

    NASM (Netwide Assembler).

    MASM (Microsoft Macro Assembler).

    GAS (GNU Assembler).

    FASM (Flat Assembler).

 Este post será muy interesante para entender cómo se compila programas.

 

Diferencias entre AT&T e Intel

A medida que se bajando de nivel, se va notando algunas cosas que no se necesitaba preocupar al momento de trabajar con lenguajes de alto nivel. Al trabajar con sistemas basados en Unix, tradicionalmente se tiene una sintaxis AT&T, en muchas herramientas se tiene la opción de obtener la sintaxis Intel. Ahora voy a nombrar algunas de las diferencias más significativas para identificar la sintaxis del ensamblador.

En algunas instrucciones donde se especifica el origen y el destino se invierten, mientras que para AT&T va primero el origen y luego el destino, en Intel es lo contrario primero el destino y luego en origen

AT&T

<instrucción> <origen><destino>

Intel

<instrucción> <destino><origen>

Un indicador de que se está trabajando con AT&T es que cada operando es precedido por un "%", mientras que Intel no lo utiliza.

 

Arquitectura 32

Endians:

Describe como es el orden de la secuencia de bytes se guardará en la memoria. Cuando se quiere representar un numero decimal con 2 bytes, por ejemplo, el 6, aquí entra el concepto del byte más significativo y el menos significativo. En este ejemplo el byte (0000) es el más significativo (MSB) y el byte (0110) menos significativo (LSB), y esto está dado porque si agregáramos un byte al primer byte (0001 0110 = 22) variaría más que si se lo agregáramos al segundo byte (0000 0111 = 7).  En Big Endian, el byte más significativo es el primero, en cambio en Little Endian el ultimo byte es el más significante.

Conocer la Endian es importante a la hora de interpretar los registros.

                                Binario                  Hex          Decimal

Big Endian           0101 0010            0x52           82

Little Endian       0101 0010            0x25            37

 

En procesadores modernos existe, registros de propósito general, registro de segmento, registros de banderas y un registro de puntero.


Registros GPR

Los registros GPR(General Purpose Register) almacenan direcciones de memoria o datos, que serán utilizados durante la ejecución del programa.

Abr Nombre Descripción
EAX Extended Accumulator
Register
Es responsable de manejar el resultado de
operaciones de llamada al sistema
EBX Extended Base
Register
Es usada para almacenar la dirección de
los datos en el segmento de registro DS
ECX Extended Counter
Register
Sirve como contador para strings y
operaciones cíclicas
EDX Extended Data
Register
Es usado para almacenar direcciones para
operaciones de entrada y salida
EBP Extended Base
Pointer
Apunta a la dirección de la base del Stack
EDI Extended Destination
Index
Es usado como el puntero de destino para
las operaciones de strings
ESI Extended Source
Index
Es usado como puntero de origen para las
operaciones de strings
ESP Extended Stack
Pointer
Apunta a la dirección de la parte superior
del Stack
EIP Extended Instruction
Pointer
Tiene 32 bits de ancho, apunta a la dirección
de la siguiente instrucción

 

 Estos registros tiene un tamaño específico que se pueden dividir en registros con tamaño mucho más pequeño, por ejemplo EAX tiene un tamaño de 32 bits, y a su vez puedo tener 2 registros AX de tamaño de 16 bits, un registro AX de 16 bits puede tener un 2 registros de 8 bits, llamados AH(high bit) y AL(low bit). En arquitecturas mas modernas como x64, se duplicó el espacio de memoria, por ejemplo un registro RAX es equivalente a 2 registros EAX.



Los registros EFLAGS tienen un tamaño de 32 bits y contiene varios diferentes flags que son usadas para varias operaciones, algunos de estos bits están reservados como lo son 1,3,5,15, 22 al 31. En arquitectura x64 son denominados RFLAGS.

Algunos EFLAGS:

Carry Flag (CF): Se encuentra en el bit 0 y este flag indica una condición de desbordamiento para operaciones aritmética de enteros sin signo.

Parity Flag (PF): Se encuentra en el bit 2 y se coloca si el bit más significativo contiene incluso un número de un solo bit.

Auxiliary Carry Flag (AF): Se encuentra en el bit 4 y es usado en operaciones matemáticas si la operación resultante es llevar y pedir prestado.

Zero Flag (ZF): Se encuentra en el bit 6,  tiene el valor de 1 y si es colocado 0 despejados. 

Sign Flag (SF): Se encuentra en el bit 7 y es usado para demarcar el signo de un entero.

Direccion Flag (DF): Se encuentra en el bit 10 y se usa para determinar la dirección de operaciones de string, si se pasa un 1, las instrucciones de string operan desde la dirección más alta a la más baja y si se pasa 0 viceversa.

Overflow Flag(OF): Se encuentra en el bit 11 y se establece si el resultado entero es un número positivo demasiado grande o pequeño para caber en el operando de destino o una condición de desbordamiento en una operación matemática.


lunes, 9 de agosto de 2021

CTF Crypto - I


 

Hace poco me encontre con unos cuantos retos de captura la bandera, estos estaban orientados a criptografía. Aunque no son los retos mas dificiles que hay fueron bastante interesantes para los que recien se enfrentan a este tipo de retos.


RETO 1: 


Este trataba de como trabaja los propiedades del la compuerta XOR.

El problema era el siguiente, te daban una serie de llaves que te ayudaran a encontrar la bandera la pista esta en los nombres de las llaves.

KEY1 = ...

KEY2^KEY1 = ...

KEY2^KEY3 = ...

FLAG^KEY2^KEY3^KEY1 = ...


La solucion esta en la pista y en las propiedades de la compuerta XOR, del siguente modo para obtener la segunda llave:

c =  a ^  b

b = a ^ c

KEY2 = KEY1  ^  KEY2^KEY1   

Asi se podra obtener la segunda llave xoreando las primeras 2 llaves. Del mismo modo se puede hallar la tercer llave y la bandera.

flag = k1  ^  k2  ^  k3  ^  f_k2_k3_k1

El truco es que como ya teniamos xoreado una de las llaves simplificaba la operacion y obtener la bandera.

flag = k1  ^  k2^k3  ^  f_k2_k3_k1
 

 

RETO 2: 

En este reto, te dan una larga cadena en hexadecimal que dentro de esta se halla la bandera y la unica pista que se dio fue que el formato de la bandera podria ayudar a solucionar el reto.

En realidad funciono bastante bien al xorear la misma cantidad de datos de la cadena encriptada con la longitud del formato, mostrando la clave con la que lo habian cifrado. Al intentar xorear toda la cadena con la llave que encontre, no funciono. 

flag = cadena ^ ( formatformat...)

Agregando una llave abierta ({) al formato, que es el siguiente caracter conocido, xorear toda la cadena, solo esta primer parte mostraba que habia funcionado. Asi que por fuerza bruta intente obtener el siguiente caracter, obteneniendo algunas opciones viables para ser la llave.

flag = cadena ^ ( format{format{...)

Al xorear el primer intento, note que tenia la longitud correcta de la llave y solo faltaba dar con el caracter correcto.

flag = cadena ^ ( format{cformat{c...)


RETO 3:

 En este reto dieron la cadena, la unica pista era que se habia xoreado con un solo byte. Asi que teniendo encunta que un byte tiene 128 valores diferentes, es factible obtener la bandera a travez de fuerza bruta, xoreando cada bite la cadena por el valor con el que se estaba probando.


NOTA: Algunos ctfs tienen prohibido publicar la solucion de los retos, por este motivo algunos aspectos fueron modificados para dar solo una vision ilustrativa del reto...



martes, 18 de mayo de 2021

Python y Message Broker - RabbitMQ I

INSTALACION:

RabbitMQ tiene soporte para varios sistemas operativos entre ellos Windows, Mac, Linux, BSD, UNIX, tambien se puede encontrar en repositorios Debian(apt) y RPM(Yum). Desde el lado de la nube, se puede encontrar varios proveedores especializados en SAAS, es muy compatible con kubernetes y ademas se puede encontrar una imagen en Dockerhub que en este caso voy a utlizar.


Lo primero sera descargar la imagen de RabbitMQ con el comando, eligiendo el plugin management que desplegara una interfaz que permite controlar y un monitorear lo relacionado a rabbitmq.

 docker pull rabbitmq:3-management

 

Para desplegar el contenedo uso el comando

 docker run -d --hostname bf-rabbit --name some-bf-rabbit -p 15672:15672 -p 5672:5672 rabbitmq:3-management

Lo que se ejecuto es lo siguiente 

run docker va a ejecutar una imagen 

-d la ejecucion sera en background

--hostname: le dara un hostname que sera importante a la hora de subirlo a un proveedor cloud

--name: sera el nombre que se le dara al contenedor

-p publicara un servicio, en este caso en el puerto 15672 estara corriendo la interfaz grafica y 5672 esta el servicio de cliente de rabbitmq.

Y para finalizar la imagen de rabbitmq y especifica que se requiere tambien el plugin management.


Bueno ya que el entorno esta corriendo, se puede ingresar a la interfaz a travez del navegador en el puerto 15672, en donde ingresar con usuario y contraseña que por defecto es guest/guest.


En este espacio, se puede hacer seguimiento de las colas, crear usuario,  muchas opciones que se abordaran en un proxymo post.


Ejemplos

RabbitMQ cuenta con soporte para distintos lenguajes, ya sea java,python,c#,js, entre otros, en este ejemplo se utilizara la libreria de python "pyka".

Productor.py


Primero importa la libreria pika.

Crea una conexion que recibe un parametro de conexion con una ip.

Crea un canal de conexion.

Declara un cola, dandole un nombre si no existe previamente.

Publicar un mensaje, usando un exchange por defecto, la ruta key que por el momento usara el nombre de la cola y el mensaje que se quiere enviar.

Cerrar una conexion.


 Consumidor.py

De manera muy similar al productor, importa la libreria, crea una conexion, crea un canal y una cola si no existia previamente. Luego crea una funcion que se utilizara por el momento para imprimir por pantalla el mensaje recibido, despues se define la cola en la que se enlazara, se llama la funcion que se creo anteriormente y los acuses de recepcion por defecto son manuales, el auto-ack facilita este flag .


Robin-Round Dispach

Imagina que estas haciendo muchas peticiones y que cada operacion se demora entre 2 - 3 segundos, de repente llegan 30 peticiones, esto representaria un retraso de cercano a un minuto y medio, la solucion es bastante sencilla,  colocar mas instancias de consumidores, permitiendo escalar

Productor.py

Modificando un poco el ejemplo anterior, para hacer enviar un numero arbitrario de peticiones.

Para probarlo, es tan sencillo como abrir una nueva ventana y ejecutar otro Consumidor.py, por defecto RabbitMQ enviará mensajes a los consumidor de forma secuencial, esta distribucion de mensajes le llaman round-robin. 

 

Message acknowledgment

Siguiendo el ejemplo, digamos que durante todo este proceso, uno de los consumidores muere, RabbitMQ lo marca para ser eliminado. 

Para evitar que ese mensaje pre procesado muera, RabbitMQ implemente el ack, es enviado de vuelta por el consumidor para decirle a RabbitMQ que un determinado mensaje ha sido recibido, procesado y que RabbitMQ es libre de borrarlo. 

Consumidor.py


 Con esta peqeña modificacion, no se perdera nada , los mensajes se volveran a entregar

 

El ack debe ser enviado en el mismo canal que recibió la entrega. Los intentos de acuse de recibo utilizando un canal diferente darán lugar a una excepción de protocolo a nivel de canal.


Message durability

 Que pasaria si por el contrario, es RabbitMQ el que se para o bloquea, hay que asegurar la cola o se perderan todos los mensajes. Para esto en la configuracion de la cola debe declararse como durable y aplicarse tanto a productor como a consumidor. Para evitar que la cola actual devuelva un error por pasarle otros parametros, se creara una nueva cola con otro nombre.

 channel.queue_declare(queue='nuevo_saludo', durable=True)  

Productor.py


Con esta modificacion marca como persistentes los mensajes, aunque no es una garantia muy fuerte, es suficiente para estas pruebas. Si posblemente les  genera un error en los consumidores, posiblemente sea porque no se ha modificado la cola del basic consume.

 channel.basic_consume(queue='nuevo_saludo'...)

 

Fair dispatch

RabbitQM distribuye los mensajes de manera uniforme, pero esto trae consigo de que alguno de los consumidores va a tener una sobre carga de trabajo. Para solucionar esto hay que decirle a RabbitMQ que no envie mas mensajes hasta que termine la operacion. 

Consumidor.py


La pequeña modificacion dice a RabbitMQ que no le envie mas de un mensaje a la vez a los consumidores.

 

ref: https://www.rabbitmq.com/

viernes, 14 de mayo de 2021

Primeros Pasos con RabbitQM

QUE ES RABBITMQ

RabbitMQ es un message broker de codigo libre, escalable y distibuido, basado inicialmente bajo el protocolo AMQP(Advanced Message Queuing Protocol), actualmente soporta otros protocolos de mensajeria como son STOMP ligero pensado para IoT y MQTT ligero orientado a texto.

 

CONCEPTOS DE RABBITMQ Y DEL SERVIDOR

Antes de profundizar, aqui algunos conceptos útiles para conocer a RabbitMQ


  •  Productor: Aplicación que genera los mensajes.
  •  Consumidor: Aplicación que recibe los mensajes.
  •  Cola: Estructura de como se almacenan los mensajes hasta que son consumidos o eliminados de la cola.
  •  Mensaje: Datos enviados del productor al consumido
  •  Conexión: Conexión TCP entre la aplicación y el RabbitMQ (messageBroker)
  •  Canal: Una conexión virtual dentro de una conexión que se utilizara para generar o consumir los mensajes.
  •  Intercambio (exchange): Recibe los mensajes de los productores y los envía a la cola segun las reglas definidas.
  •  Vinculación (binding): Una vinculación es una relación que se crea entre una cola y un intercambio.
  •  Clave de enrutamiento: La clave que el intercambio mira para decidir cómo enrutar el mensaje a las colas. Piensa en la clave de enrutamiento como la dirección de destino de un mensaje.
  •  Usuarios: Son creados con permisos asignados como derechos de lectura, escritura y confguración ademas de poder especificar hosts virtuales. 
  •  Vhost: Los hosts virtuales separan las aplicaciones que están usando la misma RabbitMQ.
  •  Acuses de Recepcion y Confirmaciones: Indicadores de que los mensajes han sido recibidos o se ha actuado sobre ellos.

 

FLUJO DE TRABAJO

  1. El productor publica un mensaje al exchange
  2. El exchange recibe el mensaje y pasa a enrutarlo
  3. Se establece un enlace entre el excange y la cola.
  4. El mensaje espera en la cola hasta que pueda ser aceptado por el consumido
  5. El consumidor procesa al mensaje


Existe varios tipos de Exchange con los que se puede alterar el trafico de los mensajes:

 

EXCHANGE DIRECTO: Se produce cuando hay un vinculo directo entre el productor y el consumidor. Esto se logra cuando la clave  de enrutamiento del mensaje coincide con la clave del enrutamiento, enviandolo a un consumidor concreto.

 

EXCHANGE TOPIC: Funciona de manera similar al exchange directo, sin embargo no necesita que haya una conincidencia exanca, este envia el mensaje a las colas que cumplan un patron definido.


EXCHANGE FANOUT: Este se comporta como un brodcast, enviando el mensaje a todos los consumidores que esten asociados a este exchange.

 
 

 En un proximo post, mostrare de forma practica como funciona RabbitMQ.

 

viernes, 19 de marzo de 2021

Creando Login MEVN STACK Front

 Primero instalar vuejs click de la pagina oficial, donde tendra toda la documentacion. Por ahora voy se va instalar cli de vue3 con el comando, 

npm install -g @vue/cli

Cuando termina de instalar, para crear un nuevo proyecto le da el comando

vue create bytefate

Me gusta escoger los packetes que voy a utilizar asi que escogi manual.

Luego que tipo de version se quiere trabajar en mi caso sera vue3, ademas babel, router y vuex.

 

Luego quieres el modo history que consiste en quitar el (#) de las rutas. Si colocas no igual va a funcionar. Enter.



Luego archivos dedicados.Si, Enter.

 

Guardar configuracion para nuevos proyectos. No, Enter. Cuando termina te aparecera algo asi.


Ahora hay que ir a la carpeta, que se creo en mi caso bytefate-front y oprimir ejecutar el siguiente comando y el te dira en que puerto esta corriendo.

npm run serve

Despues vas a la direccion que te dio y voula ya esta corriendo.



Ahora con el editor de texto preferido, van a ir a la ruta src/views y vamos a modificar el home.vue.

Voy a quitar todo el contenido del div, a eliminar el import y modificar el export y dejarlo algo asi. 

Dentro del form los input tienen una etiqueta llamada v-model, con ella se va a almacenar en un objeto llamado user, los valores que se le pasaron desde el navegador. Lo que hay en la linea 9 solo es para mostrar en pantalla lo que almaceno el objeto. En la linea 18, asi es como se define el objeto que almacenara la informacion. Se puede probar en el navegador y ver como los datos ingresados en los inputs, se imprimen en el navegador.


Ahora algo mas interesante, como toma la aplicacion los datos desde el navegador.

Primero se importa el mapa de acciones desde vuex, en la linea 26, se trae una accion o mejor una funcion y que la va a ejecutar el form, pasandole como parametro el user que tiene los datos del input. El @submit es un evento propio de vue que se dispara al precionar el boton y el prevent es para que la pagina no se refresque.


Cuando se instala vuex, lo que se pretende es centralizar los datos entre las rutas, los componentes en un lugar. Ese lugar es la ruta store/index.js, por defecto tendra modulos, las acciones por lo general lo que hace es llamar a una mutacion, que a su vez modifica el valor del estado y  el estado es como un tipo de variable global que vamos a acceder a ellas.

Bien como en la vista llamamos en el mapa de acciones a la funcion login, aqui debemos definirla. Hay que pasarle el commit como parametro y el objeto user, ahora con el console.log podemos mostrar los valores en consola.

 

Bien ahora que tal si se envia esos datos al backend?

 

Como se va a hacer una peticion con fetch al backend, lo mejor es convertir la funcion en asincrona, dentro de la sentencia try, se hace una peticion fetch pasandole en el body el objeto usuario y la respuesta la ´muestra por consola. Y el catch me mostrara si hay algun error.

 

En la linea 26 lo que hace es que llama a la mutacion llamada setToken y se le pasa el token recibido del backend. En la linea 8, setToken es una funcion que recibe un objeto state y un payload que en resumen toma una varible que es la que va a interactuar con el navegador pasandole el token para navegar en las rutas protegidas. Se puede visualizar en el almacenamiento en el modo consola del navegador.

Una comprobacion para que la aplicacion compare si hay un token en el navegador desde el componente padre de la aplicacion (App.vue). Lo que hara es con el siguiente script, es que cuando ingrese a la aplicacion verifique si hay un token de un usuario.



Ahora las rutas protegidas.

Lo que se hara es colocar un meta en la rutas protegidas y un foreach, pasandole 3 parametros (to, from, next) y al final verificar si contiene o no esa ruta la meta que se le coloco a la ruta.

En la linea 14 coloco el meta con un booleano en mi caso es isProtected y en la linea 23 se recorre router, verificando si es protegida o no la ruta. E la consola del navegador se podria visualizar el mensaje de protegido o no.


Ahora una condicion mas si existe el token y la ruta es protegida deberia dejar seguir y en caso contrario deberia redirigir al inicio. En este caso se evalua que si el token existe accediendo al store (import store from '../store'). Despues solo es consultar si el state del token es null se redirecciona al inicio o en el caso contrario podra navegar sin problemas.


Para probar que se este ingresando bien desde una ruta protegida, vamos a alguna ruta que se haya definido. Se importa el mapState como en la linea 9, se accede a los estados a travez de una propiedad computada. Hasta ahi perfecto, ahora para hacer una peticion hacia el backend se debe pasar en los headers un token y en el metodo created se inicializa la funcion que hace el fetch al backend.

 

Para cerrar sesion lo primero sera ir al index del storage y se creara una funcion Signup que resive un commit como parametro. Ahi se llamara al localStorage y se eliminara el token y tambien se cambiara el valor del estado token a null.

En la pagina principal de vue, anteriormente se habia mapeado las acciones para traer el token, lo que facilita la operacion. Ahora en la linea 14, se debe llamar a la funcion signout que se creo en el store y crear un boton que ejecute dicha funcion como en la linea 5

Para desplegarlo, corre el comando 

npm run build

Con eso compilara el proyecto y creara una carpeta nueva llamada dist.

Al ir dentro de esa carpeta, creas el comando git init para crear un nuevo proyecto

Descargar las actualizaciones desde el repositorio para evitar errores

Añades los arhivos al stage con git add nombreArchivo

Creas un commit -m "mensaje sobre el commit"

realizas el git branch -M nombreRama

git push -u origin nombreRama

 

Con eso se hizo un basico sistema de autenticacion con vue, mongodb express nodejs.

domingo, 22 de noviembre de 2020

PROCESO DE COMPILACION

Un lenguaje de programación es un tipo de lenguaje, que permiten generar un conjuntos de órdenes para el ordenador y que de este modo pueda realizar tareas. 

El primer lenguaje es el codigo maquina o binario que crean un grupo de instrucciones en base de 0's y 1's y es el lenguaje

Existen 2 grupos grandes de lenguajes.

Lenguajes de alto nivel:

Es el lenguaje mas compresible para el desarrollador pero en terminos de optimizacion no es lo mas adecuado al trabajar con hadware.

lenguajes de alto bajo nivel

Es el lenguaje as cercano al lenguaje maquina, en algunas ocaciones se suele utilizar directamente con el hardware, por ser el mas adecuado en terminos de rendimiento.

Ademas existen lenguajes que son considerados en un estado intermedio como es C, aunque otros los llaman de bajo nivel, su uso de punteros y rutinas en codigo ensamblador.

 

Sin importar como se considere un lenguaje de alto o bajo nivel, si es un lenguaje compilado necesitara forzosamente un compilador,que es una especie de traductor que transforma en este código en instrucciones binarias que la computadora pueda entender. Dependiendo de la arquitectura y el sistema operativo, los compiladores más usados son: gnu compiler collection para linux, clank para mac y Msvc para windows. En mi caso voy a utilizar OS linux asi que debo usar para compilar gcc.

Para convertir este código fuente en algo que nuestra computadora pueda interpretar y ejecutar tenemos que compilarlo en 4 pasos:

  •  Pre-procesamiento 

  • Compilación 

  • Ensamble 

  • Enlace 

En el pre procesamiento, el pre procesador identificando las directivas incluidas en el código fuente, haciendo que algunas como puede ser #define #include #ifdef, sean sustituidas, por el valor en donde han sido invocadas.

Con el comando: 

gcc -E edad.c > edad.pp 

Se vera un archivo con extencion .pp Durante este proceso se buscará el contenido del archivo que se indica como directivas y se reemplaza por completo de modo recursivo posiblemente haciendo llamado a otras dependencias. Asi es como un pequeño codigo de una pocas lineas termina con un poco mas de 700 lineas. 

La segunda etapa llamada compilación lo que hace es convertir esas 700 líneas en unas cuantas instrucciones en assembler.

Con el comando:

 gcc -S edad.c 

 Se obtendra un archivo con extension .s, si lo abre, obtendra algo similar a lo anterior, un archivo en codigo en lenguaje esamblador, aunque puede variar dependiendo la arquitectura es de x64 o x86. 

 

La tercera etapa en el proceso de compilación es el ensamblado,

independiente del sistema o la arquitectura, en este punto, el ensamblador tomara el archivo con el codigo assembler y lo conviete en codigo binario. 

Con el comando: 

gcc -c edad.c 

Se obtendra un archivo objeto, con extencion .o . Aunque no es tan frecuente hacer pasar por las etapas anteriores y tener un archivo en codigo assembler, se puede convertir a un archivo objeto con el comando:

 as -o edad.o edad.s 

Al abrir el archivo con extencion .o se puede aprenciar que es ilegible para los humanos. 

La última etapa es el enlazado, el compilador en cadena los archivos.o ademas creando los enlcaes de lsa distintas librerias que se invocan desde estos archivos. El enlazador se denomina ld, por motivos practicos no voy a ejemplificarlo, por tener que especificar las rutas de las librerias que seran consumidas por el programa.

En cambio, gcc con el siguiente comando, permite hacer este enlace con los archivo con extension .o:

gcc -o edad edad.o 

Para hacer los 4 pasos con un solo comando: 

gcc -o edad edad.c 

Por defecto cuando se crea un enlace dinamico, esto quiere decir que el ejecutable carga desde la memoria del equipo las liberias necesarias para funcionar correctamente, mientras que el enlace estatico hace que el ejecutable sea mas independiente por tener sus librerias incorporadas, pero esto hace que el archivo sea mas pesado. 

Para especificar el enlace estatico con el flag -static: 

gcc -static -o edad edad.c

 

ref: https://gcc.gnu.org/onlinedocs/ 

ref: man gcc

martes, 17 de noviembre de 2020

Chat Socket Tcp Con Node.js

 Profundizando un poco sobre los sockets bajo los protocolos TCP / UDP, como es la implementacion de socket tcp con nodejs, con un pequeño ejemplo de un chat room.


server.js

Como ya hemos visto, lo primero seria importar la libreria .net de node.js, se guarda en una variable la instancia del servidor. En la linea 6, se crea el evento connection, que se ejecutara si hay algun socket hace una conexión, ademas muestra por consola la ip y el puerto del usuario. Como esta recibiendo un socket, con el evento data, recibe la informacion que haya enviado el usuario, en este caso el consol log mostrara el buffer y los datos transformados a utf-8, en otras palabras,legible para humanos, asimismo devuelve con el metodo write lo que el usuario escribio. Y al final la instancia del servidor necessita en el evento listen, un puerto y host en este caso se le especifico que corriera con ip4 en el host y mostrara en consola el puerto en el que esta corriendo el servidor.

 

client.js

 El cliente tambien importa la libreria .net e instancia un socket en una variable.
En la linea 4 se esta importando una libreria tambien nativa de node.js que permite leer flujos de datos de distintas fuentes, como archivos, peticiones http, una consola, entre otras, una linea a la vez a travez de una interfaz, declarando el input y output.
El socket se pasa en el evento socket el host y el puerto del servidor, en la siguiente linea convierte los buffer recibidosen utf-8. En la liña 12 se instancia la interfaz de readline con el evento line que emite una linea, que se la enviaran al servidor a travez del evento socket.write.
Y por ultimo el socket data, recibe la respuesta del servidor y lo mostrará por consola.
Lo que se acabo de hacer, en el ejemplo anterior es conocido como servidor espejo, que reenvia los datos hacia el mismo usuario.
 

 server.js

Los cambios se hizo al ejemplo anterior, es comprobar que una clave que enviada desde el cliente cierre la coneccion del socket. En este caso es FINISH, cuando es enviada al servidor muestra un mensaje por consola y desconecta el server, en caso contrario solo mostrar la enformacion recibida.

client.js

Los cambios al cliente son si envía una clave cierre la coneccion con el servidor, y esperar una respuesta cuando este completamente cerrado. En este caso no espera una respuesta del servidor pero cerra la interfaz que captura lo que el cliente escribe por consola.


server.js

Para finalizar este ejemplo, severifica si hay una conexión  sin registrar, delo contrario se continua normalmente y se esta atento a los errores del servidor. Cuando hay una nueva conexión de socket al servidor, se guarda ese mensaje y el socket en un mapa declarado en la linea 5. Si el usuario envía la clave para terminar la conexión, el socket del usuario es eliminado junto con su usuario. Delo contrario se pasara la información del usuario formateada, junto al socket a una función creada en la linea 7, que enviará un el mensaje a todos los sockets almacenados excepto al socket del emisor.


client.js

En la interfaz, hay un método query que permite es un método que permite recibir un dato como entrada por el usuario y utiliza como salida este dato. Para utilizarlo en la interfaz debe especificar el output  debajo del input así output: process.stdout. Este dato de entrada la utilizara el servidor como nombre de usuario y se le muestra por consola la clave para cerrar la conexión.

Hasta aquí el ejemplo de chat desde consola utilizando librerías nativas de node.js a través del protocolo tcp.

ref: https://nodejs.org/en/docs/

viernes, 13 de noviembre de 2020

Sockets Nodejs

Socket es un interfaz con la cual, se crearon las implementaciones de la pila de protocolos tcp-ip con la que permite que internet se creara, y con ello dos servicios colección 

TCP

Los tcp sockets son los que gestionan todo lo relacionado a los circuitos vistuales conectando tanto a clientes como a sevidores. Tiene una serie de metodos como el connect que permite establecer el circuito desde el cliente hasta el servidor,destruirlos datos , crear eventos y utilixando el modelo de cliente servidor.

El socket de server sirve para escuchar eventos de forma pasiva y establecer la comunicación con el cliente.

El  socket de cliente que son las estructuras de datos despues de haberse establecido todo el circuito permitiran la interacción con el servidor.

UDP

Es la alternativa mas rapida y simple, enviando datagramas sin establecer un enlace obligatorio como es el 3 handshake, que utiliza tcp para establecer la conexión entre el cliente y servidor. El envio de datagramas, tiene unos datos asociado con un tamaño maximo.Es una comunicacion sensilla, sin embargo, no hay garantía de la integridad de los datos. Al  no establecer una conexión con el receptor de los datos, no se espera mensajes de respuesta, mucho menos el orden de llegada de los datos o si los paquetes están completos, haciéndolo un caso de uso muy especifico primando la velocidad de transmisión como lo son o servicios de voz y vídeo.

Ejemplo  

ServerUdp.js

En la primer linea se implementa la libreria dgram nativa de nodejs, la siguiente línea se crea un socket con ipv4 y la almacena en la variable server, e inicializa el socket con el método bind que recibe por parámetro un puerto por donde escuchara a los clientes. Los demás son eventos, el primero se emitee cuando un nuevo datagrama esta disponible en el socket, el segundo dgram.Socket es direccionable y puede recibir datos y el tercero si ocurre un error. 

Para entrar mas en detalle lo que esta haciendo el código, en el evento message, lo que esta haciendo es retornar al cliente el mensaje enviado, el evento listening esta guardando los datos del socket y los retorna en consola y el evento close si detecta un error, va a mostrarlo por consola y cerrara la conexión.

ClientUdp.js


De manera similar, tenemos al cliente que es muy similar al servidor, en este caso los process.stdin y
process.stdout fueron utilizados para que desde la consola se pudiera escribir e imprimir texto. Como se había mencionado antes los eventos del servidor son pasivos y necesita que el cliente los active. En este caso en la linea ocho, el socket llama al método send, que lo que hace es mandar datos al servidor. En el evento message su funcion aquí sera escribir en consola la respuesta  del servidor ypor último el evento error, mostrar por pantalla el error, cerrará la conexión y cerrara todolo demás. 

 

ClientTcp.js

Para trabajar con sockets tcp se debe cargar la libreria net que es nativa de nodejs, en la 2 linea se almacena un socket en una variable, en la linea siguiente, en el evento connect se le pasa el host y puerto del servidor al que se quiere conectar.

Cuando se trabaja con sockets los datos no se transmiten en texto plano sino en secuencia de bytes llamado buffer, por eso en la linea 5 se esta convirtiendo a texto legible por humanos. En la linea 7 se envia datos en el socket y en la linea 9, se espera el evento data que envie datos y los muestre por consola.

ServerTcp.js

En las primeras 2 lineas se carga la libreria, se crea y almacena una variable del servidor tcp, en la 4 linea se emite cuando hay una nuevo socket conectado, imprime por consola el host y el puerto del socket que se conecto. En la linea 7 en evento data, recibe los datos y los imprime en pantalla y devulve al socket lo que envio. En la linea 8 imprime en pantalla 2 valores, el primero el buffer recibido y el segundo, ese mismo buffer convertido a texto con el metodo .toString.

Con esto se ha profundizado un poco sobre protocolo y como nodejs desde sus librerías nativas permite realizarlo probando con un servidor eco.

ref: https://nodejs.org/api/

martes, 27 de octubre de 2020

Primeros Pasos de SQL Comandos (mysql)

 

La gestión de base de datos es una de las tareas más comunes que competen a todas las industrias, desde las más pequeñas, hasta las más grandes corporaciones. Es normal que muchos utilicen herramientas como en el caso de PhpMyAdmin para administrar la base de datos, pero no siempre es el caso cuando no existe interfaz gráfica y no hay más remedio de utilizar la consola, por eso hoy les traigo como administrar MySQL desde la consola y sobrevivir en el intento.

 

Iniciar sesión.

Nota: Utiliza el parámetro -h si solo es necesario.
 mysql -h hostname -u root -p

 

Crear una base de datos en el servidor SQL.

create database [databasename];

 

Listar todas las bases de datos en el servidor SQL.

show databases;

 

Cambiar de base de datos.

use [db name];

 

Ver todas las tablas en la base de datos.

show tables;

 

Para ver los formatos de los campos de la base de datos.

describe [table name];

 

Borrar la base de datos.

drop database [database name];

 

Borrar una tabla.

drop table [table name];

 

Mostrar toda la información de una tabla.

SELECT * FROM [table name];

 

Devuelve las columnas y la información de las columnas correspondientes a la tabla designada.

show columns from [table name];

 

Mostrar ciertas filas seleccionadas con el valor "algo".

SELECT * FROM [table name] WHERE [field name] = "algo";

 

Mostrar todos los registros que contengan el nombre "Luis" Y el número de teléfono '1234567'.

SELECT * FROM [table name] 
WHERE name = "Luis" AND phone_number = '1234567';

 

Mostrar todos los registros que no contengan el nombre "Luis" Y el número de teléfono '1234567' ordenados por el campo phone_number.

SELECT * FROM [table name] 
WHERE name != "Luis" AND phone_number = '1234567' 
order by phone_number;

 

Mostrar todos los registros que empiecen por las letras "Luis" Y el número de teléfono "1234567".

SELECT * FROM [table name] 
WHERE name like "Luis%" AND phone_number = '1234567';

 

Utilice una expresión regular para encontrar registros. Utilice "REGEXP BINARY" para forzar la distinción entre mayúsculas y minúsculas. Esto encuentra cualquier registro que empiece por a.

SELECT * FROM [table name] WHERE rec RLIKE "^a$";

 

Mostrar los registros únicos.

SELECT DISTINCT [column name] FROM [table name];

 

Mostrar los registros seleccionados ordenados de forma ascendente (asc) o descendente (desc).

SELECT [col1],[col2] FROM [table name] ORDER BY [col2] DESC;

 

Contar los registros.

SELECT COUNT(*) FROM [table name];

 

Unir tablas en columnas comunes.

select lookup.illustrationid, lookup.personid, person.birthday 
from lookup 
left join person 
on lookup.personid = person.personid;

 

Cambie a la base de datos mysql. Cree un nuevo usuario.

INSERT INTO [table name] (Host,User,Password) VALUES('%','user',PASSWORD('password'));

 

Cambiar la contraseña de un usuario (desde el Shell Unix).

mysqladmin -u root -h hostname.blah.org -p password 'new-password';

 

Cambiar a mysql db. Dar privilegios de usuario para una db.

INSERT INTO [table name] 
(Host,Db,User,Select_priv,Insert_priv,Update_priv,
Delete_priv,Create_priv,Drop_priv) 
VALUES ('%','db','user','Y','Y','Y','Y','Y','N');

 

Para actualizar la información que ya está en una tabla.

UPDATE [table name] 
SET Select_priv = 'Y',Insert_priv = 'Y',Update_priv = 'Y' 
where [field name] = 'user';

 

Borrar registro(s) de una tabla.

DELETE from [table name] where [field name] = 'algo';

 

Actualizar permisos/privilegios de una base de datos.

FLUSH PRIVILEGES;

 

Borrar columna

alter table [table name] drop column [column name];

 

Añadir una nueva columna a una tabla.

alter table [table name] add column [new column name] varchar (20);

 

Cambiar nombre de columna.

alter table [table name] 
change [old column name] [new column name] varchar (50);

 

Haz una columna única para que no haya duplicados.

alter table [table name] add unique ([column name]);

 

Ampliar una columna.

alter table [table name] modify [column name] VARCHAR(3);

 

Borrar el índice de una tabla.

alter table [table name] drop index [colmn name];

 

Cargar un archivo CSV en una tabla.

LOAD DATA INFILE '/tmp/filename.csv' replace INTO TABLE [table name] FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n' (field1,field2,field3);

 

Volcar todas las bases de datos para la copia de seguridad. El archivo de copia de seguridad es para recrear todas las db's.

mysqldump -u root -ppassword --opt >/tmp/alldatabases.sql

 

Volcar una base de datos para la copia de seguridad.

mysqldump -u username -ppassword --databases databasename >/tmp/databasename.sql

 

Volcar una tabla para la copia de seguridad.

mysqldump -c -u username -ppassword databasename tablename > /tmp/databasename.tablename.sql

 

Restaurar una copia de seguridad.

mysql -u username -ppassword databasename < /tmp/databasename.sql

 


viernes, 9 de octubre de 2020

Como configurar entornos virtuales en Python3

 


Los entornso virtuales, son mecanismos utilizados en para trabajar en distintos entornos separados de los directorios del sistema.Cada entorno funciona independiente de los demas, una vez activos puede tener conjuntos independientes de las librerias sin importar las versiones, solucionando multiples problemas de compatibilidad.

 

PYTHON3

PASO 1: Instalar python3-venv

Primero como buena practica siempre actualizar los paquetes del sistema antes de instalar cualquier paquete:

sudo apt-get update -y

Ahora instalar python3-venv

sudo apt-get install python3-venv

 

PASO 2: Crear el entorno virtual de python

Despues instalado, es hora de crear el directorio donde se almacenara el entorno virtual

mkdir byte_fate cd byte_fate

Ahora se crea el entorno virtual para en la carpeta del proyecto.

python3 -m venv bytefate_env

Si quieres comprobarlo te mostrar una carpeta nueva con el nombre que le diste al entorno

ls -l
 

PASO 3: Activar el entorno

Es hora de trabajar, para activar el entorno es necesario utilizar el siguiente comando

source bytefate_env/bin/activate

Una vez activado se podra ver el nombre del entorno virtual en la barra antes de la informacion del sistema, algo asi..

(bytefate_env) user@host:~/byte_fate#
 

PASO 4: Instalar paquetes

Ya tienes un entorno en limpio para jugar con diferentes versiones, sin ningun inconveniente al momento de agregar un nuevo paquete. Prueba instalando este paquete.

pip install requests
 

Paso 5: Cerrar el entorno Virtual

Para cerrarlo es muy sencillo, es ubicar la terminal que esta ejecutando el entorno virtual y ejecutar el siguiente comando
deactivate
 
 

Ahora que ya estas listo para crear, sus propios entornos con paquetes independientes.