Автоматическое получение конфигов Openvpn для бесплатного VPN от vpnbook.com

Преамбула

Есть относительно неплохой бесплатный сервис VPN vpnbook.com, мы про него когда-то давно писали, а я одно время даже активно пользовался, пока меня не задолбали некоторые ограничения, и я не перешел на лучший и более надежный в плане безопасности Riseup, но в качестве резерва, почему бы не иметь и его? Заодно и знакомый попросил его настроить.
В общем, пошел я на сайт, а там все изменилось, появились и периодически добавляются новые сервера, старые подохли, в общем контора активно цветет и пахнет.

Так вот, на случай появления новых серверов, придется идти на сайт, скачивать конфиги, при необходимости добавлять свои параметры, и т.д. А зачем это каждый раз делать руками, если можно автоматизировать?

Описание задачи

1. Вытащить с сайта список конфигов
2. Скачать архивы конфигов на локальный компьютер и распаковать их
3. Автоматически добавить в конфиг дополнительные параметры, например изменить уровень script-security и добавить пользовательские скрипты, выполняющиеся при соединении и разрыве соединения с сервером, и т.д. Подробности тут или тут
4. Конфиги для каждого сервера поставляются в нескольких вариантах, для соединения по разным портам, например TCP 443, TCP 80, UDP 25000, UDP 53. Сервера различаются по странам. Соответственно, надо предусмотреть возможность выбора всех или определенных конфигов.

Дополнительные программы

Нам понадобится какой-нибудь парсер HTML. Я использую xidel, о котором недавно писал

Подготовительные действия

1. Добавляем в начало скрипта необходимые переменные:

VPNBOOKPAGE="https://www.vpnbook.com/"
WORKDIR="/tmp/vpnbook/"
UNPDIR="/tmp/vpnbook/unpack/"
HTMLFILE="vpnhtml.html"

Страница, с которой будем выдирать ссылки на архивы, рабочий каталог скрипта, каталог, куда будем распаковывать архивы и имя файла, под которым сохраним HTML-страницу сайта с нужными данными.

2. Предусматриваем возможность удалить каталог с распакованными конфигами (если пользователь запустит скрипт с ключом ):

if [[ "$1" == "-c" ]]; then
    echo "Cleaning  unpack directory..."
    rm -rf "$UNPDIR"
fi

3. Удаляем ранее сохраненный HTML-файл (иначе новые wget будет сохранять под именами vpnhtml.html.1, vpnhtml.html.2 и т.д.) и создаем рабочий каталог и каталог для распаковки архивов. Путь будет создан со всеми подкаталогами, если он ранее не существовал. Если каталог уже существовал, то никакой ошибки не будет.

rm "$WORKDIR$HTMLFILE"
mkdir -p "$WORKDIR"
mkdir -p "$UNPDIR"

Далее под катом

Скрипт целиком

На PasteBin
На GitHub

Отображение картинок в консоли Linux

Задумался тут, можно ли показать изображение в консоли Linux без использования X-Server’а. Ведь в современных Линуксах консоль, по большей части, только маскируются под текстовую, а на самом деле, с определенного этапа загрузки ОС, она вполне себе графическая, и фреймбуфер у них есть, и все прочее для отображения картинки. Шрифты же она отображает, причем не как в DOS, где в консоли никакого графического режима по умолчанию нет, и единственный шрифт 80×25 для VGA-режима и 40×25 для EGA (о-о-о-чень старые мониторы и видеочипы), ЕМНИС.

В Linux наоборот, надо еще пошаманить, чтобы сэмулировать режим VGA в «голой» консоли без иксов. Если не шаманить, то наоборот, может получиться как-то так:


Мелко, противно, нихрена не видно

Справедливости ради, в DOS есть и графические режимы, и даже софт для отображения картинок, но, фактически отображение будет не совсем «в консоли», программа должна будет переключить видеоадаптер в графический режим, и там уже сама как-то справляться с изображениями.

Вернемся к Linux. Итак, консоль вполне себе графическая, так есть ли софт? Как выяснилось, есть.

Называется программа FIM. Программа небольшая, поддерживает основные форматы (BMP, GIF, JPEG, png, tiff) и некоторые другие (PPhotoCD, ppm, XWD), а для остальных она пытается использовать ImageMagick. Программа основана на Fbi (framebuffer imageviewer — это нечто вроде печально известного Vim, только для работы с изображениями в консоли).

В зависимости от того, где она была запущена, программа использует разные механизмы отображения графики:
— если она выполняется в эмуляторе терминала под иксами, то использует библиотеку SDL или imlib2. Впрочем, в иксах, лично у меня, fim смухлевал. В том же самом терминале рисовать не стал, а создал отдельное окно.
— если запущена в «голой» консоли без иксов, использует консольный фреймбуфер
— и, что довольно забавно, если попытаться запустить ее на терминале, который графику не поддерживает (например, через PuTTY), то программа преобразует изображение в ASCII-арт, ну тут уж, что называется, как получится.

Установка

Для Debian/Ubuntu и подобных им дистрибутивов есть готовый пакет, для Slackware пришлось собирать из исходников, впрочем, у меня собралось с первого раза.

Запуск

fim <имя файла 1> [имя файла 2] [имя файла 3...] — для просмотра одного или нескольких файлов.

fim -R <каталог>, например, fim -R ~/Pictures/ — для просмотра изображений в каталоге.

Основные клавиши

n — следующий файл
p — предыдущий
+ — увеличить
— уменьшить
r — поворот
m — отзеркалить
f — отзеркалить и перевернуть вверх ногами
q, ESC — выход

На самом деле у утилиты довольно много возможностей, есть командный режим, как у Vim, в котором изображение можно редактировать, подробное описание всех возможностей — в мануале на официальном сайте.

Скриншоты


Котик в «голой» консоли


А вот в иксах он смухлевал, хотя котика нарисовал


Псевдографический котик в текстовом терминале. Довольно ничего получилось.

Ссылки

Официальный сайт
Исходники Копия
Мой пакет для Slackware

xidel, крохотный парсер HTML, XML, JSON

Преамбула

Понадобилось тут быстро и качественно выдрать из HTMLки ссылки и картинки.

Наткнулся на довольно интересный инструмент. Называется xidel, и умеет вытаскивать данные не только из HTML, но также из XML, CSS, JSON, в общем штука получается довольно универсальная. Еще один плюс — кросплатформенность. На сайте есть готовые бинарники под Windows, Linux, пакет для Debian. Все вышеперечисленное, что очень приятно, есть в версиях, как для x86, так и для x64. Также имеются версии для Android ARM и Mac OS 10.8. Открыт и исходный код. Утилита, что хорошо, маленькая, самая большая версия для Android — 2Мб, остальные еще меньше.

Брать исходный файл программа может, как из сохраненной на диск страницы, так и непосредственно с сайта.

Примеры использования

На самом деле, инструкция там довольно большая, покажу только самые простые вещи.

Выдираем все адреса ссылок с главной страницы:

xidel -s --extract "//a/@href" "http://tolik-punkoff.com"

Выдираем адреса изображений:

xidel -s --extract "//img/@src" "http://tolik-punkoff.com"

То же самое с сохраненной предварительно на диск страницей:

wget -P "/tmp" --default-page="test.html" --header="Content-type: text/html" "http://tolik-punkoff.com"

xidel -s --extract "//a/@href" "/tmp/test.html"

wget -P "/tmp" --default-page="test.html" --header="Content-type: text/html" "http://tolik-punkoff.com"

xidel -s --extract "//img/@src" "/tmp/test.html"

Результат


Скачать

На официальном сайте
Мой пакет для Slackware

NodeJS для Slackware 14.2

Ох и запарился я ее собирать… Не, собралась автоматом, просто долго. А готовые пакеты у них на сайте почему-то только под Linux x64. Поэтому, чтоб не пролюбить пакеты:

node-v10.16.1-i486.txz

node-v12.7.0-i486-1.txz

На всякий случай еще и исходники сохраню.

node-v12.7.0.tar.gz

Смешно, из-за нее не так давно умудрился уронить 12 слакварь, точнее Absolute Linux, который был на ней основан, вертелся-крутился года три и никого не трогал, так и перешел на 14-ую.

Использование переменных из bash-скрипта в sed

Преамбула

Вроде невелика проблема, а вопросы вызывает. Понятно, что вот так работать не будет:

VAR1="Nado naiti"
VAR2="Nado zamenit'"

sed 's/$VAR1/$VAR2'

т.к. одинарные кавычки в команде sed все закэранируют, и sed будет искать черти что и с боку бантик.

Решение

1. Поменять одинарные кавычки на двойные.
2. Поменять sed’овский разделитель слэш (/) на что-нибудь другое, например на знак % (Уникальность программы sed в том, что она позволяет использовать любой разделитель, например знак подчеркивания)

VAR1="Nado naiti"
VAR2="Nado zamenit'"

sed "s%$VAR1%$VAR2"

Примеры

Добавление строки в начало файла из предыдущей заметки. Строка содержится в переменной $FIRSTSTRING:

sed -i -e "1 s%^%$FIRSTSTRING\n%" file.txt

Замена строки, начинающейся с любого количества пробелов и/или со строки из переменной $START на строку, содержащуюся в переменной $REPLACE:

sed -i "s%^ *$START.*%$REPLACE%" file.txt

NSIS: продолжение установки после перезагрузки.

Преамбула

Например, у нас есть софтина, которая в процессе своей установки требует перезагрузку, после чего доустанавливается. Например, софт устанавливает свой драйвер, обновление, или же регистрирует системный сервис. Как реализовать инсталлятор для такой программы?

Изначально я хотел обойтись параметрами командной строки, добавляемыми при запуске установщика, но с ними произошла жопа, поэтому будем действовать более надежными методами.

Алгоритм

0. Проверяем наличие уникального ключа Реестра, сигнализирующего о том, что надо выполнить вторую часть установки (после перезагрузки):

DetailPrint "Read After Reboot flag..."
ReadRegStr $R0 HKCU "Software\Microsoft\Windows\CurrentVersion\"
"${APPNAME}_afterreboot"
StrCmp "$R0" "1" AfterReboot

1. Производим все действия, которые необходимо произвести до перезагрузки (устанавливаем драйвера, регистрируем DLL и т.д.)
2. Записываем в однократную автозагрузку (ключ Реестра RunOnce) наш инсталлятор, путь к exe файлу инсталлятора, который можно взять из переменной $EXEPATH.
Автозагрузку прописываем для текущего пользователя (пользователя, запустившего установщик), т.е. в ключ HKEY_CURRENT_USER.

WriteRegStr HKCU
"Software\Microsoft\Windows\CurrentVersion\RunOnce"
"${APPNAME}" "$EXEPATH"

Примечание: В RunOnce могут записаться программы, которые требуется выполнить однократно при загрузке системы. После выполнения программ, ключ RunOnce очищается автоматически, что отличает его от ключа Run, где данные не очищаются, и его можно использовать, как постоянную автозагрузку.

3. Устанавливаем уникальный флаг, по которому будем определять, что инсталлятор был запущен после перезагрузки, например, таким образом:

DetailPrint "Write After Reboot flag..."
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\"
"${APPNAME}_afterreboot" "1"

4. Выдаем запрос на немедленную перезагрузку:

DetailPrint "Reboot request."
MessageBox MB_YESNO|MB_ICONINFORMATION
"Installation will be cobntinue after reboot. Press OK to reboot now." IDYES RebootID

Если пользователь ответил «Yes«, сразу перезагружаемся:

	RebootID:
		DetailPrint "Rebooting..."
		Reboot

Если нет, ждем перезагрузки вручную:

DetailPrint "Installation continue if user restart system."
Goto SecEnd

5. После перезагрузки удаляем флаг (проверив его наличие, см выше):
DetailPrint "Delete After Reboot flag..."
DeleteRegValue HKCU "Software\Microsoft\Windows\CurrentVersion\"
"${APPNAME}_afterreboot"

6. И продолжаем установку…
DetailPrint "Continue install after reboot..."

Скриншоты



Исходник примера

На GitHub

Глюк в NSIS: проверка параметров командной строки инсталлятора не работает

Вот серьезно, бьюсь (головой об стену) уже третий день, ну не работает функция GetOptions, так, как заявлено в NSIS Wiki, уже и по колесам стучал, и фары протирал, в смысле просто тупо копировал код из примера в тестовый инсталлятор, и еще десяток написал, перепробовав все что можно и нельзя, ну не выходит каменный цветок, хоть тресни. Функция в любом случае выдает, либо что никаких ошибок не случилось, для следующего кода, соответственно, всегда получается found:

Section
	${GetOptions} "/S /T" "/T"  $R0
 
	IfErrors 0 +2
	MessageBox MB_OK "Not found" IDOK +2
	MessageBox MB_OK "Found"
SectionEnd

Либо, для следующего кода всегда остается значение по умолчанию, даже если в командной строке явно задано иное:

Section
	${GetOptions} "/AR=N" "/AR=" $R0
	DetailPrint "R0: $R0"
	
SectionEnd

Например, выполняешь TestInstaller.exe /AR=Y, все равно в переменной $R0 оказывается N

Такие дела.

Переопределение вывода на другой терминал в Linux

Преамбула

Пришли сегодня ко мне с одной задачкой, мол есть у нас программка, которая висит в фоне и периодически выводит данные в консоль. Неудобно оператору работать, либо что-то другое делать, либо ничего не делать, лишь в консоль смотреть. Даже отдельный комп думаем программке выделить, чтоб она на нем крутилась-вертелась. И нельзя ли так сделать, чтоб программку на другом терминале запустить, чтоб можно было по Ctrl+Alt+F[номер] переключаться, и за состоянием программки смотреть?

Вот запустить нельзя, без особого бубна, а вывод переопределить, всегда пожалуйста.

Решение

Можно пользуясь стандартным перенаправлением ввода-вывода в Linux, заставить программу или скрипт отправлять сообщения на другой терминал. Пусть программка будет называться tscript. За терминалы в Linux отвечают устройства /dev/tty*, например, /dev/tty2 отвечает за терминал, вызываемый по Ctrl+Alt+F2.
Например, чтобы программа переопределяла вывод на /dev/tty2, запускаем ее таким образом:

tscript >/dev/tty2

Можно отправить на другой терминал только вывод сообщений об ошибках:

tscript 2>/dev/tty2

Чтобы программа работала в фоне, а на том терминале, с которого мы ее запустили, можно было продолжить работу, добавляем после команды знак &:

./tscript >/dev/tty2 &

Пример

Пишем тестовый скрипт, который, скажем, будет бесконечно выводить на консоль случайное шестнадцатиричное число раз в секунду:

#!/bin/bash

SEC=1

echo "Test script, write to STDOUT random number after $SEC sec."

while [ 1 -eq 1 ];do
    sleep $SEC
    printf 'Number: %x\n' $RANDOM
done

Пишем скрипт, который будет убивать тестовый:

#!/bin/bash
echo "Kill test script..."
pkill tscript

Пишем запускающий скрипт, в котором вывод тестового скрипта переопределяется на терминал tty2:

#!/bin/bash
TERMNO=2
echo "Send tscript output to terminal #$TERMNO"
./tscript >/dev/tty$TERMNO &

Пример работы

Запускаем тестовый скрипт на текущем терминале:

Выполняем запускающий скрипт:


Состояние tty1


Вывод на tty2

Исходники примера

На GitHub

NSIS: Совсем коротко про секции

Преамбула

Секции — это удобный механизм, позволяющий обеспечить пользователю выбор компонентов программы, если такие присутствуют. В каждой секции можно создавать свои ярлыки, распаковывать файлы, и производить любые другие действия, практически независимо от других секций. Естественно, значения переменных, измененные в одной секции, в других тоже будут изменены, потому что в NSIS все переменные глобальные.

Отображение секций и выбор компонентов

Для самого простого выбора компонентов в NSIS, необходимо вставить в скрипт, перед, собственно, описанием секции, следующий код:

ComponentText "Какой-то текст", например:

ComponentText "Choose which features of ${APPNAMEANDVERSION} you want to install."

Естественно, ${APPNAMEANDVERSION} должна быть заранее определена:

!define APPNAME "SectionsExample"
!define APPNAMEANDVERSION " SectionsExample 0.1"


Окно инсталлятора с выбором компонентов

Простая секция

В любом NSIS-скрипте должна быть создана хотя бы одна секция, иначе компилятор будет ругаться, и файл установщика не создаст. В самом простом случае, когда не требуется выбор компонентов, создается единственная секция без названия:

Section
	DetailPrint "Hello, world!"	
SectionEnd


Примечание: После конструкции Section идет имя секции, заключенное в кавычки. Если кавычки пропустить, то имя секции будет некорректным, и неверно отобразится в окне выбора компонентов. Попробуйте вставить следующий код в пример, и посмотрите, как он будет работать. Ссылка на пример в конце заметки.

Section Component 4

	; Wrong section description
	SetOverwrite on
	
	DetailPrint "Component #4 installing..."
	
SectionEnd

Основные компоненты. Блокируем возможность снятия checkbox’а (галочки) пользователем

Для чего? Например, у нас есть программа, у которой, в свою очередь есть основные компоненты, например экзешник и DLL, а также дополнительные, которые можно устанавливать, а можно и не устанавливать. И если уж пользователь хочет поставить наше приложение, то он должен установить хотя бы основные компоненты.

Для того, чтобы заблокировать чекбокс, прописываем в начале секции конструкцию:

SectionIn RO

Section "Main Program and components"

	; Checkbox select and disable user changes
	SectionIn RO
	SetOverwrite on
	
	DetailPrint "Main program installing..."
	
SectionEnd

Чекбокс (галочка) выбранный по умолчанию

Для этого ничего делать не надо, только определить секцию с именем в кавычках и дефольными настройками. Пользователь может деактивировать checkbox (снять галочку) в окне выбора компонентов.

Section "Component #2"

	; Checkbox enabled by default & user will change it state
	SetOverwrite on
	
	DetailPrint "Component #2 installing..."
	
SectionEnd

Сделать, чтобы галочка была снята по умолчанию

Наверное, самый частый вопрос, задаваемый, что в рунете, что в Интернете вообще, по поводу NSIS. Так вот, ларчик открывается просто. Достаточно после Section поставить специальный флаг /o.

Пользователь также сможет активировать checkbox (галочку), если ему нужно будет установить данный компонент.

Section /o "Component #3"

	; Checkbox disabled by default & user will change it state
	SetOverwrite on
	
	DetailPrint "Component #3 installing..."
	
SectionEnd

Скрытые секции

Такие секции не будут отображены в окне выбора компонентов. Их названия пишутся без кавычек и без пробела, а перед названием ставится знак «-«. Код в таких секциях будет выполнен в любом случае, независимо от желания пользователя:

Section -HiddenSection
	DetailPrint "This is a hidden section"
	DetailPrint "This code running anyway."
SectionEnd

Специальные секции

К ним, наверное, относится одна — Uninstall, ну и еще не совсем секция, а встроенная функция, которую можно переопределить, дописав свой код, т.е. что-то типа обработчика событий в «больших» языках, например в C#

О секции Uninstall и рассказывать особо не надо, кроме ремарки, что в секции Uninstall «забываются» все значения глобальных переменных и значение переменной $INSTDIR

Исходник примера с секциями

На GitHub

IPInformer v 0.2.0

Наконец-то руки дошли прикрутить инсталлер и выложить 🙂

Программа предназначена для отображения внешнего IP-адреса компьютера, определения географической принадлежности IP-адреса, а также того, не попадает ли IP-адрес в список «запрещенных» стран.

Программа получает IP-адрес, из поставляемого с ней PHP-скрипта, размещенного на Web-сервере в Интернете, и/или (в текущей версии) с сайтов, которые информируют пользователя о его внешнем IP. В текущей версии не все такие сайты подходят (сайт не должен быть заскриптован, не требовать обязательного использования cookie и не выдавать капчу), а оригинальный скрипт PHP предоставляет некоторые дополнительные возможности.

Далее, программа получает из базы данных SxGeo сведения о геопозиции, и, если настроено и IP-адрес попал в стоп-лист стран, выводит предупреждение о попадании в данный список.

Свежую версию БД SxGeo можно бесплатно скачать с сайта разработчиков базы данных: https://sypexgeo.net/ru/download/

Программа при запуске находится в системном трее, управление производится через контекстное меню.

Изначально писалась по заказу одного активиста, у которого была проблема с периодическим отключением от VPN, в связи с чем, случайно мог «засветиться» его IP, или VPN мог переключить его на нежелательную страну.

По умолчанию программа запускается в «портативном» режиме (все данные хранятся в подкаталоге data каталога с исполняемым файлом)

Системные требования

Microsoft Windows XP и выше (Vista/7/8/8.1/10), .NET Framework 2.0 и выше, 512 Мб оперативной памяти, 15 Мб на жестком диске.

Дополнительные компоненты

В качестве контрола для ввода IP-адреса мы использовали C# IP Address Control вот этого автора:

https://www.codeproject.com/Articles/9352/A-C-IP-Address-Control

База данных SypexGeo (SxGeo):
© 2006-2018 zapimir
© 2006-2018 BINOVATOR

https://sypexgeo.net

Скриншоты

Получение нового IP

Остальные под катом

История версий

0.0.1 b, 19/01/2010 — Первая версия, написанная для товарища OPPosition
0.1.2 08/08/2018 — Исправлен код запросов и конфигов, многое переделано
0.2.0 01/07/2019 — Программа «отвязана» от скрипта с SxGeo на сервере, интерфейс к БД SxGeo перенесен внутрь программы, запросы к БД обрабатываются локально, добавлена поддержка других источников IP-адресов. Первая публичная версия.

Скачать

Портабельная версия
Инсталлятор

Исходники

Репозиторий на GitHub

Сборник фразочек.

С подрочества собирал фразочки, опечатки, оговорки и приколы, а так же надписи в лифтах и туалетных кабинках. Вот он вам тот самый сборник (часть I)

Программа выполнила некорректную операцию и будет закрыта

Любимая ось

Девушки! Не бойтесь секса, он во рту вкуснее кекса!

Подсмотренно в туалете

Я сегодня милку съел, только клитор захрустел.

Постапокалиптическое

Не верь хую, встающему по утру,
Ведь он не любви просящий,
А ПОПИСАТЬ вопиющий.

Подсмотренно в туалете лицея

Кафедра физики мертвого тела.
Кафедра физики голого тела.
Кафедра МАТанализа. Лицам младше 18 лет вход строго запрещен.
Надпись на туалете: «Мы ждем Вас».

Студенты

У какого же растения все-таки квадратный корень???

Карл Линней

Изготовление оградок, стальных дверей, арматуры, оконных решеток по
чертежам заказчика и других металлических изделий.

Отдам запорожец в добрые руки

Объявление

Наша деревня называется Трах

«Поход изгоев»

А я деятель физиологии, анатомии и знатный фекаловед!

Подвал имел отношение к заведению жрального типа, которое умерло грязной
смертью из-за запрета СЭС.

«В мире животного»

Принять меры по эксплуатации людей…

Правила ПБ ЦГБ

Надпись на могиле: «Эй вы, жлобы из профсоюза, а теперь верите, что я был
БОЛЕН!?»

Рабинович.

Постоянно следуй влечению
Не высказывай всё напрямую, но лучись добротой
Конкурентов нет, но будь ангелом
Набаловав, не упорядочивай связи
Уважай седины, а не прикидывайся незнайкой
В долгах перехватывай инициативу
По-женски гаси возмущение

Мой генератор фразочек

Покупайте лотерейные авиобилеты.
«Красная шапочка, я тебя съем!» , — сказал пионер и сожрал свою пилотку.
Как говорят в мужской балетной школе — одно другому не мешает.
Если вы постоянно ставите точки над i, значит вы пишите по-украински

Русское радио

Сел гвоздем на задницу.
Дебицилл.
Губернал-генератор.
Быстро надежно и без хлопот Вас похоронит Аэрофлот.

Без подписи.

У Армянского Радио спрашивают: «Многие города переименовали, а как можно
переименовать Москву?»
«На прошлой неделе — в Ереван, а теперь после активизации скинхедов —
в Жидгород»

Почему албанцы дают жару сербам? Так ведь у них столица в стране — Тирана!
Наши бы переименовали Москву в Наподдаванск, тоже что-нибудь бы устроили!

Все гордимся мы сполна,
Что российский хакер
Сеть любую без труда
Взламывает на фиг.

«Тушите свет»

Это программное обеспечение было установлено под счетом с правами
администратора. Вы должны бревно на счет с правами администратора
неустановить это программное обеспечение.

Переводчик

Вчера прохожий Н. гуляя по лесу наткнулся на пожарную часть.
Это была часть пожарного, которого накануне задрал медведь

Наши глупости

Лопаты по технике безопасности.
Электрический торк.
Числотное кисло.
Иногда настает момент, когда больше уже нельзя оттягивать свой конец.
Надпись в зеленом блокнотике: гр 17 — ЖОПА!
Про мою работу: Че тут написано?! Тыр-пыр. Тру-щу-щу???

Препод по электротехнике

Перелом тазов.
Пердохранители
Класрификация помещений по степени электрической. опасности
Помазать ожог сырыми яйцами.
Затянуть жгут повыше руки.
Затянуть жгут повыше локтя, пониже запястья.

Хабзайцы

Контакторы пенного тока
Магнитные пукатели
Марки кобелей
Замеситель директора
Неисправность барана принтера
Налоговая баба
1 МОм = 1024 кОм

Сие печатал и говорил я.

Глюк (недоработка) uninstaller’а NSIS.

Или как поместить uninstaller не в директории программы.

Преамбула

Конечно, возникает вопрос «зачем?». Ну, например, мы устанавливаем некое системное приложение, драйвер, или хотим что-то пропатчить. В качестве каталога по умолчанию для такого приложения может служить, например, директория $WINDIR (обычно C:\Windows). Если мы хотим безболезненно удалить такое приложение, то нам нужно создать анинсталлер, но, совсем не обязательно чтоб он хранился в том же каталоге, что и установленное приложение. Зачем, например, загаживать каталог C:\Windows файлами uninstall.exe. Да в том то все и дело, что незачем, и вот тут мы сталкиваемся с глюками анинсталлера.

Баг uninstaller’а

В анинстайлере и инсталляторе переменная $INSTDIR определяется по-разному. В секции установки $INSTDIR можно задать, в т.ч. и автоматически, а в uninstaller’е она определяется, как директория, из которой запустился анинсталлер. Это довольно легко проиллюстрировать простым кодом, который на самом деле ничего не устанавливает, а просто предлагает пользователю выбрать каталог для установки, а сам выводит пути к каталогам и создает тестовый анинсталлер во временном каталоге. Анинсталлер тоже ничего не удаляет, просто выводит значения переменных, заданных в основном скрипте.

Любые пользовательские переменные при работе uninstall так же «забываются», вне зависимости от того, были ли они определены в секции, или в скрипте вообще.

Фрагмент кода из установщика:

; явно задаем директорию для установки
InstallDir "$PROGRAMFILES\TestUninst" 
;создаем тестовую переменную
Var TESTVAR
;[..]
;выводим окно для выбора директории для установки
DirText "Choose the folder in which to install ${APPNAME}."

Section "Inst"

	; Set Section properties
	SetOverwrite on
	
	StrCpy $TESTVAR "Test variable value"

	DetailPrint "INSTDIR (install): $INSTDIR"
	DetailPrint "TESTVAR (install): $TESTVAR"
	WriteUninstaller "$TEMP\TestUninst.exe"

SectionEnd

Секция установки:

1. Заполняем $TESTVAR
2. Выходим значение $TESTVAR
3. Выводим значение $INSTDIR
4. Создаем Uninstall’ер, причем не в $INSTDIR


В секции удаления выводим значения $INSTDIR и $TESTVAR, анинсталлер запускаем из временного каталога.

Section Uninstall
	
	SetDetailsView show
	DetailPrint "INSTDIR (uninstall): $INSTDIR"
	DetailPrint "TESTVAR (uninstall): $TESTVAR"
	
SectionEnd

Значение $INSTDIR изменилось на временный каталог, а значение $TESTVAR было потеряно. Если переместить анинсталлер в другой каталог, значение $INSTDIR опять поменяется.

Исходник, иллюстрирующий баг

Размещение uninstall в не в $INSTDIR

Из вышеизложенного напрашивается вывод, что значения $INSTDIR и нужных переменных надо сохранять на этапе установки, например в Реестр или INI-файл, а на этапе удаления восстанавливать.

В следующем примере я буду сохранять нужные значения в INI-файл, который будет располагаться в директории с uninstall.exe, а сама программа будет устанавливаться в другой каталог. Сгенерирую простой скрипт мастером скриптов и немного подправлю.

1. Меняем InstallDir на "$TEMP\TestApp"
InstallDir "$TEMP\TestApp"

2. Заводим переменную $UNINSTDIR
Var UNINSTDIR

3. В секции установки задаем ее значение, скажем "$PROGRAMFILES\TestApp"
StrCpy $UNINSTDIR "$PROGRAMFILES\TestApp"

4. Создаем каталог $UNINSTDIR
CreateDirectory "$UNINSTDIR"

5. Меняем где надо пути в создаваемых ярлыках
CreateShortCut "$SMPROGRAMS\TestApp\Uninstall.lnk" "$UNINSTDIR\uninstall.exe"

6. …путь для записи uninstall.exe
WriteUninstaller "$UNINSTDIR\uninstall.exe"

7. …и запись в Реестре для «Программ и компонентов»
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "UninstallString" "$UNINSTDIR\uninstall.exe"

8. После создания uninstall.exe в каталоге $UNINSTDIR необходимо создать INI-файл, в который сохранить пути к каталогам $UNINSTDIR и $INSTDIR

WriteINIStr "$UNINSTDIR\dirs.ini" "dirs" "I" "$INSTDIR"
WriteINIStr "$UNINSTDIR\dirs.ini" "dirs" "U" "$UNINSTDIR"

На этом с секцией установки закончили.

В секции удаления:

1. Читаем значения из INI-файла (который для uninstall.exe будет располагаться в каталоге из переменной $INSTDIR) в перезаписываемые переменные $0 и $1. Если чтение не удалось, необходимо будет обработать ошибку (см. описания функций ReadINIStr и конструкции IfErrors в справочнике копия).

ReadINIStr $0 "$INSTDIR\dirs.ini" "dirs" "I"
IfErrors Dupa 0
ReadINIStr $1 "$INSTDIR\dirs.ini" "dirs" "U"
IfErrors Dupa 0

2. Восстанавливаем значения $INSTDIR и $UNINSTDIR:

StrCpy $INSTDIR $0
StrCpy $UNINSTDIR $1

3. Удаляем uninstall.exe, INI-файл и каталог анинсталлера:

Delete "$UNINSTDIR\uninstall.exe"
Delete "$UNINSTDIR\dirs.ini"
RMDir "$UNINSTDIR\"

4. Удаляем компоненты программы и ярлыки.

5. В конце секции заводим метку OK:

6. После удаления программы переходим в конец секции
Goto OK

7. Перед меткой OK: заводим метку Dupa:, куда попадем если произошла ошибка чтения INI-файла. После метки Dupa: будет обработчик ошибки. В данном случае выводим пользователю сообщение о том, что INI-файл некорректный, и произвести автоматическое удаление программы нельзя.

Dupa:
	MessageBox MB_ICONSTOP|MB_OK "Error reading
        $INSTDIR\dirs.ini! Uninstall aborted!"

Исходники

1. Исходник, иллюстрирующий баг uninstaller’а
2. Исходник примера

Справочник по NSIS с OSZone

Не сильно хороший, но пусть будет.

Примечание: Если открываешь CHM-файл а страницы пустые, нажимаем на файле правой кнопкой мыши, заходим в свойства и разблокируем его (там кнопка будет)

Скачать с Mega.nz
На OSZone

Лунное затмение 16-17.07.2019

Мои фото, к сожалению, похерились. Пришлось ждать, пока товарищ пришлет свои. Снимал он, насколько мне известно, с крыши, но не с самой высокой точки города и, к сожалению, без штатива. Полноразмерные фото доступны по клику.


Начало наблюдения, минут за 10 до максимума


Над домами


Максимум

+3

NSIS: определение версии и архитектуры Windows

Одна из частых задач при создании инсталлятора — определить версию и архитектуру ОС, например, чтобы в зависимости от этого подкладывать нужную версию экзешника, или устанавливать нужный драйвер.

Отображение версии Windows

Для отображения версии Windows можно воспользоваться готовым кодом из NSIS wiki. На выбор предоставлены два скрипта: только для клиентских ОС и для клиентских и серверных. Для своих целей я пользовался вторым, правда в нем есть небольшой баг — клиентская Windows XP x64 определяется как Windows Server 2003:

Создаем отдельный пустой NSIS-скрипт, копируем туда код из wiki, и сохраняем в тот же каталог, где находится основной скрипт инсталлятора под любым удобным названием, например gvv.nsi.

В основном скрипте подключаем этот файл:

!include gvv.nsi

Далее вызываем GetWindowsVersion, записываем результат в переменную (например, в предопределенную $R0) и выводим результат:

${GetWindowsVersion} $R0
DetailPrint "Windows Version: $R0"

Выполнение кода, если обнаружена определенная версия Windows

Так сказать, «точное» определение версии. Применяется, когда надо выполнить определенные действия, например, в XP и только в XP, или в семерке и только в семерке.

Для этого в комплекте есть модуль WinVer.nsh, сначала подключим его:

!include WinVer.nsh

Далее используем if и один из макросов IsWin?, например IsWinXP, IsWin7, IsWin10:

${If} ${IsWinXP}
	DetailPrint "Is Windows XP"
${EndIf}

Определенная версия и выше

Применяется, когда нужно выполнять код, если версия ОС выше нужной или нужная.

В WinVer.nsh есть другой комплект макросов — AtLeastWin? (AtLeastWin7, AtLeastWin8, AtLeastWin10) которые также нужно использовать вместе с if. Например, следующий код сработает на «семерке» и всех последующих версиях Windows. В деталях установки отобразится соответствующее сообщение:

${If} ${AtLeastWin7}
	DetailPrint "Is Windows 7 or higher"
${EndIf}

Архитектура ОС

Для определения архитектуры ОС необходимо подключить модуль x64.nsh (также поставляется вместе с компилятором NSIS):

!include x64.nsh

Поддерживается определение архитектуры x86 (IsNativeIA32), PC (AMD) x64 (IsNativeAMD64) и ARM64 (IsNativeARM64) пример кода есть в самом файле x64.nsh 🙂 Мне ARM была не нужна, поэтому пример кода на три строки короче:

${If} ${IsNativeAMD64}
    DetailPrint "System Architecture: x64"
${ElseIf} ${IsNativeIA32}
    DetailPrint "System Architecture: x86"
${Else}
    DetailPrint "Unsupported CPU architecture!"
${EndIf}

Скриншоты

Под катом

Пример целиком

На GitHub

Источники

1. Get Windows version
2. Stackoverflow

Отключение Secure Boot на Acer Aspire A315-31 или A315-33

Может поможет и для других ноутов Acer.

Иногда надо отключить в BIOS/UEFI опцию Secure Boot, например, чтобы переустановить Windows с флешки, иначе при загрузке получим сообщение Secure Boot Fail.

Не знаю, что скурили инженеры Acer, но пункт Secure Boot в разделе Boot неактивен, и по умолчанию его значение никак не изменить. Итак, отключаем Secure Boot:

1. Заходим в BIOS/UEFI (клавиша F2 при загрузке)
2. Переходим в раздел Security
3. Задаем Supervisor Password (пароль администратора BIOS). Без разницы какой, но главное его не забыть — забудете, будете долго трахаться с перепрошивкой BIOS. Просто так сбросить его не получится! Так что задайте что-нибудь типа 111
4. На этом этапе нужные пункты уже будут открыты, но лучше зайти на последнюю вкладку, выбрать Exit & Save Changes, перезагрузиться и вновь войти в BIOS по F2
5. Потом надо будет ввести установленный пароль.
6. Пункт Secure Boot в разделе Boot стал активен, теперь можно изменить его значение на Disabled

NSIS: Hello, world.

Изучение любого языка начинается с Hello, world, вот и я не буду отступать от этой традиции. Напишем простой инсталлятор, который даже не инсталлятор, потому что ничего не устанавливает, а просто пишет сообщение пользователю.

Name "HelloWorld"
OutFile "helloworld.exe"

ShowInstDetails show
RequestExecutionLevel User

Section
	DetailPrint "Hello, world!"	
SectionEnd

Объяснение кода

Сначала пишем обязательную конструкцию Name и придумываем имя установщика, тут, естественно, "HelloWorld". Имя может содержать пробелы, оно будет отображаться в заголовках окон и окнах инсталлятора, а также попадет в список программ в «Программы и компоненты», в случае реального установщика.

Далее идет обязательная конструкция OutFile — файл установщика. Если его не прописать, то компилятор не будет знать под каким именем собрать программу установки и пошлет нас.

Следующим шагом (ShowInstDetails show) развернем окно с логом установки, как это было описано в предыдущей копия заметке.

Теперь запрашиваем запуск из под пользователя с ограниченными правами (RequestExecutionLevel User). Инсталляторы обычно запускаются с правами администратора, но в данном случае мы ничего не устанавливаем, и нажимать лишний раз кнопку в окошке UAC не нужно.

Далее необходимо завести хотя бы одну секцию. Если в скрипте не будет хотя бы одной секции — компилятор прервет работу. Организуем единственную секцию без названия.

Section
	[ТУТ БУДЕТ КОД]
SectionEnd

На самом деле секции нужны для того, чтобы сделать возможным выбор компонентов устанавливаемой программы, полную или выборочную установку. Но об этом как-нибудь в другой раз.

Внутри секции пишем сообщение, выводящее заданный текст в окошко с логом (деталями установки):

DetailPrint "Hello, world!"

О редакторах кода для NSIS

На самом деле выбора не так, чтобы много, но какой-никакой есть. На официальном сайте предлагают пользоваться Eclipse и плагином к нему, но у меня на Клипсу, wim и TeX стойкая аллергия еще со студенческих времен.
Есть плагин для Visual Studio, но написан он китайцами для китайцев, так что нафиг. Впрочем, может есть и нормальные плагины, но я не нашел. Сам пользуюсь пожилой средой Venis IX, там есть мастер для генерации простых установщиков, которого вполне хватает, чтоб постоянно не писать одно и то же, создавая новый инсталлятор.

Исходник

На GitHub