Categories
Uncategorized

Recording Audio Cross Platform

There are several sources for doing this but, the only that worked for me was this implementation of Record.js.

Works in Chrome Android, Safari Mac, Safari IOS

https://addpipe.com/simple-recorderjs-demo/

I hope this helps somebody.

Categories
Cognito

How to manage machine user in AWS and Cognito Pools

Consumers

If you are buildg an app you will have two types of consumers.

  • User consumers
  • Machine Consumers

User consumers

Users consumers are human users.

Also called internal user.

These are the users of Your WebApp.

Users will authenticate against a Cognito User pool using Authorization code grant.

Machine User Consumer

These are bots or programatic clients.

These users are also called external users.

They will consume the API in a different way.

Machine users are different from users, they shouldnt access a browser to authenticate themselves and also they cant confirm via email when the credentials are created or restored.

From the AWS official documentation

See Client Credentials Grant

The steps for the process are as follows:

  1. An app makes a POST request to https://AUTH_DOMAIN/oauth2/token, and specifies the following parameters:
    • grant_type – Set to “client_credentials” for this grant type.
    • client_id – The ID for the desired user pool app client.
    • scope – A space-separated list of scopes to request for the generated access token.
    In order to indicate that the app is authorized to make the request, the Authorization header for this request is set as “Basic BASE64(CLIENT_ID:CLIENT_SECRET)“, where BASE64(CLIENT_ID:CLIENT_SECRET) is the base64 representation of the app client ID and app client secret, concatenated with a colon.
  2. The Amazon Cognito authorization server returns a JSON object with the following keys:
    • access_token – A valid user pool access token.
    • expires_in – The length of time (in seconds) that the provided access token is valid for.
    • token_type – Set to ” Bearer“.
    Note that, for this grant type, an ID token and a refresh token aren’t returned.
  3. The app uses the access token to make requests to an associated resource server.
  4. The resource server validates the received token and, if everything checks out, executes the request from the app.

The following diagram illustrates the steps used in a client credentials grant:

Resource Server

To be able to configure a client settings to use the client credentials flow it is necessary to create a resource server which controls the access level of the machine user. You can add several.

Example of getting a token:

var axios = require('axios');
var qs = require('qs');
var data = qs.stringify({
 'grant_type': 'client_credentials',
'client_id': 'someid',
'client_secret': 'somecredential',
'scope': 'https://your.apidomain.com/somestage/external/api.readwrite' 
});
var config = {
  method: 'post',
  url: 'https://your.userpool.domain/oauth2/token',
  headers: { 
    'Content-Type': 'application/x-www-form-urlencoded' // this is important
  },
  data : data
};

axios(config)
.then(function (response) {
  console.log(JSON.stringify(response.data));
})
.catch(function (error) {
  console.log(error);
});

Example on how to verify the token

var jwt = require('jsonwebtoken');
var jwkToPem = require('jwk-to-pem');
var token = "sometoken";
var keys = [] // the content of the keys key of https://cognito-idp.<region>.amazonaws.com/<user-pool-id>/.well-known/jwks.json
function validate(token, keys) {
    let pems = {};
    // console.log('antes del for', keys.length);
    for(let i = 0; i < keys.length; i++) {
        //Convert each key to PEM
        let key_id = keys[i].kid;
        let modulus = keys[i].n;
        let exponent = keys[i].e;
        let key_type = keys[i].kty;
        let jwk = { kty: key_type, n: modulus, e: exponent};
        let pem = jwkToPem(jwk);
        // console.log('key_id', key_id);
        pems[key_id] = pem;
    }
    console.log('aaaa');
    //validate the token
    const decodedJwt = jwt.decode(token, {complete: true});
    if (!decodedJwt) {
        // console.log("Not a valid JWT token");
        return false;
    }


    const kid = decodedJwt.header.kid;
    const pem = pems[kid];
    if (!pem) {
        // console.log('Invalid token');
        return false;
    }


    jwt.verify(token, pem, { algorithms: ['RS256'] }, function(err, decodedToken) {
        console.log('decoded', decodedToken);
    });

}

validate(token, keys);

Usage Plans

As our application grows we will require to measure the usage at least for the external users, the machine users.

To achieve this AWS offers a service called Usage Plans within Api Gateway.

A usage plan can hold several api keys, there should be an api key per client.

Note: API key values must be unique. If you try to create two API keys with different names and the same value, API Gateway considers them to be the same API key.

Api Gateway will read an x-api-key header then it will check if the intent does not exeed the limits defined in the usage plan and then will save the Api Consumption intent, if the limits have been reached it will deny the access.

What are usage plans and API keys?

usage plan specifies who can access one or more deployed API stages and methods—and also how much and how fast they can access them. The plan uses API keys to identify API clients and meters access to the associated API stages for each key. It also lets you configure throttling limits and quota limits that are enforced on individual client API keys.

Best practices for API keys and usage plans

The following are suggested best practices to follow when using API keys and usage plans.

  • Don’t rely on API keys as your only means of authentication and authorization for your APIs. For one thing, if you have multiple APIs in a usage plan, a user with a valid API key for one API in that usage plan can access all APIs in that usage plan. Instead, use an IAM role, a Lambda authorizer, or an Amazon Cognito user pool.
  • If you’re using a developer portal to publish your APIs, note that all APIs in a given usage plan are subscribable, even if you haven’t made them visible to your customers.

A post explaining that cognito can handle machine users:

https://medium.com/faun/setting-up-a-machine-to-machine-authentication-system-with-amazon-cognito-4c8e2de41c2e

Official documentation for API Gateway usage plans

https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-api-usage-plans.html

Categories
Angular

How to debug Angular apps using the chrome dev tools

A lot of times I find myself trying to do some debugging in Angular, in this post I will share with you some of the most useful techniques I use to make this a more easy task.

The info method

This is a super simple one. In your component create an info() method that will be triggered by a button in the html.

You can see a full example here:

https://stackblitz.com/edit/angular-ivy-mxyvj6?embed=1&file=src/app/app.component.ts

The technique is rudimentary but it is good enough, you can check the state of your component at any point.

Breakpoints + debugger;

This is my recommended way to go. As a developer you need to have tools for debugging and if you are a front dev you need to know how to use your browser developer tools.

Most of the time you know where the bug could be, but if you dont you need to find the first part of the code that could be related to the bug and add a breakpoint there.

In your code, instead of using console.log(variable) use debugger;

debugger; // put this BEFORE the buggy code 
const myVariable = 'some';
// ... more code e.g. a for loop with a bug

Open your browser and refresh the page. If all went ok you should see the developer tools oppened. just there. Now add some breakpoints to start debugging.

The ng.probe (ng global variable)

Thanks to the video below I found this other way to debug:

Angular exposes the ng global variable at a window level.

There are some usful methods that you can use by passing an HTML Element.

Some of the methods are:

  • ng.getComponent
  • ng.getDirectives
  • ng.getListeners
  • ng.applyChanges
  • ng.getOwningComponent
  • ng.getContext
  • ng.getRootComponents
  • ng.getInjector
// example
// Get more info of hat $0 means -> https://developers.google.com/web/tools/chrome-devtools/console/utilities#dom
let component = ng.getComponent($0);
console.log(component);
component.someVal = 5;
ng.applyChanges($0) // will apply the changes

Categories
Gutenberg

How to tweak an existing gutenberg block

This page sumarizes the process https://developer.wordpress.org/block-editor/developers/filters/block-filters/

Categories
Code Quality

How to use semantic release

We have a wordpress-theme and we want to use @semantic-release package to build versions of it using a Gitlab CI/CD, after creating the release we want to push the new version to the composer registry within Gitlab

Install Dependencies

npm i @semantic-release/changelog \
	@semantic-release/commit-analyzer \
	@semantic-release/exec \
	@semantic-release/git \
	@semantic-release/npm \
	@semantic-release/release-notes-generator \
        @semantic-release/gitlab

Note: Change @semantic-release/gitlab with @semantic-release/github when necessary

Configure your .gitlab-ci.yml

stages:
  - release
  - deploy

release:
  image: node:12-buster-slim
  stage: release
  variables:
    GITLAB_TOKEN: $GITLAB_TOKEN
  before_script:
    - apt-get update && apt-get install -y --no-install-recommends git-core ca-certificates
  script:
    - npm ci && npx semantic-release
  only:
    refs:
      - master
      - beta
      - alpha
    variables:
      - $CI_COMMIT_MESSAGE !~ /skip release/

deploy:
  stage: deploy
  only:
    - tags
  script:
    - 'curl --header "Job-Token: $CI_JOB_TOKEN" --data tag=$CI_COMMIT_TAG "https://gitlab.com/api/v4/projects/$CI_PROJECT_ID/packages/composer"'

We need to create a configuration file

// release.config.js
module.exports = {
    "plugins": [
        "@semantic-release/commit-analyzer",
        "@semantic-release/release-notes-generator",
        "@semantic-release/changelog",
        ["@semantic-release/npm", {
            "tarballDir": "release",
            "npmPublish": false
        }],
        ["@semantic-release/exec", {
            "prepareCmd": "bash scripts/release.sh ${nextRelease.version}",
        }],
        "@semantic-release/gitlab",
        ["@semantic-release/git", {
            "assets": ["CHANGELOG.md", "package-lock.json", "package.json", "style.css"],
            "message": "chore(release): ${nextRelease.version} [skip release]\n\n${nextRelease.notes}"
        }]
    ],
    "preset": "angular",
    "tagFormat": "${version}"
}

And create a release.sh file that will be executed to change the version in your custom files

# scripts/release.sh

export PATH="./node_modules/.bin:$PATH"

TO="Version:        "
VER=$1
TO_VER="$TO$VER"
sed -i "s/Version:\(.*\)/$TO_VER/" "style.css"
Categories
Knowledge Base

PHP Environment Variables

If your curious like me you will now this post explains how this works.

POST URL: https://mattallan.me/posts/how-php-environment-variables-actually-work/

Categories
Wordpress Code

How to create a Gutenberg Block Easily

Blocks are the new thing in the wordpress world, and for a good reason! they are super performant and the enable the possibility to do anything you can imagine.

Now imagine that you want to create a plugin that register a new block, and you also want to use ESNext.

In the official documentation of wordpress you can find this post.

Show me the code:

npx @wordpress/create-block todo-list
cd todo-list
npm start

I hope this helps someone :).

Categories
Linux

How to install PHP 7.4 in Ubuntu 18.04

sudo apt-get update
sudo apt -y install software-properties-common
sudo add-apt-repository ppa:ondrej/php
sudo apt-get update

sudo apt -y install php7.4

# install the packages you want
sudo apt-get install -y php7.4-{intl,mbstring,gd,zip,pgsql,xsl,curl,fpm}

sudo apt-get install -y php-{amqp,redis}

# Disable apache
sudo systemctl disable --now apache2 

Categories
Wordpress Code

How to setup a wordpress site with Woocommerce using docker compose and xdebug in minutes

Follow this steps except for the commands section:

How to setup a wordpress multisite with docker compose and xdebug in minutes

Instead run this commands:

# create a templates directory
mkdir templates

# create a wp directory
mkdir wp

# move .htaccess file to template dir
mv .htaccess templates

# start docker containers
docker-compose up -d

docker-compose run --rm cli core install \
  --url=http://localhost \
  --title="test site" \
  --admin_user="admin" \
  --admin_password="admin" \
  --admin_email="example@example.com" \
  --skip-email

# to be able to update core we need write permissions
sudo mkdir -p wp/wp-content/uploads && sudo chmod -R 777 wp/wp-content/uploads
sudo mkdir -p wp/wp-content/upgrade && sudo chmod -R 777 wp/wp-content/upgrade

# install last version
docker-compose run --rm cli core update

# Only if you want to install specific version
docker-compose run --rm cli core update --version=5.4.2

Add woocommerce

# install woocommerce
docker-compose run --rm cli plugin install woocommerce --activate

# update woocommerce
docker-compose run --rm cli plugin update woocommerce

Install Storefront Theme

# install theme
docker-compose run --rm cli theme install storefront --activate

# update theme
docker-compose run --rm cli theme update storefront

Setup Woocommerce

Since last versions you can setup your store by using the GUI.

If you want to do it manually

# setup Woo
docker-compose run --rm cli post create --post_title='Home' \
    --post_type=page \
    --post_status=publish \
    | awk '{ print $NF }' | grep -Eo '[0-9]+' | read page_id

docker-compose run --rm cli option update page_on_front $(echo "$page_id")
docker-compose run --rm cli option update show_on_front page # or posts

docker-compose run --rm cli post create --post_title='Webshop' \
    --post_type=page \
    --post_status=publish \
    | awk '{ print $NF }' | grep -Eo '[0-9]+' | read webshop_id

docker-compose run --rm cli option update woocommerce_shop_page_id $(echo "$webshop_id")

Add some dummy data:

sudo chmod -R 777 wp/wp-content/plugins/woocommerce/sample-data

Then follow this:

https://docs.woocommerce.com/document/importing-woocommerce-sample-data/

Categories
Javascript

How to listen to changes in the DOM – An intro to Mutation Observer

Today I faced an issue in one of the developments I work on. We have a form with an input radio and, for some reason, one of the choices was disabled.

I inspected the source html to check if the disabled attribute was being set from the server but it wasn’t. At this point I knew that some JS was causing the issue but, how to determine which script was doing that.

Mutation Observer to the rescue:

The MutationObserver is part of the Web Api of the DOM.

It has very good support fot the majority of browsers, see: canIuse.

The MutationObserver interface provides the ability to watch for changes being made to the DOM tree. It is designed as a replacement for the older Mutation Events feature, which was part of the DOM3 Events specification.

https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver

How to listen to the changes made to an element?

var element = document.querySelector('#myId');
    setTimeout(function() {
        element.setAttribute('data-text', 'whatever');
    }, 5000)

var observer = new MutationObserver(function(mutations) {
        mutations.forEach(function(mutation) {
            if (mutation.type == "attributes" && mutation.attributeName === 'disabled') {
                console.log("attributes changed", mutation);debugger;
            }
        });
    });

    observer.observe(element, {
        attributes: true //configure it to listen to attribute changes
    });

The snipped above will make the debugger to stop just after the change is made.

Once you are in the debugger you can see the callstack and see the chain of events that triggered the change.

I was able to find the solution.

I hope this helps someone else.