Restore files from backup with restic

I had a misconfiguration in my nginx deployed with ansible. I couldn't remember what was the correct configuration. I had to restore the /etc/nginx/sites-enabled directory from the backup.

Fortunately or unfortunately I don't need to do this often, so I had to look up how to do it.

vim.lsp.buf.execute_command is deprececated in favor of clint:exec_cmd

The vim.lsp.buf.execute_command is used to execute a command on the LSP server for a specific buffer.

Neovim will deprecate (see :checkhealt vim.deprecated) vim.lsp.buf.execute_command in favor of clint:exec_cmd in the future. For example to the typescript organizeImport should be changed from:

local function on_ts_ls_attach(client, bufnr)
    vim.keymap.set("n", "<leader>o",
        "<cmd>lua vim.lsp.buf.execute_command({command = \"_typescript.organizeImports\", arguments = {vim.fn.expand(\"%:p\")}})<cr>",
    { noremap = true, silent = true, buffer = bufnr })
end

to

local function on_ts_ls_attach(client, bufnr)
    vim.keymap.set("n", "<leader>o", function
        return client:exec_cmd({
            command = "_typescript.organizeImports",
            arguments = { vim.api.nvim_buf_get_name(bufnr) }
        }, { bufnr = bufnr })
    end, { noremap = true, silent = true, buffer = bufnr })
end

If also think that the new format is more readable and more flexible.

i3tree - view the i3wm window tree

An utility tool I created for i3wm to visualize the the tree of windows in the current i3 session.

i3tree

i3tree example

zsh argument completion

Some help how to define arguments for a zsh completion

#compdef the_command
#autoload

# basic subcommands, like docker run
local -a _1st_arguments
_1st_arguments=(
    'run'
    'exec'
    'rm'
)

# function to parse the subcommands
_the_command_subcommand() {

    case "$words[1]" in
        'run')
            _alternative "the_command_run:the_command run:"
            return
            ;;
        'exec')
            _arguments "(-t)-t[some description]"
            return
            ;;
    esac
}

_arguments -C '*:: :->subcmds'
if (( CURRENT == 1 ));then
    _describe -t commands "the_command command" _1st_arguments
    return
fi

_the_command_subcommand

A simple option with an alternative short name and with description. It also expects a value after the option.

_arguments \
       '(-o --option-name)'{-o,--option-name}'[Describe what the option is good for]:option name:' \
       && return 0

Example:

the_command -o foobar
# or
the_command --option-name freetext

A simple option with an alternative short name and with description, and provide a fix list as the value of the options

_arguments \
       '(-o --option-name)'{-o,--option-name}'[Describe what the option is good for]:option name:(foo bar baz)' \
       && return 0

Example:

the_command -o foo
# or
the_command --option-name bar

A simple option with an alternative short name and with description, and a shell script which generates the possible values

_arguments \
       '(-o --option-name)'{-o,--option-name}'[Describe what the option is good for]:option name:($(the-shell-script))' \
       && return 0

A simple option with an alternative short name and with description, and provide a function which can generate the available options

_command_option_values() {
       compadd $(shell script where every word is an completion string)
}

_arguments \
       '(-o --option-name)'{-o,--option-name}'[Describe what the option is good for]:option name:_command_option_values' \
       && return 0

TIL exclude directories in grep and ripgrep

$ man grep
 --exclude=GLOB
        Skip any command-line file with a name suffix that matches the
        pattern GLOB, using wildcard matching; a name suffix is either
        the whole name, or a trailing part that starts with a non-slash
        character immediately after a slash (/) in the name.  When
        searching recursively, skip any subfile whose base name matches
        GLOB; the base name is the part after the last slash.  A pattern
        can use *, ?, and [...] as wildcards, and \ to quote a wildcard
        or backslash character literally.
 --exclude-from=FILE
        Skip files whose base name matches any of the file-name globs
        read from FILE (using wildcard matching as described under
        --exclude).
 --exclude-dir=GLOB
        Skip any command-line directory with a name suffix that matches
        the pattern GLOB.  When searching recursively, skip any
        subdirectory whose base name matches GLOB.  Ignore any redundant
        trailing slashes in GLOB.

So to exclude a directory with the name test for example:

grep -r --exclude-dir=test something

I expected that ripgrep has similar options, but in that case it doesn't.

rg --help

-g, --glob <GLOB>... Include or exclude files and directories for searching that match the given glob. This always overrides any other ignore logic. Multiple glob flags may be used. Globbing rules match .gitignore globs. Precede a glob with a ! to exclude it.

So use the --glob option for that:

rg --glob='^test/' something

TIL: How to find if a number is power of 2

Take the number and take the number - 1, perform a binary and (&) operation on the two numbers. If the result is 0 then the number is the power of 2.

number != 0 && (number & (number - 1)) == 0

Let's see some numbers which are power of 2 and their binary representation (padded with 0 for easer reading):

2  00010
4  00100
8  01000
16 10000

Let's see the numbers - 1 and their binary representation (padded with 0 for easer reading):

1  00001
3  00011
7  00111
15 01111

An & (and) operation will give 1 for a digit if both of digits are 1.

For example

4: 00100
3: 00011
--------
&: 00000

Which will end up in 0, because a number which is the power of 2 only the first digit will be 1 and when we substitute 1 from the same number, we will get a number where all digits are 1 (except the first of the original number). So in the and we will &-ing 0 to 1 in every digit.

But on the other hand, if we substitute 1 from a non-power of 2, at least the first digit will always be 1 for both numbers, so &-ing them will always return a non 0 number:

3: 00011
2: 00010
--------
&: 00010

Which is 2

6: 00110
5: 00101
--------
&: 00100

Which is 4, so it's definetly not 0. So they are not power of 2.

Originally I found it in the Plan9 source code

TIL: RBL DNS Query

Today I learned how to query if an address is on an rbl list.

Reverse the octets of the IP address: 1.2.3.4 becomes 4.3.2.1 Then append the domain name given by the DNSBL service (dnsbl.example.com) Then look up of this domain's A record.

host 4.3.2.1.dnsbl.example.com

If the IP is listed, it will return an address, or it will return an NXDOMAIN if the IP is not listed. The exact meaning of the address can be different at each provider.

Based on the knowledge I created a small program to check if a address is listed on a blacklist: DNSBL Check

From Wikipedia

A service to share secrets securely

I built a simple program to share sensitive data securely

In the last few months I've been working on a service, which helps to share data securely. The service called sekret.link.

I wanted to practice Golang and Angular and it was a good candidate for that.

Imagine that a new colleague joined to the company, there are bunch of things she will need to have access, like WiFi, database, internal site or whatever. You know the password or you generate the password and you will need to send it to her on Slack or e-mail. You can send it as a simple message, but that will mean that Slack or her e-mail provider can read the information. What is worse that then this information won't be deleted automatically. If someone breaks into her account now can discover these secret informations and the company will be in a pretty bad situation.

The service what I created tries to help on these issues. You send the sensitive information to the service and it will store it encrypted. It returns an URL which can be used to decrypt the information. After the secret has been read it also destroyed and there is no way to restore it.

No one else will have access to the decryption key. It isn't saved, it isn't logged can not be guessed. The web client (which is visible at https://sekret.link) is even encrypting the data before sending it, so the unencrypted data never left your browser.

As the main purpose of the application is to protect privacy and keep secret hidden from unauthorized third parties I made it as secure as possible:

  • The decryption key is random and long enough to be secure
  • The decryption key is only known by the user who created the secret
  • No external scripts included to the site
  • No tracking scripts included to the site, it's not tracking even internally
  • It doesn't use any cookies
  • Both the frontend application and the server code are Open Source
  • It has an API, so if you don't trust in the frontend application you can create your own

There were (are) several challenges I needed to solve. I wanted to make it secure as possible, as usable as possible and as developer friendly as possible.

The very first version had no UI, and I only wanted to be able to use it with curl. For example curl -d 'secret message' https://sekret.link/api/ will return the link what you can send to your friend right away. However, it's simple and good, already has one issue: many applications, like Slack and other services fetches the pasted URLs to create some kind of preview. It means two very bad things: this application will read the secret will also be destroyed, so the real recipient will not be able to read it. That's why I needed to create the frontend application.

I plan to write some more about the challenges, like how I utilized the go interfaces, how I got some hard time with the Angular routing. How I made it work when JavaScript is turned off in the browser and I have some other stories.

Footnote: the idea is not new, there are several other services like that, for example Privnote, what I used before I created this service.

Set default sound level of FiiO K1 on plug

FiiO K1 became very silent recently when you plug it in on Ubuntu for some reason.

To fix it add an UDEV rule:

/etc/udev/rules.d/71-fiio-k1.rules

SUBSYSTEMS=="usb", ACTION=="add|change", ATTRS{manufacturer}=="FiiO", ATTRS{product}=="FiiO USB DAC K1", RUN+="/home/ajnasz/bin/init-fiio-k1.sh"

And create the shelscript which set the volume whenever you plug the DAC:

/home/ajnasz/bin/init-fiio-k1.sh

#!/bin/sh

CARD_ID="$(aplay -l | grep "FiiO.*K1" | cut -d ' ' -f 2 | tr -d ':')"

if [ -z "$CARD_ID" ];then
    return
fi

amixer -c "$CARD_ID" sset PCM 90%

ThinkPad T510 Xorg NVidia config

To enable screen backlight brightness adjustment, create the following file and restart the X server