lunes, 10 de diciembre de 2018

AEM hablemos del arquetipo 11

Cuando creamos un proyecto con AEM. Siempre es importante saber que arquetipo estamos usando. Pues esto me determinara que source, herramientas y auto-configuraciones se esta utilizando.


Para declarar un servlet;

 Arquetipo 10:


@SlingServlet(paths="/bin/mySearchServlet", methods = "POST", metatype=true)
public class HandleClaim extends org.apache.sling.api.servlets.SlingAllMethodsServlet {
    private static final long serialVersionUID = 2598426539166789515L;
}


Arquetipo 11:

@Component(service=Servlet.class,
property={
Constants.SERVICE_DESCRIPTION + "=Simple Demo Servlet",
"sling.servlet.methods=" + HttpConstants.METHOD_POST,
"sling.servlet.paths="+ "/bin/myDataSourcePoolServlet"
})
}



Para usar @reference;

 Arquetipo 10:

import org.apache.felix.scr.annotations.Reference;

@Reference
private DataSourcePool dataPool;


Arquetipo 11:

import org.osgi.service.component.annotations.Reference;

@Reference
private DataSourcePool dataPool;


Usando DataPools:


Arquetipo 10:
Se configura como; Apache Sling Connection Pooled DataSource
http://localhost:4502/system/console/configMgr


Arquetipo 11:

Se configura como; Day Commons JDBC Connections Pool
http://localhost:4502/system/console/configMgr

miércoles, 5 de diciembre de 2018

Adobe AEM Form + AEM Data Model + MySql Example

Prerequisitos:

  1. AEM 6.3
  2. AEM-6.3.3.0-6.3.3.zip
  3. AEM-CFP-6.3.3.1-1.0.zip
  4. AEM-FORMS-6.3.3.1-LX-4.1.90.zip
  5. Mysql 

Pasos:

Necesitamos crear un ambiente con todos los prerequisitos anteriormente listados. 



Seguidamente necesitamos crear una base de datos.

Script:

CREATE DATABASE Registro_de_mascotas;
USE Registro_de_mascotas;

CREATE TABLE Mascotas (Nombre VARCHAR(20), Raza VARCHAR(30), Sexo CHAR(1), Fecha_de_nacimiento DATE);


Debemos crear la conexión a la base de datos. Y lo para esto, necesitamos;

Instalar los drivers en AEM:
Lo hacemos atravez de este tool:

http://localhost:4502/system/console/bundles

Dentro instalamos los bundles que necesitemos. Para este caso en especifico instalamos el de Mysql.


Este lo podes descargar aqui





Configurar Mysql como Datasource de AEM

Esto lo hacemos en el siguente tool:
http://localhost:4502/system/console/configMgr

Dentro buscamos: Apache Sling Connection Pooled DataSource

Y pulsamos en mas (+)

En el formulario, ponemos los datos de la base de datos:

Detalles:
Notas: Los datos que no se encuentra debajo dejarlos default


Datasource name: MascotasDataSource
DataSource service property name:
datasource.name
JDBC driver class:
com.mysql.jdbc.Driver
JDBC connection URI:
jdbc:mysql://localhost:3306/Registro_de_mascotas?autoReconnect=true&useUnicode=true&characterEncoding=utf-8
Username:
root
Password:
<VACIO>
Test on Borrow:
True
Test on Return:
True
Validation Query:
-1
Transaction Isolation:
READ_COMMITTED

Después de pulsar Save. Se creara por debajo un nuevo data source:



Nuestro siguiente paso es crear un nuevo data model.
http://localhost:4502/aem/forms.html/content/dam/formsanddocuments-fdm




Agregamos un nombre y pulsamos siguiente;



Seleccionamos el Datasource







Y pulsamos el botón de crear
Tenemos que editar el DataModel Recién creado.




Dentro en el Panel de edición, simplemente podemos desplegar el árbol y tendremos acceso a la base de datos.

Debemos agregar la tabla y los inputs.  Dentro del modelo:


Pulsamos el botón "Add Selected". Se agregara una tabla al panel de edición:

 Tenemos que editar la tabla y escogerles los modos y servicios (Mas adelante se explica esto en detalle)



Debemos escoger el;
Read Service: get.
Bidding To: Request Atribute
Biding Value: Nombre. (Nombre de la tabla)
Es importante destacar que he tenido problemas configurando el Bidding Value. Si se presenta ese problema utilizar la nomenclatura <Nombre Tabla>.<Nombre campo> eg; Mascotas.Nombre

Debemos escoger el;
Write Service: insert






Pulsamos Done.
Ahora nos toca configurar los servicios.

Editamos el servicio Get:




 Escogemos el método;
Output Model Object: Mascotas.
Return array?: True (Por que la tabla de prueba no tiene llave primaria)

Editamos el servicio Insert:

Escojemos:
Output Type: Boolean (Defecto)
Arguments: Mascotas







Nuestra siguiente tarea seria probar que el DataModel este funcionando correctamente.

Entramos al utilitario de Test Model Object


Dentro escogemos el
Select Model/Service: Write model Object

Y debemos escribir los datos a insertar:

{
  "Mascotas": {
    "Nombre": "Pepe",
    "Raza": "Indefinida",
    "Sexo": "M",
    "Fecha_de_nacimiento": "2015-12-17"
  }  
}


Y pulsamos el botón Test:

Mi experiencia me dice que este tool tiene mucho problemas, pues me a tocado pulsar repetidamente Test, hasta 5 veces para la respuesta del insert sea True.

Ahora nos toca pulsar la búsqueda.

En este caso escogemos:
Select Model/Service: Read model object

Pulsamos Mascotas. Y nos generara un template solicitando el Nombre.
Seria poner "Gabo" para hacer referencia al que acabamos de insertar.


{
    "request": {
        "attribute": {
            "Nombre": "Gabo"
        }
    }
}


De igual manera que en el insert, Me toco pulsar varias veces el botón de Test. Porque las primeras veces me muestra errores de conexión, como el 4 o 5 intento funciona correctamente.

Crear el formulario:

El paso final es crear el formulario basado en el Data Model anterior, en el siguiente tool:


http://localhost:4502/aem/forms.html/content/dam/formsanddocuments


Creamos un Adaptive Form



Creamos un Template en blanco
Nombramos el Formulario como: MascotasForm





Escogemos el datasource


Y pulsamos el botón Create.

Seguidamente tenemos que editar el formulario:
Nos vamos al tab de Data Model Objects y arrastramos toda la tabla:


Luego agregamos el botón de submit:







Y editamos el container del formulario:
En la sección de  Submission:
Submit Action: Submit using Form Data model
Data Model to submit: Escojemos el del mascotas.

Y por ultimo guardamos los cambios.

Ahora solo resta pulsar el botón de preview.
De igual manera que los tool de testing, cuando doy submit la primera vez me genera un error. Es hasta el segundo submit cuando efectivamente se insertan los valores en la base de datos.

martes, 20 de noviembre de 2018

Clonando y cambiando partición root en Linux

Contexto:
Sucede que mis particiones de root siempre las hago alrededor de los 20GB. Usualmente esto me da espacio suficiente para soportar mucho tiempo antes de la próxima reinstalación.
 Pero esta vez no, cuando trate de dimensionar root, me dio errores. Entonces tome la decisión de clonar root y cambiarlo.

Nota:
De momento ha funcionado bien y sin problemas.

Pasos:
  1. Utilizando un Live CD en mi caso use Kubuntu 14.02 (Viejo). Entro en en modo "Probar sin instalar".
  2.  Dentro entro al gestor de particiones de KDE. Comando:
    partitionmanager




  • Dentro encontré: 

    • /dev/sda7 como root (20GB), 
    • /dev/sda5 como home(350GB). 
    • Simplemente lo que hice fue hacer algo de espacio para la nueva partición que superara su tamaño original. Esta fue asignada con 90GB y quedo como /dev/sda8




  • Lo siguiente que debemos hacer es clonar sda7 (Viejo root) en /dev/sda8 (Nuevo root). Usando el comando: 
    dd if=/dev/sda7 of=/dev/sdb8 bs=64K conv=noerror,sync
  •  El siguiente paso fue montar /dev/sda7 y el /dev/sda8 para poder editar el fstab. Usando Dolphin es solo cuestión de darle un par de clicks.
  •  Debemos editar el /etc/fstab de ambas particiones. Quedaría algo como esto: Nota: Soy de vieja escuela y siempre me ha parecido mejor usar particiones que UUID. Sin embargo en el final de este post encontraras como cambiar los UUID de la vieja partición.
  • Como se logra ver en la imagen anterior, antes se usaba la UUID del /dev/sda7. Pero ahora directamente lo cambie para /dev/sda8. Y esto para no tener que lidear con NADA mas. Sino tendriamos que actualizar un monton de cosas entre ellas grub.(Recortar cambiar el FSTAB DE AMBAS PARTICIONES)
  • Para este punto ya podemos reiniciar (Dejar de usar el LiveCD
  • Con la nueva partición corriendo, si ejecutamos el
    df -h
    se puede notar  que la partición aun tiene 20Gb de espacio. Esto es porque se clono de forma que la tabla de particiones se duplico. Lo que debemos hacer es ejecutar este comando:
    sudo resize2fs /dev/sda8 
    de esta forma se actualiza y ahora si me marca los 90GB de espacio. 

  • Epilogo
    Como editar el UUID de un disco duro con comandos?

    Contexto:
    Como se duplico la vieja root, también duplico el UUID y esto no es recomendable.

    Es tan sencillo como generar un nuevo UUID y actualizarlo:

    uuidgen
    #bbef6868-6903-456e-ad5e-2784154dfb9a
    tune2fs /dev/sda7 -U bbef6868-6903-456e-ad5e-2784154dfb9a
    

    domingo, 11 de marzo de 2018

    Jugando con las macros del Razer BlackWidow Ultimate 2012 para Linux(Parte 1)

    Nota: Ya existen proyectos super eficientes como OpenRazer.

    Sin embargo el presente articulo fue creado con el fin de experimentar un poco con libusb, udev.

    Para quien es este articulo?
    Esta pensando para programadores, y curiosos. No se explica como funciona Libusb, pero se da un ejemplo de vida real.

    Contexto:
    El teclado viene con 5 Macro Keys. Que necesitan ser inicial izadas en orden de que Linux detecte sus entradas. Desgraciadamente para ello se necesita, hacer un poco de ingeniería inversa de las entradas. El objetivo de  articulo no es para aprender a hacer ingeniería inversa del tema. Pero pueden ver un vídeo muy ilustrativo aqui.

    En resumen; Lo que necesitamos hacer es mandar unos bits mágicos a través de LibUSB al teclado para que empiece a usar los Macros.
    La forma mas sencilla de probar todo es con evtest.

    sudo evtest
    No device specified, trying to scan all of /dev/input/event*
    Available devices:
    #Blablabla en mi compu el input esta en el 4
    /dev/input/event4:      Razer Razer BlackWidow Ultimate
    /dev/input/event5:      Razer Razer BlackWidow Ultimate
    /dev/input/event6:      Razer Razer BlackWidow Ultimate
    #Blablabla
    Select the device event number [0-20]: 4
    Input driver version is 1.0.1
    Input device ID: bus 0x3 vendor 0x1532 product 0x10d version 0x111
    Input device name: "Razer Razer BlackWidow Ultimate"
    Supported events:
      Event type 0 (EV_SYN)
        #Bla bla bla Y esta es la parte interesante... Note que el Key configura teclas F13 en adelante. Esas son las macros.
        Event code 183 (KEY_F13)
        Event code 184 (KEY_F14)
        Event code 185 (KEY_F15)
        Event code 186 (KEY_F16)
        Event code 187 (KEY_F17)
        Event code 188 (KEY_F18)
        Event code 189 (KEY_F19)
        Event code 190 (KEY_F20)
        Event code 191 (KEY_F21)
        Event code 192 (KEY_F22)
        Event code 193 (KEY_F23)
        Event code 194 (KEY_F24)
        Event code 240 (KEY_UNKNOWN)
      Event type 4 (EV_MSC)
        Event code 4 (MSC_SCAN)
      Event type 17 (EV_LED)
        Event code 0 (LED_NUML)
        Event code 1 (LED_CAPSL)
        Event code 2 (LED_SCROLLL)
    Key repeat handling:
      Repeat type 20 (EV_REP)
        Repeat code 0 (REP_DELAY)
          Value    250
        Repeat code 1 (REP_PERIOD)
          Value     33
    Properties:
    Testing ... (interrupt to exit)
    Event: time 1520787420.323002, type 17 (EV_LED), code 0 (LED_NUML), value 0
    Event: time 1520787420.323002, -------------- EV_SYN ------------
    Event: time 1520787420.376467, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70028
    Event: time 1520787420.376467, type 1 (EV_KEY), code 28 (KEY_ENTER), value 0
    Event: time 1520787420.376467, -------------- EV_SYN ------------
    Event: time 1520787422.226497, type 4 (EV_MSC), code 4 (MSC_SCAN), value 700e0
    Event: time 1520787422.226497, type 1 (EV_KEY), code 29 (KEY_LEFTCTRL), value 1
    Event: time 1520787422.226497, -------------- EV_SYN ------------
    Event: time 1520787422.476487, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70006
    Event: time 1520787422.476487, type 1 (EV_KEY), code 46 (KEY_C), value 1
    Event: time 1520787422.476487, -------------- EV_SYN ------------


    Cada vez que toquen una tecla convencional, verán el input de la tecla. Pero si se presiona alguna de las macros no pasa nada. Para solucionar cree un pequeño programa en C el cual le pasa los bits mágicos al teclado.

    #include 
    #include 
    #include 
     
    using namespace std;
     
    #define VENDOR_ID 0x1532
    #define PRODUCT_ID 0x10D
    #define USB_REQUEST_TYPE  0x21
    #define USB_VALUE  0x300
    #define USB_REQUEST  9
    #define USB_INDEX  0
    #define USB_INTERFACE  0 //La interfaz de configuracion esta en el 0
     
    unsigned char buffer[90] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00}; //Magic bits
     
    int main(int argc, char** argv) {
        libusb_context *ctx = NULL; //a libusb session
        libusb_device_handle *dev_handle; //a device handle
        int result; //Result form the writting
        result = libusb_init(&ctx); //initialize a library session
        if (result < 0) {
            cout << "libusb_init init error " << result << endl; //there was an error
            return false;
        }
        dev_handle = libusb_open_device_with_vid_pid(ctx, VENDOR_ID, PRODUCT_ID); //these are vendorID and productID I found for my usb device
        if (dev_handle == NULL) {
            cout << "libusb_open_device_with_vid_pid cannot open Blackwidow keyboard" << endl;
            return false;
        }
        if (libusb_kernel_driver_active(dev_handle, USB_INTERFACE) == 1) {
            if (libusb_detach_kernel_driver(dev_handle, USB_INTERFACE) != 0) {
                cout << "libusb_detach_kernel_driver error" << endl;
                return false;
            }
        }
        result = libusb_claim_interface(dev_handle, USB_INTERFACE); //claim interface 0 (the first) of device (mine had jsut 1)
        if (result < 0) {
            cout << "Cannot Claim Interface" << endl;
            return false;
        }
        result = libusb_control_transfer(dev_handle, USB_REQUEST_TYPE, USB_REQUEST, USB_VALUE, USB_INDEX, buffer, 90, 0);
        if (result != 90) {
            return false;
        }
        result = libusb_release_interface(dev_handle, USB_INTERFACE); //release the claimed interface
        if (result != 0) {
            cout << "Cannot Release Interface" << endl;
            return false;
        }
        //Attached and reclain the driver
        libusb_attach_kernel_driver(dev_handle, USB_INTERFACE);
        libusb_close(dev_handle); //close the device we opened
        libusb_exit(ctx); //needs to be called to end the
        return 0;
    }
    


    Ahora bien debemos compilar el programa con libusb y ejecutar este programa con sudo

    # Instalar la libreria necesaria
    sudo apt-get install libusb-1.0-0-dev
    # Instalar GCC
    sudo apt-get install build-essential
    # Compilar
    g++ blackwidowkeyboardinit.cpp `pkg-config libusb-1.0 --libs --cflags` -o blackwidowkeyboardinit
    
    # Ejecutar el programa
    sudo ./blackwidowkeyboardinit 
    
    #Ahora bien debemos moverlo a una ubicacion final
    sudo mv blackwidowkeyboardinit /usr/bin/blackwidowkeyboardinit
    

    Y por ultimo volvemos a probar con evtest.

    Ahora si veremos las entradas del teclado cuando presionemos algún MacroKey...

    Lo que queda es que el programa se ejecute con permisos de super usuario, cuando se inserta el teclado. Para eso recurrimos al udev.
    #Dentro de la carpeta /etc/udev/rules.d
    #Creamos un archivo 
    sudo touch 40-razer_blackwidow_keyboard.rules
    
    #Con el contenido
    #ACTION=="add", ATTR{idVendor}=="1532", ATTR{idProduct}=="010d", RUN+="/bin/sh -c 'echo == >> /home/koza/udev-env.txt; env >> /home/koza/udev-env.txt'"
    #ACTION=="add", ATTR{idVendor}=="1532", ATTR{idProduct}=="010d", RUN+="/usr/bin/blackwidowkeyboardinit"
    
    #Refrescamos las reglas con udev
    sudo udevadm control --reload-rules
    
    #Reiniciasmos udev
    sudo service udev restart
    

    Tomar en cuenta que la primera linea del archivo se puede eliminar, Pero por testing la dejo allí.
    Simplemente cuando insertar el teclado en un USB en home crear un archivo con los datos del ambiente.

    Si quieres experimentar con las reglas debes simplemente ejecutar el comando siguiente después de cada cambio.

    udevadm control --reload-rules && udevadm trigger
    


    Nota: Probado en Debian 8 (Jessie)

    sábado, 2 de septiembre de 2017

    Configurar Android Devices para desarrollo en Linux (Debian 8)

    Es muy comun encontrarse este error despues de ejecutar:

    adb devices
    
    #Error al mostrar que no hay permisos:
    List of devices attached
    M4 SS1070       no permissions (verify udev rules); see [http://developer.android.com/tools/device.html]

    Aquí el problema es que los usb son mas restrictivos en linux.
    Pero no te alarmes. Es sencillo de resolver.

    Lo que voy a mostrar en una recopilación de la mayoría de vendors para que no sufras mas por esto. Eventualmente si después de seguir los pasos abajo mostrados aun te sigue saliendo.
    Tendrás que buscar el vendo-Id correcto para tu device.

    #Edita/Agregar el archivo de udev rules
    sudo nano /etc/udev/rules.d/51-android.rules
    
    #Agregar la lista de abajo al archivo.#51-android.rules: 
    #Lista con los vendors mas comunes
    SUBSYSTEM=="usb", ATTR{idVendor}=="0502", MODE="0666", GROUP="plugdev" #Acer
    SUBSYSTEM=="usb", ATTR{idVendor}=="0b05", MODE="0666", GROUP="plugdev" #ASUS
    SUBSYSTEM=="usb", ATTR{idVendor}=="413c", MODE="0666", GROUP="plugdev" #Dell
    SUBSYSTEM=="usb", ATTR{idVendor}=="0489", MODE="0666", GROUP="plugdev" #Foxconn
    SUBSYSTEM=="usb", ATTR{idVendor}=="04c5", MODE="0666", GROUP="plugdev" #Fujitsu
    SUBSYSTEM=="usb", ATTR{idVendor}=="04c5", MODE="0666", GROUP="plugdev" #Fujitsu Toshiba
    SUBSYSTEM=="usb", ATTR{idVendor}=="091e", MODE="0666", GROUP="plugdev" #Garmin-Asus
    SUBSYSTEM=="usb", ATTR{idVendor}=="18d1", MODE="0666", GROUP="plugdev" #Google
    SUBSYSTEM=="usb", ATTR{idVendor}=="201E", MODE="0666", GROUP="plugdev" #Haier
    SUBSYSTEM=="usb", ATTR{idVendor}=="109b", MODE="0666", GROUP="plugdev" #Hisense
    SUBSYSTEM=="usb", ATTR{idVendor}=="0bb4", MODE="0666", GROUP="plugdev" #HTC
    SUBSYSTEM=="usb", ATTR{idVendor}=="12d1", MODE="0666", GROUP="plugdev" #Huawei
    SUBSYSTEM=="usb", ATTR{idVendor}=="24e3", MODE="0666", GROUP="plugdev" #K-Touch
    SUBSYSTEM=="usb", ATTR{idVendor}=="2116", MODE="0666", GROUP="plugdev" #KT Tech
    SUBSYSTEM=="usb", ATTR{idVendor}=="0482", MODE="0666", GROUP="plugdev" #Kyocera
    SUBSYSTEM=="usb", ATTR{idVendor}=="17ef", MODE="0666", GROUP="plugdev" #Lenovo
    SUBSYSTEM=="usb", ATTR{idVendor}=="1004", MODE="0666", GROUP="plugdev" #LG
    SUBSYSTEM=="usb", ATTR{idVendor}=="22b8", MODE="0666", GROUP="plugdev" #Motorola
    SUBSYSTEM=="usb", ATTR{idVendor}=="0e8d", MODE="0666", GROUP="plugdev" #MTK
    SUBSYSTEM=="usb", ATTR{idVendor}=="0409", MODE="0666", GROUP="plugdev" #NEC
    SUBSYSTEM=="usb", ATTR{idVendor}=="2080", MODE="0666", GROUP="plugdev" #Nook
    SUBSYSTEM=="usb", ATTR{idVendor}=="0955", MODE="0666", GROUP="plugdev" #Nvidia
    SUBSYSTEM=="usb", ATTR{idVendor}=="2257", MODE="0666", GROUP="plugdev" #OTGV
    SUBSYSTEM=="usb", ATTR{idVendor}=="10a9", MODE="0666", GROUP="plugdev" #Pantech
    SUBSYSTEM=="usb", ATTR{idVendor}=="1d4d", MODE="0666", GROUP="plugdev" #Pegatron
    SUBSYSTEM=="usb", ATTR{idVendor}=="0471", MODE="0666", GROUP="plugdev" #Philips
    SUBSYSTEM=="usb", ATTR{idVendor}=="04da", MODE="0666", GROUP="plugdev" #PMC-Sierra
    SUBSYSTEM=="usb", ATTR{idVendor}=="05c6", MODE="0666", GROUP="plugdev" #Qualcomm
    SUBSYSTEM=="usb", ATTR{idVendor}=="1f53", MODE="0666", GROUP="plugdev" #SK Telesys
    SUBSYSTEM=="usb", ATTR{idVendor}=="04e8", MODE="0666", GROUP="plugdev" #Samsung
    SUBSYSTEM=="usb", ATTR{idVendor}=="04dd", MODE="0666", GROUP="plugdev" #Sharp
    SUBSYSTEM=="usb", ATTR{idVendor}=="054c", MODE="0666", GROUP="plugdev" #Sony
    SUBSYSTEM=="usb", ATTR{idVendor}=="0fce", MODE="0666", GROUP="plugdev" #Sony Ericsson
    SUBSYSTEM=="usb", ATTR{idVendor}=="2340", MODE="0666", GROUP="plugdev" #Teleepoch
    SUBSYSTEM=="usb", ATTR{idVendor}=="0930", MODE="0666", GROUP="plugdev" #Toshiba
    SUBSYSTEM=="usb", ATTR{idVendor}=="19d2", MODE="0666", GROUP="plugdev" #ZTE
    SUBSYSTEM=="usb", ATTR{idVendor}=="0414", MODE="0666", GROUP="plugdev" #Gigabyte
    
    #Ejecutar el comando:
    sudo udevadm control --reload-rules
    #Esto con el objetivo de no reiniciar tu PC
    #Y refrescar los Udev en "caliente"
    
    
    #Por ultimo simplemente volver a conectar nuestro device a la computadora y ejecutar
    adb devices
    
    List of devices attached
    M4 SS1070       device



    martes, 18 de julio de 2017

    miércoles, 1 de marzo de 2017

    Seguridad con SpringBoot y CSRF

    La seguridad con con Springboot es realmente sencilla.
    Para activar la Basic Html, simplemente creamos un conjunto de clases de esta forma:

    @EnableWebSecurity
    @Configuration
    @EnableSpringHttpSession
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Value("${com.pmj.dyo.configuration.security.user}")
        private String user;
    
        @Value("${com.pmj.dyo.configuration.security.password}")
        private String password;
        
        @Value("${com.pmj.dyo.configuration.csrf.login}")
        private String loginPage;
        
        @Value("${com.pmj.dyo.configuration.csrf.allow}")
        private String[] patterns;
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests().antMatchers(patterns).permitAll().and().csrf().disable().httpBasic().and()
                    .addFilterAfter(csrfFilter(patterns), FilterSecurityInterceptor.class)
                    .addFilterAfter(new CsrfGrantingFilter(loginPage), CsrfFilter.class);
        }
    
        private Filter csrfFilter(String[] patterns) {
            CsrfFilter csrfFilter = new CsrfFilter(csrfTokenRepository());
            csrfFilter.setRequireCsrfProtectionMatcher(csrfProtectionMatcher(patterns));
            return csrfFilter;
        }
    
        private NoAntPathRequestMatcher csrfProtectionMatcher(String[] patterns) {
            return new NoAntPathRequestMatcher(patterns);
        }
    
        private CsrfTokenRepository csrfTokenRepository() {
            HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
            repository.setHeaderName(X_XSRF_TOKEN);
            return repository;
        }
    
        /**
         * bCryptPasswordEncoder
         * 
         * @return
         */
        @Bean
        public BCryptPasswordEncoder bCryptPasswordEncoder() {
            return new BCryptPasswordEncoder();
        }
    
        /**
         * configureGlobal
         * 
         * @param auth
         * @throws Exception
         */
        @Autowired
        public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
            auth.inMemoryAuthentication().withUser(user).password(password).roles("USER");
        }
    
        /**
         * sessionRepository
         * 
         * @return
         */
        @Bean
        @SuppressWarnings("rawtypes")
        public SessionRepository sessionRepository() {
            return new MapSessionRepository();
        }
    
        /**
         * sessionStrategy
         * 
         * @return
         */
        @Bean
        public HeaderHttpSessionStrategy sessionStrategy() {
            return new HeaderHttpSessionStrategy();
        }
    
        /**
         * @return the user
         */
        public String getUser() {
            return user;
        }
    
        /**
         * @param user
         *            the user to set
         */
        public void setUser(String user) {
            this.user = user;
        }
    
        /**
         * @return the password
         */
        public String getPassword() {
            return password;
        }
    
        /**
         * @param password
         *            the password to set
         */
        public void setPassword(String password) {
            this.password = password;
        }
    }
    
    ////////////////////////////////////////////////////////////////////////////////////////////
    
    
    public class CsrfGrantingFilter implements Filter {
    
        public static final String X_XSRF_TOKEN = "X-XSRF-TOKEN";
    
        private String loginPage;
    
        private final Logger log = LoggerFactory.getLogger(this.getClass());
    
        /**
         * Login Page injection
         * @param loginPage
         */
        public CsrfGrantingFilter(String loginPage) {
            this.loginPage = loginPage;
        }
    
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
                throws IOException, ServletException {
            CsrfToken csrf = (CsrfToken) servletRequest.getAttribute(CsrfToken.class.getName());
            String token = csrf.getToken();
            if (token != null && isAuthenticating(servletRequest)) {
                servletRequest.setAttribute(X_XSRF_TOKEN, true);
            } else {
                servletRequest.setAttribute(X_XSRF_TOKEN, false);
            }
            filterChain.doFilter(servletRequest, servletResponse);
        }
    
        private boolean isAuthenticating(ServletRequest servletRequest) {
            HttpServletRequest request = (HttpServletRequest) servletRequest;
            return request.getRequestURI().equals(loginPage);
        }
    
        @Override
        public void destroy() {
            LogUtil.info(log, this.toString());
        }
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            LogUtil.info(log, filterConfig.toString());
        }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    
    @RequestMapping(method = POST, path = "", produces = APPLICATION_JSON_VALUE)
        public Map login(@RequestBody UserEntry userEntry, ServletRequest servletRequest,
                ServletResponse servletResponse) {
            boolean xsrfAvailable = (boolean) servletRequest.getAttribute(X_XSRF_TOKEN);
            Authorization aut = client.login(userEntry);
            Map resolve = new HashMap(); 
            if (aut != null && aut.isAccepted() && xsrfAvailable) {
                CsrfToken csrf = (CsrfToken) servletRequest.getAttribute(CsrfToken.class.getName());
                String token = csrf.getToken();
                HttpServletResponse response = (HttpServletResponse) servletResponse;
                Cookie cookie = new Cookie(X_XSRF_TOKEN, token);
                cookie.setPath("/");
                cookie.setSecure(true);
                response.addCookie(cookie);
                resolve.put(STATUS, AUTHORIZED);
                resolve.put(USERNAME, username);
                resolve.put(PASSWORD, password);
                resolve.put(ROLE, aut.getRole());
                resolve.put(TOKEN, token);
            } else {
                resolve.put(STATUS, UNAUTHORIZED);
            }
            return resolve;
        }
    


    Básicamente lo que sucede en este ejemplo es lo siguiente:
    1.  El punto de control que genera el Cross Site Request Forgery es /login
    2. Si el login no es efectivo el CSRF no aparece como set en el cookie
    3. Ahora bien el toque esta en que el body también presenta el basic autentification y el CSRF. De esta forma es mas sencillo que el Javascript almacene los datos.
    4. Cada nuevo request debe enviar los Basic Login y el CSRF.
    Dentro de la aplicacion pasa esto:
    1.  La aplicacion fija el toking en el login. 
    2. Si cualquier otro request que no este en la lista de permitidos es invocada. Revisa el Basic Aut y el CSRF toking. La clase que genera los toking es CsrfGrantingFilter.

    martes, 21 de febrero de 2017

    Java Poi con Maven y Springboot Restful (Usando imagenes)

    Este articulo no es un "tutorial". Es un conjunto de notas de mi experiencia.
    Si vas a adentrarte en este articulo. Debes conocer como usar POI. Maven y Springboot Restfull.

     Lo primero que debemos hacer es configurar el POM del maven para usar  todas las características de excel. Claramente algunas no son necesarias. Pero es mejor tenerlas para usar TODO lo que Excel ofrece:

    
          dom4j
          dom4j
          1.6.1
      
      
       org.apache.poi
       poi
       3.9
      
      
       org.apache.poi
       poi-ooxml
       3.9
      
      
          org.apache.commons
          commons-collections4
          4.1
      
      
          org.apache.xmlbeans
          xmlbeans
          2.3.0
      
    

    Ahora bien para generar reportes POI ofrece varias características principalmente varias vistas de distintos tipos. Para no complicarse vamos a usar lo que SpringBoot ofrece.


    No es recomendable... generar los reportes como stream dentro de los HttpServletResponse . Porque se puede cortar el request y el reporte quedar corrupto. Usar siempre las vistas.

    //Lo primero debemos escojer un view que se ajuste a las necesidades. Al final hablare de los distintos tipos
    public class ExcelBuilder extends AbstractXssfStreamingView {
    
        @Override
        public void buildExcelDocument(Map model, Workbook workbook, HttpServletRequest request, HttpServletResponse response) throws Exception {
            //Aqui ya vienen inicializado el workbook.
            //La unica funcion es implementar. Seria; Crear el sheet, crear filas, celdas, poner estilos, etc
            //No debemos preocuparnos por escribir el workbook en el response. Solo dejemos que el metodo termine.
            //Y Spring sabe que debe tomar el workbook y generar un archivo.
        }
    
    }
    
    //Debemos configurar que la vista sea usada para los endpoint
    //Sencillamente podemos usar esto:
    @Configuration
    public class ExcelBuilderConfig {
        
        @Bean
        public ExcelBuilder ExcelBuilder() {
            return new ExcelBuilder();
        }
    
    }
    
    //Ahora bien solo resta usarlo en algun endpoint
    @Api(value = "contest", description = "the contest API")
    public interface ContestApi {
    
        /**
         * contestApplicantExport
         *
         * @param contest
         * @param brandid
         * @return
         */
        @ApiOperation(value = "", notes = "Returns a excel file report according to the information provided (A5:ContestApplicantExport)")
        @ApiResponses(value = {@ApiResponse(code = 200, message = "gallery response"),
                @ApiResponse(code = 200, message = "unexpected error")})
        @RequestMapping(value = "/contest/{contest}/{brandid}", produces = {
                "application/ms-excel"}, method = RequestMethod.GET)
        @org.springframework.web.bind.annotation.GetMapping("/dyo-config")
        ModelAndView contestApplicantExport(
                @ApiParam(value = "Filter based on a specific contest", required = true) @PathVariable("contest") String contest,
                @ApiParam(value = "Filter based on a specific brand", required = true) @PathVariable("brandid") String brandid,
                @ApiParam(value = "HttpServletResponse to setup the excel ouput", required = true) HttpServletResponse response);
    }
    
    
    
    @Configuration
    @RestController
    public class ContestApiController implements ContestApi {
    
    
        @Override
        public ModelAndView contestApplicantExport(
                @ApiParam(value = "Filter based on a specific contest", required = true) @PathVariable("contest") String contest,
                @ApiParam(value = "Filter based on a specific brand", required = true) @PathVariable("brandid") String brandid,
                @ApiParam(value = "HttpServletResponse to setup the excel ouput", required = true) HttpServletResponse response) {
    
            Book book = /*Cualquier Objecto*/
            return new ModelAndView("ExcelBuilder", "book", book); //Note que "book" es el dato que se puede obtener de la vista
        }
    }
    
    
    Los diferentes tipos de vistas presentes generan diferentes tipos de workbook.
    Cada una con características diferentes:
    Podemos mencionar XSSFWorkbook and SXSSFWorkbook.

    La clase AbstractXssfStreamingViewes funcional para archivos muy grandes. Sin embargo tiene la tendencia a no funcionar de buena manera con las imágenes. Puede que te tengas que enfrentar a Streaching o a resize ridículos. Después de muchos intentos y de canas verdes. Descubrí que si uno quiere insertar imágenes. La mejor forma es usando XSSFWorkbook.

    Para eso escribí mi propia versión de un AbstractXlsxView.

    //Simplemente hacemos esto:
    public abstract class AbstractXssfStreamingView extends AbstractXlsxView {
    
        @Override
        protected XSSFWorkbook createWorkbook(Map model, HttpServletRequest request) {
            return new XSSFWorkbook();
        }
    
    }
    
    //Y lo utilizamos:
    public class ExcelBuilder extends AbstractXssfStreamingView {
    
        @Override
        public void buildExcelDocument(Map model, Workbook workbook, HttpServletRequest request, HttpServletResponse response) throws Exception {
            Book book = (Book) model.get("book"); //Usar de referencia al ejemplo de arriba para obtener los datmos del model
            //Tu codigo aqui
        }
    
    }
    
    //En el codigo de ejemplo para agregar imagenes creo un pequeno factory.
    //La implementacion es por un conjunto de intefacez de esta manera:
    
    @FunctionalInterface
    public interface CellProduceInterface {
    
        /**
         * update
         * 
         * @param excelCell
         * @param data
         * @param workbook
         * @param sheet
         * @param point
         */
        public void update(org.apache.poi.ss.usermodel.Cell excelCell, Cell data, Workbook workbook, Sheet sheet, Point point);
    
    }
    
    //Y su implementacion
    //Notas:
    //El excelCell es el cell de POI
    //El data es el modelo de la informacion de la celda
    //Woorkbook asociado con la vista 
    //Sheet actual en que que excelCell esta presente
    public class ImageCellProduce implements CellProduceInterface {
    
        private static final Logger log = LoggerFactory.getLogger(ImageCellProduce.class);
    
        @Override
        public void update(org.apache.poi.ss.usermodel.Cell excelCell, Cell data, Workbook workbook, Sheet sheet,
                Point point) {
            String path = (String) data.getValue();
            if (path != null) {
                byte[] bytes = ExcelUtil.convertImagePathToBytes(path);
                if (bytes.length > 0) {
                    int pictureIdx = workbook.addPicture(bytes, Workbook.PICTURE_TYPE_PNG);
                    CreationHelper helper = workbook.getCreationHelper();
                    Drawing drawing = sheet.createDrawingPatriarch();
                    ClientAnchor anchor = helper.createClientAnchor();
                    //Col and Cell pos
                    anchor.setCol1(point.y);
                    anchor.setRow1(point.x);
                    //Height is not possible without stretched the image
                    Picture pict = drawing.createPicture(anchor, pictureIdx);
                    if (data.getWidth() != -1) {
                        sheet.setColumnWidth(point.y, ExcelUtil.calculatePoiWidthSize(data.getWidth()));
                        data.setWidth(-1);//Asi no se vuelve a aplicar el estilo mas adelante
                    }
                    if (data.getHeight() != -1) {
                        excelCell.getRow().setHeight((short) ExcelUtil.calculatePoiWidthSize(data.getHeight()));
                        data.setHeight(-1); //Asi no se vuelve a aplicar el estilo mas adelante
                    }
                    data.setAutoSize(false);
                    pict.resize(); //Como es XSSFWorkbook no deberia presentar problemas con el size y mantiene el original
                }
            } else {
                log.info("ImageCellProduce: Ignoring image on " + point);
            }
        }
    
    }
    
    

    miércoles, 6 de abril de 2016

    Provar en local enviar correos con Postman

    Creo que esto podría servir para cualquier tecnología. Pero me voy a enfocar en el plugin de Postman para wordpress en PHP.

    Pasos:

    1.) Debemos instalar Python con todos los utilitarios.

    2.) Ejecutar el comando en una terminal
    Nota: La terminal mostrara en consola todo los correos que se envíen a este servidor de pruebas.

    sudo python -m smtpd -n -c DebuggingServer localhost:45
    

    3.) Debemos ir a la configuración del postman del wordpress.
    Luego en Configuración manual.



    Dentro es simplemente de poner:

    Outgoing mail server hostname:......127.0.0.1
    Outgoing mail server port:................45
    Security:..............................................None
    Authentication:...................................None


    4.) Enviamos un mail de pruebas.


    5.) Este correo lo podremos ver en la terminal.



    jueves, 17 de marzo de 2016

    Kde Kate con React.js y Syntaxis Hightlight

    Para los que me siguen en el blog, saben que mi entorno de escritorio favorita es KDE. Y para desarrollo web en especial para Javascript utilizo Kate.
    Resulta que React.js esta muy de modo hoy en día, entonces me di a la tarea de investigar y aprender un poco.
    Para mi sorpresa, React.js tiene una sintaxis algo "Jodida". Y no se puede interpretar como Javascript normal.
    Entonces tome el Synstaxis Higtlight de Javascript que viene por defecto en Kate y lo edite para que funcione con React.js
    (Por cosas como estas amo el software libre).

    Simplemente tiene que colocar este archivo:

    
    
    
    
      
        
           break 
           case 
           catch 
           const 
           continue 
           debugger 
           default 
           delete 
           do 
           else 
           finally 
           for 
           function 
           if 
           in 
           instanceof 
           new 
           return 
           switch 
           this 
           throw 
           try 
           typeof 
           var 
           void 
           while 
           with 
        
        
           class 
           enum 
           export 
           extends 
           import 
           super 
    
          
           implements 
           interface 
           let 
           package 
           private 
           protected 
           public 
           static 
           yield 
        
        
           Infinity 
           NaN 
           false 
           null 
           true 
           undefined 
        
        
    
          
          
          
            
          
    
          
            
            
            
    
            
            
            
            
            
    
            
            
            
    
            
            
            
            
            
            
            
    
            
            
    
            
            
            
    
            
            
    
            
            
    
            
    
            
            
    
          
    
          
            
            
            
            
            
            
          
    
          
            
            
            
            
          
    
          
            
            
          
    
          
            
            
            
            
            
            
          
    
          
            
            
            
          
          
            
            
            
          
    
          
            
            
          
          
            
            
            
          
    
          
            
            
            
            
            
            
            
            
          
          
            
            
            
          
          
            
          
          
            
          
    
          
            
            
          
    
          
            
            
            
            
            
            
          
          
            
            
            
            
            
            
         
         
            
            
         
    
    
        
        
          
          
          
          
          
          
    
          
          
          
          
          
          
    
          
          
          
          
          
          
          
    
          
          
    
        
      
      
        
          
          
        
        
      
    
    

    con el nombre. react.xml.

    En el folder: ~/.kde/share/apps/katepart/syntax/

    Nota: Esta es la primera versión del asunto.
    Supongo que la tendré que ir madurando. Cualquier Feedback sera mas que bienvenido.

    domingo, 4 de octubre de 2015

    Instalar Nvidea Dirver/Steam en Debian 8


    Pasos:

    1. Agregar el el repositorio al administrador de paquetes
    sudo nano /etc/apt/sources.list
    #deb http://http.debian.net/debian/ jessie main contrib non-free
    sudo apt-get update
    

     2. Activar multiarquitectura
    sudo dpkg --add-architecture i386
    sudo apt-get update
    

    3. Instalar el paquete:
    sudo apt-get install libgl1-nvidia-glx:i386
    sudo apt-get install steam
    


    4. Crear el archivo:

    /etc/X11/xorg.conf.d/20-nvidia.conf

    Con el contenido:

    Section "Device"
            Identifier "My GPU"
            Driver "nvidia"
    EndSection

    5. Reiniciar

    lunes, 31 de diciembre de 2012

    Apache para drupal 7 en Linux (Problemas con Clean URL)

    Hace algún tiempo me he empezado a interesar en Drupal 7. Honestamente me ha gustado mucho, la idea esta bien planteada. La documentación esta bien y el soporte de la comunidad. En futuras entradas hablare de los módulos. Por ahora quiero hablar un poco sobre los requisitos necesarios y sobre todo de Apache y su configuración.

    Verán instalar Drupal 7 es un juego de ninos. Podrían buscar en Internet miles de entradas de como instalarlo. Por eso no me parece útil referirme al tema.

    Una vez instalado ya tienen su sistema instalado en localhost. Y digamos que quieren ingresar a la pagina de autentificación de ususario.
    Deberian acceder a la siguente pagina:

    http://127.0.0.1/kcontrol/user

    Pero sorpresa, SORPRESA!!!
    La pagina no existe. Bienvenido al problema de los cleanURL.
    Para poder acceder esta pagina deberian usar:

    http://127.0.0.1/kcontrol/?q=/user

    Porque?
    El .htaccess de Apache es un archivo que te permite escribir reglas especializadas para que los clean url funcionen en Drupal 7. Por defecto no vienen configuradas en nuestro Apache de linux mediante de los repositorios (sudo apt-get install apache2)

    Por eso vamos a hacer un par de ajustes para que sirvan:

    1. Primer paso instalar apache y todas las dependencias:

    #!/bin/bash
    sudo apt-get install apache2 php5 libapache2-mod-php5 php5-gd php5-dom php5-pgsql


    Note que yo uso Postgrest SQL. Por eso el paquete php5-pgsql pero para los mysql adictos debería ser php5-mysql

    2. Modificar el archivo /etc/apache2/sites-available/default
    Remplazar:
    "AllowOverride none" por "AllowOverride All"


    3. Habilitar el modulo de rewrite rules

    #!/bin/bash
    sudo a2enmod rewrite
    sudo service apache2 restart

    Listo!!!

    miércoles, 30 de mayo de 2012

    Convertir el color de una imagen a transparente con bash...

    Hace tiempo atrás me había enfrentado a la tarea de quitar un color de una imagen en BMP y sustituirla por transparencia.

    Nota: Por razones de derechos de autor no puedo poner las imágenes, pero puedo poner el link donde están:

    http://www.reinerstilesets.de/

    Para recrear lo que quiero hacer es algo como esto:
    Cambiar el cafe y ponerlo trasparente
     

    Esas imágenes son geniales para programar juegos con SDL. Ya que necesitamos un color key que podamos "sacrificar". Pero si lo queremos usar en algún lenguaje que soporte transparencia como Java.

    R// Muy fácil dirán unos, abrís GIMP y seleccionas con Magic Choose el color deseado lo cortas y lo salvas.

    Es verdad, pero hacerlo para 1000 imágenes...
    VERDAD? que no es tan fácil.

    La solución a nuestros problemas es simplemente un script en bash que hagarra todas las imágenes las convierta y borre las originales.

    El comando que necesitamos es este:

    convert -transparent 'RGB()' imagenOrigen.bmp imagenDestino.png

    El script quedaria

    #!/bin/bash
    FILES=`find $1 | grep bmp`
    for f in $FILES
    do
        nf=`echo ${f//bmp/png}` #replace all
        echo $nf
        convert -transparent 'RGB(97,68,43)' $f $nf
        rm $f
    done

    Y para usarlo basta llamar el script y darle el folder con todas las imagenes

    viernes, 20 de enero de 2012

    El meollo de las librarias y el proceso de linkeo en C++

    Uno de los compiladores más completos que cumple con todas las normas ISO de C++ Gcc sobre linux. Y quiero compartir lo que he aprendido en los últimos años de programación.
    Lo primero que siempre me costo es el linkeo y que es este condenado proceso:
    Bueno el linkeo es el paso de anexar bibliotecas a nuestro código objeto (Source code compilado) generando una imagen binaria.
    Un ejemplo hiper sencillo. El clásico holamundo.cpp

    //holamundo.cpp
    #include <iostream>
    using namespace std;
    int main() {
        cout << "Hola Mundo" << endl;
        return 0;
    }
    
    ./hola


    El comando genera en silencio un binario con la salida de hola (Parametro -o) del sorce code (seguido de g++)
    Para correrlo simplemente usamos

    g++ holamundo.cpp -o hola

    Este archivo utiliza una librería implícita que es la iostream. Por ende el linkeo se da correctamente.
    Pero imagina que queremos hacer algo mas complejo. Algo que necesite de librerías adicionales para trabajar. Bueno que tal si creamos una librería súper sencilla para servir de ejemplo. Con esto se aclararan muchas dudas. Pero lo primero.
    Nota: La librería que vamos a crear es conocida como librería estática. Esta es un poco mas pesada. que una dinámica. Y se encuentra en ubicaciones no estandar.( /usr/include y /usr/lib). La dificultad para crear una biblioteca dinámica es nula. Pero lo dejare para futuras entradas.

    //koza.h
    #ifndef MENSAJE_H
    #define MENSAJE_H
    int getMessage();
    #endif
     
    //koza.cpp
    #include <iostream>
    #include "koza.h"
    int getMessage(){
        return 25;
    }
    

    Ahora si a crear nuestra biblioteca.

    g++ -c koza.cpp -o libkoza.o
    ar rcs libkoza.a libkoza.o

    Ahora si. La hablada. El primer comando crea un archivo objeto de nuestro source sin linkear. (comando -c). La salida (comando -o) es libkoza.o. Esto es un estándar para bibliotecas. Siempre deben empezar con lib#Nombre#.a (En el caso de las librerías estáticas).
    Ahora si tenemos nuestra libreria y nuestro archivo de inlcusion.
    Simulemos un ambiente de mas o menos de esta forma.
    Primero nuestro archivo de ejemplo para que utilice la biblioteca.

    //mostrar.cpp
    #include <iostream>
    #include "koza.h" //Se incluye la cabecera de esta forma porque es bilioteca estatica (dinamica es con <>)
    using namespace std;
    int main(){
        cout << getMessage() << endl;
        return 0;
    }
    

    Simulemos la siguiente estructura de archivos.
    /home/koza/ejemplo/mostrar.cpp
    /home/koza/ejemplo/include/koza.h
    /home/koza/ejemplo/lib/libkoza.a
    ahora si a compilar

    g++ /home/koza/ejemplo/mostrar.cpp -I/home/koza/ejemplo/include/ -L/home/koza/ejemplo/lib/ -lkoza

    Ahora si que sucede.
    El Parámetro -I le dice la ruta de los archivos de inlcusion.
    El Parámetro .L le dice la ruta de los archivos de librerías
    y el comando -lkoza -> La librería a incluir es libkoza.a PORQUE? Pues por el estándar. el busca el nombre de la librería después del -l#NAME según el nombre libkoza.a.
    Ese fue un ejemplo muy troglodita.
    Veamos algo mas útil.
    Nota: Debemos tener instaladas las bibliotecas de QT4.
    Vamos a compilar un ejemplo de holamundoqt.cpp

    //holamundoqt.cpp
    #include <qapplication>
    #include <qpushbutton>
    
    int main(int argc, char *argv[]) {
        QApplication app(argc, argv);
        QPushButton hello("Hello world!");
        hello.resize(100, 30);
        hello.show();
        return app.exec();
    }
    

    Qt es una librería para hacer muchas cosas, entre ellas interfaces gráficas.
    Bueno es hora de compilar el ejemplo de arriba. Como verán se ocupan un montón de librerías. Entonces a jugar.

    g++ holamundoqt.cpp -o hola -I/usr/include/qt4 -I/usr/include/qt4/QtGui -L/usr/lib/qt4 -lQtCore -lQtGui

    Hay una herramienta que nos ayuda mucho a la hora de realizar linkers de nuestros programas.
    Es la poderosa pkg-config.
    Simplemente es una herramienta que ayuda a la hora de completar los comandos de compilación. Generando los parámetros -I -L -l necesarios para compilar.
    Para conocer los paquetes instalados usamos:

    pkg-config --list-all

    El nombre que se genera a la izquierda es el paquete que podemos usar.
    En el ejemplo de qt de arriba el siguiente comando

    pkg-config --cflags --libs QtGui

    Muestra la siguiente salida.
    -DQT_SHARED -I/usr/include/qt4 -I/usr/include/qt4/QtGui -I/usr/include/qt4/QtCore -lQtGui -lQtCore
    Es precisamente todos los comandos que escribimos arriba. Haciendo uso de esta herramienta y de los pipes. El programa de holamundoqt lo podemos compilar tambien de esta forma:

    g++ holamundoqt.cpp -o hola `pkg-config --cflags --libs QtGui`

    martes, 18 de octubre de 2011

    Algunos trucos con el httpd.conf y php.init

    Php en su archivo de configuración tiene una serie de atributos interesantes. Muchos de los cuales en mi vida he visto y otros que no les presto mucha importancia. Curiosamente hace un par de semanas atrás, mi jefe directo me asigno una misión bastante peculiar. Tenia que hacer funcionar local un aplicación. No voy a rondar en detalles. Si los quieren leer pueden verlos aquí.

    En mi búsqueda de hacer funcionar dicha aplicación me tope con algunas variables en los archivos de configuración en el php y en el apache que quiero compartir por aca:
     
    Primer truco

    Uno muy interesante es poder anular los warning en php.
    Usando la variable siguente en el php.init:

    error_reporting = E_ALL & ~E_NOTICE

    Esto le dice al Php que muestre los errores, pero no los warning o Notice como se les conoce. Entonces imaginemos que en el php creamos un array o tratamos de acceder alguna variable global y después simplemente tratamos de acceder sus datos con un índice que no existe.

    Ejemplo:

    echo $_REQUEST["email"]; 

    Si esta variable no se encuentra configurada en el php.init, el warning es mostrado.

    Sin embargo puede presentar problemas intensos de hackeo. Yo no recomendara utilizarlos.

    Segundo Truco

    Otro truco que si me parece mas util de usar es el: auto_prepend_fileauto_append_file. Estos son archivos que se cargan al inicio de cualquier script y despues de cualquier otros script en su orden respectivamente.

    Un ejemplo seria algo asi como:
    auto_prepend_file = /home/sites/koza/phpdefines.php

    Esta variable auto carga o auto ejecuta este script antes de cualquier ejecusion. Es equivalente a:

    inlcude('/home/sites/koza/phpdefines.php');
    

    En el incio de cualquier script.

    Tercer Truco

    Ejecutar los script en php en archivos con extensión html. Al inicio pensé que esto seria de lo mas trivial del mundo. Honestamente confieso que me tomo más tiempo del que pensé. Realmente es trivial, pero encontrar el lugar para poner la configuración fue lo que me tomo mucho tiempo. Nota: Se puede hacer esto un archivo .httpaccess. Sin embargo no logre hacerlo funcionar por eso prefiero dejarlo como un nota (De que en teoría es posible).


    En el archivo de configuración de apache (httpd.conf)

    Buscamos la línea:

    AddType application/x-httpd-php

    Y le agregamos al final .htm y .html

    Quedando algo asi como:

    AddType application/x-httpd-php .htm .html

    Esto es muy útil por razones de seguridad. Escondiendo en que esta programado la aplicación porque en el browser se vera simplemente .html en los scripts que en realidad son php. Pienso que es una excelente practica de configuración del los servidores.

    Cuarto Truco.

    Los virtual host, las configuración https y el /etc/hosts. Estos chicos pueden hacer una verdadera epifanía si no se sabe configurar bien. Hagamos algo básico y general. Los archivos hosts son archivos especializados dentro de los sistemas operativos (/etc/hosts para linux, unix y derivados) -> notese el s al final. Este archivo "simula" la llamada de un dominio remplazando por un ip previamente configurado.

    Ejemplo:
    127.0.0.1 koza.com

    Si en el browser abro la dirección www.koza.com en realidad el archivo hosts se encarga de cargar mi servidor local.

    Quinto Truco.

    Los virtual Host son una noble invención, junto con el archivo host pueden hacer grandes hazanas.
    Daremos por un hecho que existe en el archivo host la configuración anteriormente dada.

    Entonces podemos construir de koza.com un mundo de reglas virtuales de nuestro sitio como:

    
            ServerName cruiser.koza.com
            UseCanonicalName Off
            DocumentRoot /home/sites/koza/htdocs/
    
        SetEnv SITE_LINK_URL http://www.google.com
    
    

    En la configuracón arriba establecida le estamos diciendo al apache (Con ayuda del host file) que la proxima vez que alguien acceda a cruiser.koza.com su configuración personalizada va a usar Document Root en la carpeta /home/sites/koza/htdocs y que va a tener una variable de entorno personalizada llamada SITE_LINK_URL. Podemos hacer uso de esta en Php asi:

    define("SITE_LINK_URL", $_SERVER["SITE_LINK_URL"]);

    domingo, 9 de octubre de 2011

    A que te Hackeo!!!

    Esa fue mi reacción, cuando con mirada frenética y sin menor contemplación una base de datos requería para realizar un encargo inusual de mi jefe inmediato. Este me había solicito echar ha andar local un proyecto web, de la forma que fuera sin importar lo medios. Solo contaba con un FTP.  

    Notas: Para evitar cualquier problema evitare nombres, definiciones o cualquier cosa que me pueda llevar a la orca.

    En este mundo hay personas que uno simplemente no les puede decir No o darse el lujo de quedarles mal. Para mi una de esas personas es mi Jefe. Lo curioso no es porque sea mi jefe, no es porque sea mi mejor amigo o alguien al que le deba mucho. Es porque simplemente es alguien que me supo ganar como aliado, es alguien que antepone la persona antes que un puesto, un titulo o nombramiento. Alguien que yo respeto, que sabe me apoya en mi ideas locas, que toma en cuenta mi opinión no importa lo ocupado que este. Alguien de admirar.

    Y hay empieza mi viaje oscuro, llevándome por el sendero de la devastación informática, a invocar las poderosas magias negras y arcanas del Hackeo Ético. Mi enigmática hazaña empieza con lo mas básico. Un Ftp "abierto de patas", como la puta piedrerita de la linea del tren. Casi desnuda y sin menor seguridad. Completamente irresistible (Sarcasmo negro). La misión que Vega me encomendó es que de una carpeta en un FTP X, lograra descargar un sitio Web (HTML, JS, CSS, PHP) y tratara de correr dicho proyecto en local.

    Resulta que dicho proyecto tenia, SSL, Base de datos y unas configuraciones en Php que solo Dios sabe. Ya me conocen, cuando algo es realmente "pichudo", es donde mas me motivo. El reto, las cosas difíciles es algo que me apasiona.
    Me di a la tarea de descargar los script y analizarlos en mi computadora local. Después de luchar un rato y simplemente convencido de que la única manera que lograría cumplir con mi misión era entrando por SSH al FTP. Buscar la base de datos, los Certificados SSL en Apache, ademas de la configuraciones de los directorios virtuales.


    Tenía la primera regla de oro del hackeo a mi favor. Muchas veces el hackeo es algo que funciona por pura y real oportunidad. No es como en las películas, que tienen equipos de codificación o cosas asi. Aveces hackear es algo tan sencillo como robar el password o asumirlo (abs123, cumpleaños, cédula). También son cosas mas avanzadas como debilidades en el software. Por lo general cuando se descubre una debilidad en un software son un par de días (al menos en software libre) para encontrar el parche de seguridad. Pero el hacker que logra encontrar dicho fallo, se vuelve muy famoso o simplemente tiene un par de días para hacker todo lo que pueda. 

    NOTA:
    No se crean lo de las películas. No todos los software se pueden hackear. Hay algunos que son super seguros y al menos que encuentren un fallo de seguridad o logren robar un password no lo alcanzaran. Se imagina que existiera un hacker que pudiera romper cualquier seguridad. Podría acceder al banco que quisiera, comprar con tarjetas de crédito robadas. Digamos que seria la persona mas poderosa en el mundo.

    Resulta que este FTP que les hablo, estaba tan mal configurado que me permitía llegar a Raíz de un directorio UNIX. YAHOOO, tenia la oportunidad que cualquiera hacker desearía. Una mala configuración en un software. Solo necesitaba ver como lograr entrar a servidor por SSH. No dure mucho en pensar que la solucion estaba en:

    ssh-keygen -t rsa

    El RSA generado lo subí al directorio del home del FTP. Después cuando ejecute el SSH, BINGO. Estaba dentro del servidor para hacer lo que me viniera en gana. Lo primero, la base de datos. Necesitaba buscarla. Con tan mala suerte que la base no estaba instalada en el Mysql del server. Después de hacer algo de magia con un par de comando, encontre un respaldo en SQL (Otra caseria oportunista exitosa). Simplemente lo importe en mi computadora con el siguiente comando:


    mysql -u koza basededatosx << backup.sql

    Y descargue todos los archivos que necesitaba buscando los comandos por ssh y despues pasarlos a mi servidor local.

    Las próxima entrada será; Lo que aprendí en php.init y el httpd.conf en mis días de hacker... No se las pierdan.

    AEM hablemos del arquetipo 11

    Cuando creamos un proyecto con AEM. Siempre es importante saber que arquetipo estamos usando. Pues esto me determinara que source, herramien...