Páginas

2019/05/03

MsiInv o cómo obtener información del software instalado en tu ordenador (en Windows)

Pues como dice el título, si quieres saber realmente qué software tienes instalado en tu computadora con el sistema operativo Windows, recomiendo utilizar el programa MsiInv (msiinv.exe) alojado aquí

Es un programa de consola que obtiene una información muy exacta de todos los programas, patches, actualizaciones, juegos, y demás utilidades que puedas tener instaladas.

Para saber cómo funciona puedes echar un vistazo a los siguientes enlaces:



2018/12/19

console.log() de javascript y substitución de texto

Siempre que he querido mostrar varias variables en una misma sentencia console.log() lo hacía de la siguiente forma:

console.log("Nombre:" + nombre + ", Apellido: " + apellido);

Es decir, concatenaba las variables con el texto.

Pues bien, acabo de descubrir que console.log() acepta la inclusión de parámetros para substituir un texto como lo hace el lenguaje C, esto es:

console.log("Nombre: %s, Apellido: %s", nombre, apellido);

También se acepta esta forma:

console.log(`Nombre: ${nombre}, Apellido: ${apellido}`, nombre, apellido);

[ nótese que se incluye el caracter ` para delimitar el texto, no sirven comillas simples ('') o dobles ("") ]

También es posible utilizar %d para números (que devuelve 0 si no lo son), y f% para números con notación decimal.


<script>
var nombre="Carl";
var apellido="Sagan";

var num1 = 56.6545;
var num2 = 57;

console.log("Nombre: %s, Apellido: %s", nombre, apellido);
// Resultado: Nombre: Carl, Apellido: Sagan

console.log(`Nombre: ${nombre}, Apellido: ${apellido}`);
// Resultado: Nombre: Carl, Apellido: Sagan

console.log('Nombre: %d, Apellido: %d', nombre, apellido);
// Resultado: Nombre: 0, Apellido: 0

console.log("num1: %d, num2: %d", num1, num2);
// Resultado: num1: 56, num2: 57

console.log("num1: %f, num2: %d", num1, num2);
// Resultado: num1: 56.6545, num2: 57

</script>

2018/05/25

PATCH y actualizaciones parciales en ASP.NET Core

Por actualización parcial me refiero a la actualización de algunas campos o propiedades de un objeto. La actualización por PUT reemplaza toda la información escribiendo campos vacíos cuando no se pasa contenido. Es decir, PUT actualiza el recurso pasado en su totalidad mientras que PATCH solamente actualiza los campos pasados en la llamada.

Con PUT se necesita pasar todos los campos que el recurso contenga, de otra forma los campos no pasados se consideran vacíos o nulos.

PATCH es útil para actualizar un campo sin tener que hacer un GET antes, ahorrando así una llamada, pero no quiere decir que sea una recomendación que tenga que utilizarse siempre ya que hay que recordar que todo depende del Contexto.

El método PATCH es particular. Es un método que consta de otras operaciones según la forma de actualización parcial que queramos, así pues tenemos las siguientes operaciones ('op'):

add, remove, replace, copy, move, test

P.ej.

{ "op": "replace", "path": "/helados/1/sabor", "value": "Chocolate" }

{ "op": "add", "path": "/helados/2", "value": { "name": "Dracula Chocolate" } }

{ "op": "remove", "path": "/helados/0" }

{ "op": "replace", "path": "/helados/1/sabor", "value": "Vainilla" }

{ "op": "copy", "from": "/helados/1", "path": "/superhelado" }

{ "op": "move", "from": "/helados", "path": "/mejoreshelados" }

{ "op": "test", "path": "/helados/name", "value": "Vainilla" } //para saber si existe
 
 
Estos ejemplos están escritos en formato JSON y es la forma con la que se trabajará con el Nuget Asp.Net Core JsonPatch (que debemos añadir a nuestro proyecto)
Existen otras librerías como Ramone, JsonPatch, Starcounter, Nancy.JsonPatch, Manatee.Json



1) Creamos nuestro método en ASP.NET Core
 
 [HttpPatch("{id:int}")]
 [EnableCors("MiPoliticaCORS")]
 public async Task<IActionResult> Patch(int id, [FromBody]JsonPatchDocument<Video> patch)
 {
   if (!ModelState.IsValid)
   {
    return BadRequest(ModelState);
   }

   Video videoBBDD = _context.Videos.AsNoTracking().SingleOrDefault(c => c.Id == id);

   if (videoBBDD == null) return NotFound();

   if (id != videoBBDD.Id)
   {
    return BadRequest();
   }

   if (!VideoExists(id))
   {
    return NotFound();
   }

   patch.ApplyTo(videoBBDD, ModelState);  //Importante este paso

   try
   {
    _context.Videos.Update(videoBBDD);
    await _context.SaveChangesAsync();
   }
   catch (DbUpdateConcurrencyException ex)
   {
     ....
   }

   return Ok();
 }



Destacar:
 - En la declaración de argumentos utilizamos JsonPatchDocument<Video>
 - Usar el método .ApplyTo()
 
En este caso quería actualizar un campo dado en el formato JSON que se 
ha visto en una fila de una BBDD de videos.


2) Pruebas del método PATCH con jQuery

(sí, ya sé que puedo hacerlo con Angular, XMLHttpRequest(), etc, etc. )

        
        var sendJsonData = [{
            "op": "replace", "path": "/name", "value": "valorCambioConPatch"
        }];
       
        console.log("JSON.stringify:", JSON.stringify(sendJsonData));

        $.ajax({
            type: 'PATCH',
            contentType: "application/json; charset=utf-8",
            headers: [{ 'Access-Control-Allow-Origin': 'http://localhost' }, 
                      { 'Access-Control-Allow-Methods': 'PATCH' } ],
            url: "http://...../api/videos/1",
            dataType: "json",
            data: JSON.stringify(sendJsonData),
            success: function (response) {
             console.log('Success: ', response);
            },
            error: function (jqXHR, textStatus, errorThrown){
             console.log("textStatus:",textStatus);
             console.log("errorThrown:",errorThrown);
            }
            }).done(function hecho(){
              console.log('Hecho.');
            });


Destacar:
- Importantísimo que en este caso sendJsonData sea un array. Hay que pasar un Array, 
  no me funcionó hasta que no lo contemplé.
- 'op' es la operación a realizar como hemos visto, en este caso quiero cambiar un valor 
   por otro pues utilizo replace
- 'path', no es una ruta de un sistema de ficheros, sino el campo del objeto BBDD que quiero cambiar (también me ha funcionado sin slash '/' 
pero en todos los sitios que he leído lo incluye)
- 'value', es el nuevo valor que quiero establecer


Referencias y páginas que me han ayudado:

- JsonPatch.com   
- http://benfoster.io/blog/aspnet-core-json-patch-partial-api-updates
- https://michael-mckenna.com/how-to-add-json-patch-support-to-asp-net-web-api/
- https://kimsereyblog.blogspot.com.es/2017/11/implement-patch-on-asp-net-core-with.html
- https://docs.angularjs.org/api/ng/service/$http#patch
 
 
 
 
Notas finales

"PATCH is neither safe nor idempotent." (https://tools.ietf.org/html/rfc5789#section-9.1)

es decir, PATCH no es seguro, entiendiendo como no seguro el tratamiento de colisiones 
al acceder al mismo tiempo sobre un mismo recurso

Collisions from multiple PATCH requests may be more dangerous than
   PUT collisions because some patch formats need to operate from a
   known base-point or else they will corrupt the resource.
Y continua...
"Clients using this kind of patch application SHOULD use a conditional request
   such that the request will fail if the resource has been updated
   since the client last accessed the resource."
"...The server MUST apply the entire set of changes atomically and never
   provide (e.g., in response to a GET during this operation) a
   partially modified representation."
Luego se sigue comentando problemas con el caché, para sentenciar ...
"There is no guarantee that a resource can be modified with PATCH..."
"Clients need to choose when to use PATCH rather than PUT."
 
Así pues, y después de lo leído, antes de utilizar PATCH hay que saber qué se hace.
 
Más referencias:
http://wahlnetwork.com/2015/07/13/patch/
https://tools.ietf.org/html/rfc5789#section-9.1

SyntaxHighlighter


Suelo utilizar este complemento para poder visualizar código formateado en este blog. El problema es que cada vez que cambio de Tema se desconfigura todo y tengo que volver a buscar información de cómo se instala.

Así pues para eso escribo esta entrada y los pasos a seguir son:

1) Ir a Tema | Editar HTML

2) Escribir estas líneas antes del </head>

<link href="https://agorbatchev.typepad.com/pub/sh/3_0_83/styles/shCore.css" rel="stylesheet" type="text/css"> 
<link ref="https://agorbatchev.typepad.com/pub/sh/3_0_83/styles/shThemeDefault.css" rel="stylesheet" type="text/css"> 

<script src="https://agorbatchev.typepad.com/pub/sh/3_0_83/scripts/shCore.js" type="text/javascript"></script> 
<script rc="https://agorbatchev.typepad.com/pub/sh/3_0_83/scripts/shBrushCSharp.js" type="text/javascript"></script> 
<script src="https://agorbatchev.typepad.com/pub/sh/3_0_83/scripts/shBrushCss.js" type="text/javascript"></script> 
<script src="https://agorbatchev.typepad.com/pub/sh/3_0_83/scripts/shBrushJava.js" type="text/javascript"></script> 
<script src="https://agorbatchev.typepad.com/pub/sh/3_0_83/scripts/shBrushJScript.js" type="text/javascript"></script> 
<script src="https://agorbatchev.typepad.com/pub/sh/3_0_83/scripts/shBrushPhp.js" type="text/javascript"></script> 
<script src="https://agorbatchev.typepad.com/pub/sh/3_0_83/scripts/shBrushPython.js" type="text/javascript"></script> 
<script src="https://agorbatchev.typepad.com/pub/sh/3_0_83/scripts/shBrushRuby.js" type="text/javascript"></script> 
<script src="https://agorbatchev.typepad.com/pub/sh/3_0_83/scripts/shBrushSql.js" type="text/javascript"></script> 
<script src="https://agorbatchev.typepad.com/pub/sh/3_0_83/scripts/shBrushVb.js" type="text/javascript"></script> 
<script src="https://agorbatchev.typepad.com/pub/sh/3_0_83/scripts/shBrushXml.js" type="text/javascript"></script> 

<script type="text/javascript">
 SyntaxHighlighter.all();
</script>


Siendo el resultado:


 

 



 

 

 

 

 

 

 

 

 

 

 




2018/05/16

Autentificación y autorización en Apache (a grosso modo)

Autentificación en Apache2

Caso práctico: se quiere establecer seguridad para que solamente algunos usuarios puedan acceder a un fichero alojado en un servidor Apache2.

Antes de nada decir que las diferencias entre Autentificación/Autenticación, y Autorización son:

  • Autentificación: verificar si la persona o entidad que se intenta conectar o acceder a un sistema es quien dice ser.
  •  Autorización: acción por el que se concede permiso a una persona o entidad a realizar otras acciones (lectura, modificación, escritura…) sobre un recurso de un servidor.


Se pedía dos formas de acceder a la lectura de un fichero en el servidor:

     1) En forma de autentificación en el sitio web pasando nombre de usuario y password
     2) Verificar que la URL pasada para consultar el recurso posee un ‘token’ o clave en esta URL en forma de texto.



1)     Autentificación en web

Para este caso tenemos que hacer lo siguiente:

a)
            sudo htpasswd –c /etc/apache2/.htpasswd nombreusuario

A continuación nos pedirá el password y este se guardará en el archivo .htpasswd

Podemos verlo con el comando:

      cat /etc/apache2/.htpasswd

b)

      sudo vi /etc/apache2/sites-enabled/000-default.conf

Añadir:

<VirtualHost *:80>
<Directory "/var/www/html/mipagina/">
   AuthType Basic
   AuthName "Restricted Content"
   AuthUserFile /etc/apache2/.htpasswd
   Require valid-user
</Directory>
</VirtualHost>

Lo que aquí configuramos es la forma de autentificación y dónde están las contraseñas alojadas para poder validad el usuario

Luego reiniciar el servidor Apache:

sudo service apache2 restart

Si accedemos a la URL nos aparecerá la siguiente imagen de autentificación:



También decir que podríamos acceder de la siguiente forma para que se 'logueara' directamente:

http://userName:password@direccionIP/pagina.html




      2)      Autorización mediante una palabra pasada por parámetro a una URL

En este caso se pidió que se le pasará la palabra ‘token=nombreequipo’ del modo http://direccionIP/pagina.html?token=nombreequipo

      a)      Módulo rewrite

    Para esto utilicé el módulo rewrite que está incluido en  
    /etc/apache2/mods-available/rewrite.load

    Para activarlo hay que ejecutarlo siguiente:
   sudo a2enmod rewrite
   service apache2 restart

      b)      Fichero .htaccess

          Añadí el fichero .htaccess dentro de /var/www/html/miproyecto

     RewriteEngine On
     RewriteCond ${REQUEST_FILENAME} -f
     RewriteCond ${REQUEST_FILENAME} !-d
     RewriteCond %{REQUEST_URI} \.html$ [NC]
     RewriteCond %{QUERY_STRING} !^token=nombreequipo [NC]

     RewriteRule . /403.html

     [NC] es un flag que indica que puede escribirse tanto en mayúsculas como en mínusculas (No Case Sensitive, es decir, que no distinga mayúscula y minúsculas)

             La primera línea activa el módulo Rewrite, la segunda es que el fichero pasado en la url sea  efectivamente un fichero, la tercera es que no sea un directorio, la cuarta que la url acabe en .html, y la quinta línea, es que el parámetro pasado contenga la frase “token=nombreequipo”. Si alguna de estas condiciones no se cumplen, el servidor nos redirige a la página 403.html

             Para poder utilizar .htaccess hace falta establecer en apache2.conf dentro de la sección <Directory> la sentencia "AllowOverride All"
  

     <Directory /var/www/html/miproyecto/>
Options –Indexes
Options FollowSymLinks
AllowOverride All
Require all granted
     </Directory>

           Options –Indexes bloquea el listado de ficheros de la raíz cuando intentamos acceder al directorio padre del proyecto.

2018/05/10

Pasos para hacer un Upload de 100 Megabytes bajo Nginx y ASP.NET Core 2


Pasos para hacer un Upload de 100 Megabytes bajo Nginx y ASP.NET Core 2

(y que no nos salga el error "413 Payload Too Large" (Kestrel) o  "413 Request Entity Too Large" (Nginx) )


Paso 1: Modificar nuestro web.config

<configuration>
  <system.web>
     <httpRuntime maxRequestLength="102400" /><!-- 100 MB in kilobytes -->
  </system.web>
  <system.webServer>

   ...
  <security>
    <requestFiltering>
      <requestLimits maxAllowedContentLength="102428800" /> <!--100 MB in bytes -->
     </requestFiltering>
  </security>

...
 </system.webServer>


Paso 2: Modificar nuestra configuración de Nginx

En mi caso tengo una configuración propia en /etc/nginx/sites-enabled/proyecto.conf
pero también es factible modificar /etc/nginx/nginx.conf

Añadiendo
client_max_body_size 100M; #si lo establecemos a 0 no hay límite.
dentro de la sección location / {} ,y server {..}, aunque también he leído que  haría falta en http {...} de nginx.conf

En mi caso yo lo he establecido en location y en server, y me ha funcionado.

Acordarse de luego hacer un nginx -s reload o service nginx reload


Paso 3: Modificar el comportamiento Kestrel

Este paso no aparece en todos los sitios y es esencial.

Nos vamos a Program.cs 

.UseKestrel(options=>
 {
   options.Limits.MaxRequestBodySize = 102428800; //100 Megas en bytes
 })





2018/04/25

Publicar un proyecto ASP.NET Core con todas sus dependencias

Si después de publicar un proyecto ASP.NET Core te han faltado librerías .dll que están reflejadas en el fichero proyecto.deps.json, y no quieres ir copiando una a una, tienes que añadir la siguiente línea a tu fichero .csproj del proyecto:

 <PropertyGroup>
    <TargetFramework>netcoreapp2.0</TargetFramework>
  <PublishWithAspNetCoreTargetManifest>false</PublishWithAspNetCoreTargetManifest>
  </PropertyGroup>


Enlace:
https://www.benday.com/2018/02/23/force-dotnet-publish-to-publish-dependencies-using-publishwithaspnetcoretargetmanifest/


MsiInv o cómo obtener información del software instalado en tu ordenador (en Windows)

Pues como dice el título, si quieres saber realmente qué software tienes instalado en tu computadora con el sistema operativo Windows, recom...