-
PG docs, part 6. SSL
(This is a new documentation chapter from the PG project.)
ToC
In this chapter:
The recent update of PG introduces SSL support. Install the newest version of PG as follows:
Lein:
[com.github.igrishaev/pg-client "0.1.8"] [com.github.igrishaev/pg-ssl "0.1.8"] ;; optional, for a custom SSL context
Deps:
{com.github.igrishaev/pg-client {:mvn/version "0.1.8"} com.github.igrishaev/pg-ssl {:mvn/version "0.1.8"}}
Setup
The are two ways to set up an SSL connection to the database. The first, and simple, is to set the
:ssl?
boolean flag to true and just connect:{:host "some.cloud.host.com" :port 5432 :ssl? true ...}
In this case, the entire SSL pipeline is held by Java. It tries to find the corresponding keys and certificates using the standard KeyStore and TrustStore which you configure on your own.
The second and more flexible way is to provide a custom SSL context to the connection map. It must be an instance of the
javax.net.ssl.SSLContext
class. Building such an instance from scratch is quite miserable though. To make your life easier, there is a thin wrapper on top of the great Less Awful SSL library that takes a map of certificates and keys and returns an instance ofSSLContext
. Since it requires a third-party library, it’s shipped as a standalone package pg-ssl. Add it to the project:[com.github.igrishaev/pg-client "0.1.8"] ;; lein ;; or {com.github.igrishaev/pg-ssl {:mvn/version "0.1.8"}} ;; deps
Now pass the
:ssl-context
parameter in addition to:ssl?
. It’s a map with the string keys:key-file
,:cert-file
, and:ca-cert-file
:(ns foo.bar (:require [pg.ssl :as ssl])) {:host "some.cloud.host.com" :port 5432 :ssl? true :ssl-context (ssl/context {:key-file "/path/to/client.key" :cert-file "/path/to/client.crt" :ca-cert-file "/path/to/root.crt"})}
The
:ca-cert-file
parameter might be missing if just:key-file
and:cert-file
are enough.(ssl/context {:key-file "/path/to/client.key" :cert-file "/path/to/client.crt"})
EDN Config
Often, we store the configuration in an EDN file. To declare SSL context there, prepend it with a reader tag called
#pg/ssl-context
:{:ssl? true :ssl-context #pg/ssl-context {:key-file ...}}
When reading EDN, pass that tag to the
:readers
map as follows:{'pg/ssl-context pg.ssl/ssl-context-reader}
The tag wraps the map with a function that builds the
SSLContext
from it.Some cloud platforms give you only the root certificate. In that case, generate both the client key and the the client certificate on your own using the root certificate. Something like:
umask u=rw,go= && openssl req -days 365 -new -nodes -subj '/C=US/ST=Test/L=Test/O=Personal/OU=Personal/emailAddress=test@test.com/CN=test' -keyout client.key -out client.csr umask u=rw,go= && openssl x509 -days 365 -req -CAcreateserial -in client.csr -CA root.crt -CAkey server.key -out client.crt
When generating the certificates, pay attention to the
CN
field which is “test” in our case. In terms of PostgreSQL, it should match the database user. Different users will have different certificates.Testing
The SSL functionality is difficult to test in Docker so I’ve got to run a native instance. Here is a brief setup.
- In
postgresql.conf
, enable thessl
parameter and specify paths to the files:
ssl=on ssl_cert_file='/Users/ivan/work/pg/certs/server.crt' ssl_key_file='/Users/ivan/work/pg/certs/server.key' ssl_ca_file = '/Users/ivan/work/pg/certs/root.crt'
- In
pg_hba.conf
, enable the “cert” validation type for SSL connections:
hostssl all all all cert
Finally, create a user with a name that matches the
CN
field:create user <CN-field> with password '******';
- In
-
SQL
Язык SQL — прекрасная вещь, пожалуй, одна из лучших, что мы имеем в айти. Научиться ему значит повысить свою квалификацию на голову. Бекендеров я бы вообще оценивал по одному критерию — насколько хорошо они работают с базой.
SQL выручал меня не только по работе. У нас в ЖК стоят шлагбаумы, и однажды я запросил логи, чтобы посмотреть, кто и когда и открывает. Мне скинули несколько страшных CSV. Разбирать их Экселе было адом, и я загнал в Постгрес и построил отчеты по всем мыслимым критериям.
Импорт:
COPY logs(time, account, type, ident, status, barrier) FROM '/Users/ivan/work/barriers/65_Ш6.csv' DELIMITER ';' CSV HEADER;
Статусы:
select distinct status from logs | status |--------------------------------------- | Добавлен | Отказ (пульт) | Отказ (нет в базе или ошибка кнопка) | Открыто (карта в базе) | Допуск (пульт) ...
Типы доступа:
select distinct type from logs | type |-------------- | Событие | Карта, метка | Звонок | Удаление ...
Общее число открываний в разрезе помещений:
select account, count(ident) as count from logs where account <> 'Нет в базе' and time > '2022-05-01 00:00:00' and status in ('Допуск (телефон)', 'Допуск (пульт)') and type in ('PP', 'Звонок') group by account order by count desc limit 50
Данные по конкретной квартире по дням:
select date_trunc('day', time) as day, count(ident) from logs where account = 'ООО "Рога и копыта"' and time > '2022-05-01 00:00:00' and status in ('Допуск (телефон)', 'Допуск (пульт)') and type in ('PP', 'Звонок') group by day order by day desc limit 50
Число телефонов и пультов на помещение:
select account, count(distinct ident) as amount from logs where account <> 'Нет в базе' and time > '2022-05-01 00:00:00' and status in ('Допуск (телефон)', 'Допуск (пульт)') group by account order by amount desc limit 100
Среднее число открываний в день:
select account, count(ident) / count(distinct date_trunc('day', time)) as per_day from logs where account <> 'Нет в базе' and time > '2022-05-01 00:00:00' and status in ('Допуск (телефон)', 'Допуск (пульт)') and type in ('PP', 'Звонок') group by account order by per_day desc limit 100
И еще штук десять подобных запросов. В итоге нашли несколько аномалий, с нарушителями был разговор.
Из недавнего: понадобилось считать рабочие часы по неделям. Что в Экселе, что Гугле это оказался адский ад, потому что тип
time
не переполняется. То есть если сложить 7 + 7 + 7 + 7 + 7 часов (пять рабочих дней), получим 11 часов, потому что 24 уйдут в перекрут. Просидел час, думая, как это решить, и так и не решил.Но выручил Постгрес! Его тип
time
тоже не поддерживает переполнение, но есть типinterval
, который прекрасно складывается сам с собой. Поэтому создаем таблицу с двумя колонками: дата и интервал:create table work (date date, hours interval);
Импорт:
\copy work from /Users/ivan/Downloads/foobar.csv with (format csv);
Удаляем пустые интервалы:
delete from work where hours is null;
Всего часов:
select sum(hours) from work;
Отчет по неделям:
select date_trunc('week', date) as week, sum(hours) from work group by week order by week;
И все это — не выходя из консоли
psql
. Представьте, какой гемор был бы построить это в Экселе, Гугле или даже на языке программирования вроде Питона. Там с одним только парсингом дат и времени наешься, а тут все из коробки.Можно сбросить все отчеты в CSV одной командой, чтобы пересохранить в Excel и отправить кому-то по работе.
Словом, одно из немногих утешений сегодня — это SQL/Postgres. Надежный как скала, полезный, простой и востребованный.
-
Выпадашки на StackOverflow
Я как-то уже писал: нам не везет с дизайнерами. Всякие Гуглы и StackOverflow берут ребят с выпадашечным мышлением. Каждый раз, чтобы донести информацию до пользователя, дизайнер ставит выпадашку. При этом все равно, что выпадашка Васи наползает на выпадашку Пети. Это не его проблема, он добавил, а остальное его не касается.
Сегодняшняя страница Stack Overflow как я ее вижу. Слой с бессмысленным текстом наползает на какое-то дерьмо про искусственный интеллект. Выпадашка на выпадашке. Интересно, как в SO устроена работа дизайнеров и контроль качества? Это же Провал Провалыч, и причина одна — несогласованность между дизайнерами.
Нельзя так.
-
Слак устарел
Этим утром Слак порадовал вдвойне: сообщил, что устарел не только он, но и моя операционная система.
Вообще, радует эта формулировка: программа устарела. Лежат себе не диске байты, работают, двигают другие байты, и вдруг раз — устарели. Срок годности вышел, что ли? Или ноут долго на солнце стоял?
Всё еще надеясь на лучшее, скачал последний Слак, но увы — программа не запускается, нужна версия Мака не ниже чего-то там.
“Устаревание” программы ещё можно понять: ленивые жопы не хотят поддерживать то, что сами же написали. Плохо, но не критично. А вот с операционкой я не пойму. Во-первых, ваш Слак — это Хром и Node.js, что там может требовать новой операционки? Обычный Хром не требует обновления Мака, а вы что, какие-то особенные?
Во-вторых, допускаю, что в новой операционке есть какая-то лабуда, но вопрос — она действительно нужна в повседневной работе? Без неё не напишешь сообщение и не позвонишь? А как раньше без неё жили?
В-третьих, обновление операционки — это простой в работе в лучшем случае на полдня. Один шанс из ста, что все программы продолжат работу и пакеты не слетят. Вот представь, разработчик Слаки, ты приходишь на работу и хоба! — ничего не можешь сделать, пока не обновишь операционку. Таски не двигаешь, часы не трекаешь, на митинги не ходишь.
Не нравится? А тебе, значит, можно так делать — отрубить мне программу для общения по работе? Ты хотя бы представил мысленно, что сделает пользователь, когда увидит это сообщение?
Эх, ребята из Слаки! Откуда вас понабрали? Нет у вас ни этики, ни эмпатии, ни мозгов.
-
Оплата в Сбере
Кто пользуется Сбером, объясните, пожалуйста. Почему, чтобы заплатить за музыкалку, нужно пять экранов? Не один, не два, а пять? При этом каждый экран повторяет прошлый на 90%: это реквизиты, всякие КБК, ОКТМО и прочая хрень, интересная только бухгалтеру.
Вот я накидал скриншотов:
Первый экран — реквизиты и кнопка “продолжить”.
Второй экран — те же реквизиты и выбор документа.
Третий экран — опять реквизиты(!) и серия/номер документа.
Четвёртый экран — РЕКВИЗИТЫ и сумма платежа.
Пятый экран — РЕКВИЗИТЫ и выбор счета.
Та же беда с коммуналкой, всякими карате, рисовалками и прочее. В коммуналке, кстати, еще +3 экрана на ввод показаний с счётчиков.
Не многовато ли?
-
Извинения за неудобства
Два года назад я писал о правилах работы с почтой. Среди прочего там есть важный пункт: если вы отправили плохое письмо, то нельзя слать вдогонку правочки и просьбы посмотреть в других письмах. Нужно отправить новое письмо, в котором все правильно.
Конечно, нашему “ПАО ТНС Энерго Воронеж” (что за бредовое название) не знакомы эти правила. Что с них взять? Но давайте поучимся чужих ошибках.
В этом месяце ребята лоханулись: разослали квитанции с битыми QR-кодами. Ну, бывает, вдруг Node.js-программист обновил package.json? Важно то, что с этим сделает руководство. А оно пишет: берите коды из прошлых писем и примите извинения. Но в кодах зашито назначение платежа, и Сбербанк не дает его поменять. А платеж по реквизитам это просто ад: у “ПАО ТНС” сто филиалов, и какой выбрать — неизвестно.
Конечно, надо было сгенерить новые квитанции и разослать вместо сломанных. Простое правило: кто накосячил, тот и исправляет.
Повторюсь, к ПАО ТНС Энерго Воронеж претензий особо нет. Большая фирма, бюрократия, и ничего кроме “примите извинения” они не могут. Для нас главное — не допустить такого в своей работе.
-
Ввод по маске
Каждый мамкин фронтендер знает: если в форме есть поле телефона, ставим плагин jQuery под названием Masked Input и не паримся. С ним нельзя ввести буквы, скобки, дефисы и прочий мусор.
Но мамкин фронтендер не знает: если вставить в поле “89623289677” (скажем, из Экселя или менеджера паролей), то всратый плагин поместит восьмерку после +7 и отбросит последнюю цифру. Результат будет как на второй картинке.
То есть всего-то испортили данные, но никого это не волнует. Подумаешь, не придет смс, не дозвонится курьер, не выдадут посылку. Фронтендеру не до этих мелочей.
Недаром говорят: благие намерения ведут в ад. Хотели сделать удобно на фронте, в итоге добавили баг.
-
Ошибки
Главная беда этой нашей айтишечки — сообщения об ошибках, не связанные с их устранением. Примеров можно найти миллион, но вот вам один.
Собираю одну фигню в докере, и команда
apt-get update
падает с сообщением, что репозиторий не подписан:The repository 'http://archive.ubuntu.com/ubuntu focal InRelease' is not signed.
При этом на другом ноуте все собирается как надо.
Оказалось, что это мулька самого Докера, и лечится она командой prune:
docker image prune -f docker container prune -f
Очевидно, без гугла и SO эту проблему не решить в принципе.
В современной айтишке много абстракций, и каждая из них не знает о другой. Отсюда эти уродские сообщения: абстракция А считает что-то неподписанным, потому что в Б нет места. А не находит файлы, потому что они не смонтированы в Б. А валится, потому что в Б другая локаль или кодировка по умлочанию.
Задача хорошего программиста в том, чтобы давать понятные сообщения об ошибках. Наверное, вас тоже бесило, когда Java говорит:
port is already in use
. Блин, какой порт? У меня их десять в проекте, тяжело добавить цифру в сообщение?Или тот же Вим. По всему миру люди страдают, не знают как из него выйти. Вопрос на SO набрал миллион просмотров и растет дальше. И что делают разработчики вима? Вместо того, чтобы добавить бар с действиями как в Nano, объясняют, что пользователи тупые.
Напоминает мост в Питере со знаком “Газель не проедет”, где разбились сто Газелей. Вместо того, чтобы порвать на тряпки мэра и начальника ГИБДД, ставят знаки и постят картинки в Контакте.
То же самое происходит у нас. Вместо понятного сообщения мы ждем, что его предоставит вышестоящий слой. Но это бессмысленно: не сделаем мы — не сделает никто.
-
Фаервол
Лучшая вещь, что случилась со мной в последнее время — это установка фаервола на всех маках. Вот как это произошло.
Когда-то я жаловался, что программы без спроса лезут в интернет обновляться. Открыл Саблайм — а он показывает модалку, что вышла новая версия. Открыл то, другое, а там то же самое: скачай-обновись.
Идея как это победить простая — нужно отобрать у программы доступ в интернет. Я пошел настраивать встроенный фаервол, но оказалось, он убогий: закрывает только входящие соединения, а исходящие не трогает. В результате даже если добавить в список программу, она спокойно идет в сеть.
Путем гугления нашел программу Lulu. Хоть название и затасканное, программа просто супер: удобный интерфейс и настройка. Lulu делит программы на группы: родные Эпла, уже установленные и другие. Можно включать и выключать целые группы, а можно по отдельности. Правила формируются в разрезе программ, папок, регулярных выражений.
Можно настроить гибкий контроль по урлам. Например, дать программе доступ к хосту
sync.blabla.com
для синхронизации, но запретить обновления по хостуupdate.blabla.com
.Можно дать временный доступ по номеру процесса. Когда программа запуститься в cледующий раз, номер будет другим, и Lulu спросит опять.
Фаервол может работать в интерактивном режиме, показывая диалог на события, которых нет в правилах, а может молча разрешать или разрешать все, что происходит.
Для себя я сделал так: удалил все правила, кроме Эпловских, а затем настраивал вручную. Запретил все программы Адоба, офисного пакета, всякие редакторы вроде Саблайма — их задача работать с текстом, а не лазить за обновлениями. Запретил обновки для Dash, программы оффлайн-документации, и много что другое.
На старом ноуте обнаружил несколько вирусов. Это программы с названиями типа robstoaf, прописанные в автозагрузке. Время от времени они ходят в сеть на левые хосты. Возможно, крадут историю браузеров или это ботнет. Так что не слушайте байки про то, что под Мак вирусов нет.
Что немаловажно, Lulu запрашивает подтверждение, когда левая программа хочет добавить себя в автозагрузку. Всякое дерьмо вроде Zoom, MS Teams прописывают себя там, и в итоге запускаются в фоне, даже если вы не просили. Больше этого беспредела нет.
Программа так понравилась, что я хотел перевести автору денег, долларов сто. Хотел скинуть с Пейпала, а у него только патреон — то есть регистрируйся, вводи персональные данные, карту, подтверждай — извините, нет.
Кроме Lulu, у автора есть смежные утилиты для безопасности, например монитор клавиатуры на предмет прослушки и что-то еще второстепенное.
Словом, не знаю как жить без Lulu: теперь это первая программа, которую я ставлю на Мак. Как раз недавно ставил ее на свежий ноут. Неистово рекомендую!
Картинки, описание и загрузка здесь: https://objective-see.org/products/lulu.html
-
CSS is Awesome
Все видели картинку, где текст из заголовка не влезает в рамку. Ха-ха, кривой CSS, технологии, которые мы заслужили (с).
Хорошо, посмеялись, а теперь вопрос: как должно быть?
Представим, вы всемогущий бог, все браузеры мира под вашим контролем. Щелкните пальцами — и у всех эта картинка покажется так, как вы скажете. Что предпочтете?
Проблема в том, что на картинке типичное UB — undefined behaviour, неопределенные поведение. В литровую банку пытаются налить два литра воды. Простыми словами, впихнуть невпихуемое. Это невозможно, поэтому кто-то окажется в проигрыше.
На самом деле на картинке все правильно: при всем уродстве мы смогли прочитать текст. Если бы он был обрезан, мы бы его не увидели, то есть не получили бы вообще ничего. А так получили хотя бы часть, пусть и фраза там бестолковая.
Эту картинку я считаю крайне неудачной. Кто-то хотел пошутить, что CSS глючный, но выбрал плохой пример: выставил дурацкие ограничения (малую рамку и огромный шрифт) и смотрит, как программа не справляется. А она, между прочим, справилась — донесла до нас текст.
Так что шутка на троечку.