Сообщество - Web-технологии

Web-технологии

521 пост 5 813 подписчиков

Популярные теги в сообществе:

185

Основы HTTP-серверов

Основы HTTP-серверов Интернет, Программирование, Длиннопост, Сервер, Http, Web-программирование

В этой статье вы поближе познакомитесь с пакетом net/http и полезными сторонними библиотеками на примере построения простых серверов, маршрутизаторов и промежуточного ПО.



Создание простого сервера:

Код снизу запускает сервер, который обрабатывает запросы по одному пути. (Все листинги кода находятся в корне /exist репозитория GitHub https://github.com/blackhat-go/bhg/.) Этот сервер должен обнаруживать URL-параметр name, содержащий имя пользователя, и отвечать заданным приветствием.

Основы HTTP-серверов Интернет, Программирование, Длиннопост, Сервер, Http, Web-программирование

Сервер Hello World

Этот простой пример предоставляет ресурс по адресу /hello. Данный ресурс получает параметр и возвращает его значение обратно клиенту. http.HandleFunc() в функции main() получает два аргумента: строку, являющуюся шаблоном URL-пути, который сервер должен искать, и функцию, которая будет обрабатывать сам запрос. При желании определение функции можно оформить в виде анонимной встроенной функции. В этом примере мы передаем определенную чуть раньше функцию hello().

Функция hello() обрабатывает запросы и возвращает клиенту сообщение «Hello». Она получает два аргумента. Первый — это http.ResponseWriter, используемый для записи ответов на запрос. Второй аргумент является указателем на http.Request, который позволит считывать информацию из входящего запроса. Обратите внимание на то, что мы не вызываем hello() из main(), а просто сообщаем HTTP-серверу, что любые запросы для /hello должны обрабатываться функцией hello().

Что же на самом деле происходит внутри http.HandleFunc()? В документации Go сказано, что она помещает обработчик в DefaultServerMux. ServerMux означает серверный мультиплексор. На деле же это просто сложное выражение, подразумевающее, что внутренний код может обрабатывать несколько HTTP-запросов для шаблонов и функций. Это выполняется посредством горутин, по одной для каждого запроса. При импорте пакета net/http создается ServerMux и прикрепляется к пространству имен этого пакета. Это DefaultServerMux.

В следующей строке прописан вызов http.ListenAndServe(), которая получает в качестве аргументов строку и http.Handler. Она запускает HTTP-сервер, используя первый аргумент в роли адреса, которым в данном случае является :8000. Это означает, что сервер должен прослушивать порт 8000 по всем интерфейсам. Для второго аргумента, http.Handler, передается nil. В результате пакет задействует в качестве обработчика DefaultServerMux. Вскоре мы будем реализовывать собственный http.Handler и передавать его, но пока что используем предустановленный вариант. Можно также задействовать http.ListenAndServeTLS(), которая запустит сервер с использованием HTTPS и TLS, но потребует дополнительных параметров.

Для реализации интерфейса http.Handler необходим один метод — ServeHTTP(http.ResponseWriter, *http.Request). И это здорово, потому что упрощается создание собственных специализированных HTTP-серверов. Существует множество сторонних реализаций, которые расширяют функциональность пакета net/http, добавляя такие возможности, как промежуточное ПО, аутентификация, кодирование ответа и др.

Протестировать созданный сервер можно с помощью curl:

Основы HTTP-серверов Интернет, Программирование, Длиннопост, Сервер, Http, Web-программирование

Превосходно! Этот сервер считывает URL-параметр name и отвечает приветствием.


Создание простого маршрутизатора:



Далее мы создадим простой маршрутизатор, приведенный , который показывает, как динамически обрабатывать входящие запросы, проверяя URL-путь. В зависимости от того, что содержит URL-путь, /a, /b или /c, будет выводиться сообщение Executing /a, Executing /b или Executing /c. Во всех остальных случаях отобразится ошибка 404 Not Found.

Основы HTTP-серверов Интернет, Программирование, Длиннопост, Сервер, Http, Web-программирование

Простой маршрутизатор

Сначала идет определение типа router без полей, который будет использован в реализации интерфейса http.Handler. Для этого нужно определить метод ServerHTTP(). Он использует для URL-запроса инструкцию switch, выполняя различную логику в зависимости от пути. В нем применяется предустановленный ответ 404 Not Found. В main() мы создаем новый router и передаем соответствующий ему указатель в http.ListenAndServe().

Давайте взглянем на это в ole-терминале:

Основы HTTP-серверов Интернет, Программирование, Длиннопост, Сервер, Http, Web-программирование

Все работает, как ожидалось. Программа возвращает сообщение Executing /a для URL, который содержит путь /a. При этом для несуществующего пути она возвращает ответ 404. Это тривиальный пример, и сторонние маршрутизаторы, которые вам предстоит использовать, будут иметь намного более сложную логику, но теперь основной принцип вам должен быть понятен.


Создание простого промежуточного ПО:



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

Основы HTTP-серверов Интернет, Программирование, Длиннопост, Сервер, Http, Web-программирование

Простое промежуточное ПО

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

Как и в примере с маршрутизатором, здесь определяется новый тип logger, но на этот раз в нем есть поле inner, которое является самим http.Handler. В определении ServeHTTP() мы используем log() для вывода времени начала и завершения запроса, вызывая между этими выводами метод ServeHTTP() внутреннего обработчика. Для клиента данный запрос завершится внутри этого обработчика. В main() с помощью http.HandlerFunc() из функции создается http.Handler. Здесь реализуется logger, в котором для inner устанавливается только что созданный обработчик. В завершение происходит запуск сервера с помощью указателя на экземпляр logger.

Выполнение кода и отправка запроса выводят два сообщения, содержащих время его начала и завершения:

Основы HTTP-серверов Интернет, Программирование, Длиннопост, Сервер, Http, Web-программирование

Маршрутизация с помощью пакета gorilla/mux



Как показано в Простом Маршрутизаторе, с помощью маршрутизации можно сопоставлять путь запроса с функцией. Ее можно использовать также для сопоставления с функцией и других свойств, таких как HTTP-глаголы (методы запроса) или заголовки хостов. В экосистеме Go доступны несколько сторонних маршрутизаторов. Здесь мы представим один из них — пакет gorilla/mux. Но как и в остальных случаях, рекомендуем расширять знания самостоятельно, изучая и другие пакеты по мере их появления на вашем пути.

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

Рассмотрим пару вариантов применения этого маршрутизатора. Выполнять эти примеры необязательно, так как вскоре мы задействуем их в реальной программе.

Для использования gorilla/mux нужно его сначала установить с помощью команды go get:

Основы HTTP-серверов Интернет, Программирование, Длиннопост, Сервер, Http, Web-программирование

Теперь можно приступить к делу и создать маршрутизатор с помощью mux.NewRouter():

Основы HTTP-серверов Интернет, Программирование, Длиннопост, Сервер, Http, Web-программирование

Возвращаемый тип реализует http.Handler, а также имеет множество других ассоциированных методов. Например, если требуется определить новый маршрут для обработки запросов GET к шаблону /foo, можно сделать так:

Основы HTTP-серверов Интернет, Программирование, Длиннопост, Сервер, Http, Web-программирование

Теперь благодаря вызову Methods() этому маршруту будут соответствовать только запросы GET. Все остальные методы будут возвращать ответ 404. Поверх этого можно надстроить цепочку других квалификаторов, например Host(string), который сопоставляет определенное значение заголовка хоста. Как вариант, следующий код будет сопоставлять только те запросы, чей заголовок установлен как www.foo.com:

Основы HTTP-серверов Интернет, Программирование, Длиннопост, Сервер, Http, Web-программирование

Иногда это полезно для сравнения и передачи параметров внутри пути запроса, например при реализации RESTful API. С помощью gorilla/mux это делается легко. Следующий код будет выводить на экран все, что следует за /users/ в пути запроса:

Основы HTTP-серверов Интернет, Программирование, Длиннопост, Сервер, Http, Web-программирование

В определении пути параметр запроса задается с использованием фигурных скобок. Можете рассматривать его как место для подстановки. Затем внутри функции-обработчика происходит вызов mux.Vars(), куда передается объект запроса. В ответ вернется map[string] string — карта имен параметров запроса с соответствующими значениями. Поле для подстановки имени user передается в качестве ключа. В итоге запрос к /users/bob должен выдать приветствие для Боба:

Основы HTTP-серверов Интернет, Программирование, Длиннопост, Сервер, Http, Web-программирование

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

Основы HTTP-серверов Интернет, Программирование, Длиннопост, Сервер, Http, Web-программирование

Теперь любые запросы, не совпадающие с этим шаблоном, будут возвращать ответ 404:

Основы HTTP-серверов Интернет, Программирование, Длиннопост, Сервер, Http, Web-программирование

Далее мы разовьем тему маршрутизации, включив реализации промежуточного ПО с помощью других библиотек. Это повысит гибкость обработки HTTP-запросов


Создание промежуточного ПО с помощью Negroni



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

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

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

Этот пакет, расположенный в репозитории по адресу https://github.com/urfave/negroni/, хорош тем, что не привязывает вас к крупному фреймворку. При этом его можно легко подключать к другим библиотекам, что делает его особенно гибким.

Также в нем присутствуют предустановленные промежуточные программы, которые могут пригодиться во многих сценариях. Для начала опять же нужно выполнить команду
go get negroni:

Основы HTTP-серверов Интернет, Программирование, Длиннопост, Сервер, Http, Web-программирование

Несмотря на то что технически этот пакет можно использовать для всей логики приложения, это будет далеко не самым оптимальным решением, потому что он призван служить промежуточным ПО и не включает маршрутизатор. Лучше применять negroni в тандеме с другим пакетом, например gorilla/mux или net/http. Применим первый для создания программы, которая познакомит вас с negroni и наглядно покажет порядок операций по ходу их реализации в цепочке промежуточных программ.

Начнем с создания нового файла main.go в пространстве имен каталогов, например github.com/blackhat-go/bhg/ch-4/negroni_example/. (Если вы клонировали репозиторий BHG, это пространство имен уже будет создано.) Теперь нужно добавить в созданный файл в код который мы сейчас напишем.

Основы HTTP-серверов Интернет, Программирование, Длиннопост, Сервер, Http, Web-программирование

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

Сначала, как и ранее, с помощью вызова mux.NewRouter() создается маршрутизатор. Далее идет первое взаимодействие с пакетом negroni, а именно вызов negroni.Classic(). Таким образом создается новый указатель на экземпляр Negroni.

Это можно сделать разными способами: использовать negroni.Classic() или вызвать negroniNew(). Первый вариант, negroni.Classic(), устанавливает набор промежуточных программ по умолчанию, включая логер запросов, утилиту восстановления, которая будет осуществлять прерывание и восстановление в случае паники (аварийной остановки выполнения программы), а также программу, которая будет предоставлять файлы из публичного каталога, расположенного в той же папке. Что же касается функции negroni.New(), то она не создает предустановленного промежуточного ПО.

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

Основы HTTP-серверов Интернет, Программирование, Длиннопост, Сервер, Http, Web-программирование

Далее следует добавление в стек промежуточного ПО маршрутизатора с помощью вызова n.UseHandler(r). Планируя и собирая собственный промежуточный комплект программ, не забудьте учесть порядок их выполнения. Например, необходимо, чтобы программа проверки аутентификации срабатывала до функции-обработчика, которая эту аутентификацию требует. Любая такая программа, надстроенная над маршрутизатором, будет выполняться после обработчика. Порядок важен. В данном случае мы не определяли собственное ПО, но вскоре к этому прибегнем.

Сейчас же мы создадим сервер из Примера использования Negroni и запустим его. Затем отправим ему веб-запросы по адресу http://localhost:8000. В результате программа логирования negroni должна вывести информацию в stdout, как показано далее. В выводе отражены временная метка, код ответа, время обработки, хост и HTTP-метод:

Основы HTTP-серверов Интернет, Программирование, Длиннопост, Сервер, Http, Web-программирование

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

Основы HTTP-серверов Интернет, Программирование, Длиннопост, Сервер, Http, Web-программирование

Эта реализация немного отличается от предыдущих примеров. Ранее мы реализовывали интерфейс http.Handler, который ожидал метод ServeHTTP(), получающий два параметра: http.ResponseWriter и *http.Request. В этом же примере вместо интерфейса http.Handler реализуем интерфейс negroni.Handler.

Небольшое различие здесь в том, что интерфейс negroni.Handler ожидает реализации метода ServeHTTP(), который получает уже не два, а три параметра: http.ResponseWriter, *http.Request и http.HandlerFunc. Параметр http.HandlerFunc представляет следующую промежуточную функцию в цепочке, которую мы назовем next. Сначала обработка выполняется методом ServeHTTP(), после чего происходит вызов next(), которой передаются изначально полученные значения http.ResponseWriter и *http.Request. В результате выполнение передается дальше по цепочке.

Но нам по-прежнему нужно указать negroni использовать в цепочке промежуточного ПО и нашу реализацию. Для этого можно вызвать метод negroni под названием Use и передать ему экземпляр реализации negroni.Handler:

Основы HTTP-серверов Интернет, Программирование, Длиннопост, Сервер, Http, Web-программирование

Писать собственный набор промежуточных программ с помощью этого метода удобно, поскольку можно легко передавать их выполнение по цепочке. Но при этом есть один недостаток: все, что вы пишете, должно использовать negroni. Например, если создать пакет промежуточного ПО, который записывает в ответ заголовки безопасности, то он должен будет реализовывать http.Handler, чтобы его можно было применять и в других стеках приложения, так как большинство из них не будут ожидать negroni.Handler. Суть в том, что независимо от назначения создаваемых промежуточных программ проблемы совместимости могут возникнуть при попытке использовать промежуточное ПО negroni в другом стеке и наоборот.

Есть два других способа сообщить negroni, что следует задействовать ваше промежуточное ПО. Первый из них — это уже знакомый вам UseHandler (handler http.Handler). Второй — это вызов UseHandleFunc(handlerFunc func(w http.ResponseWriter, r *http.Request)). Последним вы вряд ли станете пользоваться часто, поскольку он не позволяет поочередно выполнять программы в цепочке. Например, если нужно написать промежуточную функцию для выполнения аутентификации, то в случае неверной информации сессии или учетных данных потребуется возвращать ответ 401 и останавливать выполнение. С помощью названного метода это сделать не получится.



Добавление аутентификации с помощью Negroni:




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

Основы HTTP-серверов Интернет, Программирование, Длиннопост, Сервер, Http, Web-программирование

Использование context в обработчиках

Здесь мы добавили новую промежуточную программу, badAuth, которая будет симулировать аутентификацию исключительно в целях демонстрации. Этот новый тип содержит поля Username и Password и реализует negroni.Handler, поскольку в нем определяется версия метода ServeHTTP() с тремя параметрами. Внутри ServeHTTP() сначала из запроса извлекаются имя пользователя и пароль, после чего их значения сравниваются с имеющимися полями. Если данные не совпадают, выполнение останавливается и запрашивающей стороне отправляется ответ 401.

Обратите внимание на то, что мы делаем возврат до вызова next(). Это останавливает выполнение оставшейся цепочки промежуточных программ. Если учетные данные окажутся верными, выполняется довольно объемный код для добавления имени пользователя в контекст запроса. Сначала происходит вызов context.WithValue() для инициализации контекста из запроса с установкой в него переменной username. Затем мы убеждаемся, что запрос использует новый контекст, вызывая r.WithContext(ctx). Если вы планируете написать веб-приложение на Go, то вам нужно будет получше познакомиться с этим шаблоном, поскольку применять его придется часто.

В функции hello() мы получаем имя пользователя из контекста запроса, применяя функцию Context().Value(interface{}), которая возвращает interface{}. Так как вам известно, что это строка, здесь можно задействовать утверждение типа. Если же вы не можете гарантировать тип или то, что это значение будет существовать в этом контексте, используйте для преобразования инструкцию switch.

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

Основы HTTP-серверов Интернет, Программирование, Длиннопост, Сервер, Http, Web-программирование

Отправка запросов без учетных данных приводит к возврату ошибки 401 Unauthorized. Если тот же запрос отправить с верным набором данных, то в ответ придет суперсекретное сообщение, доступное только аутентифицированным пользователям.

Усвоить нужно очень большой объем рассмотренного здесь материала. Функции-обработчики используют для записи ответа в экземпляр http.ResponseWriter только fmt.FPrintf(). Закончу эту статью последним разделом про создание HTML- ответов с помощью шаблонов.



Создание HTML-ответов с помощью шаблонов:



Шаблоны позволяют динамически генерировать содержимое, включая HTML, с помощью переменных из программ Go. Во многих языках генерация шаблонов реализуется с помощью сторонних пакетов. В Go для этой цели есть два пакета, text/template и html/template. Мы же в этой главе используем пакет HTML, потому что он предоставляет необходимую нам контекстную кодировку.

Одна из особенностей учета контекста в пакете Go заключается в том, что он кодирует переменную по-разному, в зависимости от ее расположения в шаблоне. Например, строка в виде URL, переданная в атрибут href, будет закодирована в URL, но при отображении в HTML-элементе она будет закодирована уже в HTML.

Процесс генерации шаблона для его дальнейшего использования начинается с определения самого шаблона, который содержит поле ввода для обозначения динамических контекстных данных для отображения. Его синтаксис покажется знакомым тем, кто применял Jinja совместно с Python. При отрисовке шаблона мы передаем ему переменную, которая будет использоваться в качестве контекста. Она может быть сложной структурой с несколькими полями либо примитивом.

Давайте проработаем код ниже, который создает простой шаблон и заполняет поле ввода JS-кодом. Это искусственный пример, показывающий, как динамически заполнять содержимое, которое возвращается в браузер.

Основы HTTP-серверов Интернет, Программирование, Длиннопост, Сервер, Http, Web-программирование

HTML-шаблонизация

Сначала создается переменная x, которая будет хранить HTML-шаблон. Здесьдля определения шаблона используется строка, вложенная в код, но в большинстве случаев вам потребуется хранить шаблоны в отдельных файлах. Обратите внимание на то, что этот шаблон представляет простую HTML-страницу. Внутри него с помощью специальной инструкции {{variable-name}} определяются поля ввода. Variable-name — это элемент внутри контекстных данных, который требуется отобразить. Напомним, что это может быть структура или другой примитив.В данном случае мы используем одну точку, сообщая таким образом пакету, что нужно отобразить весь контекст. Учитывая, что мы будем работать с одной строкой, это нормально, но в случае применения более крупных и сложных структур, таких как struct, получение нужных полей осуществляется вызовом после этой точки. Например, если в шаблон передать структуру с полем Username, то отобразить это поле можно будет, используя выражение {{.Username}}.

Далее в функции main() с помощью вызова template.New(string) создается новый шаблон ❸. Затем выполняется вызов Parse(string), обеспечивающий верное форматирование шаблона и его парсинг. Совместно эти две функции возвращают указатель на Template.

В этом примере задействуется всего один шаблон, но шаблоны можно вкладывать в другие шаблоны. При использовании нескольких шаблонов для удобства их дальнейшего вызова важно именовать их последовательно. В завершение происходит вызов Execute(io.Writer, interface{}), который обрабатывает шаблон, используя переменную, переданную в качестве второго аргумента, и записывает его в предоставленный io.Writer. Для демонстрации мы применяем os.Stdout. Вторая передаваемая в метод Execute() переменная — это контекст, который будет использоваться для отображения шаблона.

Выполнение этого кода сформирует HTML-код, и можно заметить, что теги скриптов и другие переданные в контексте вредоносные символы закодированы правильно:

Основы HTTP-серверов Интернет, Программирование, Длиннопост, Сервер, Http, Web-программирование

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

ССЫЛКА НА ТЕЛЕГРАМ КАНАЛ АВТОРА

Показать полностью 25
158

Написание DNS-серверов

Написание DNS-серверов Linux, Хакеры, Информационная безопасность, Взлом, Google, Интернет, Длиннопост

Мастер Йода говорил: «И как всегда двое их, не больше и не меньше». Он, конечно же, говорил об отношениях «клиент — сервер», и поскольку вы являетесь мастером клиентов, то пришло время стать мастером серверов. В этом разделе с помощью того же пакета Go DNS мы напишем простой сервер и прокси. DNS-серверы можно использовать для нескольких вредоносных задач, включая туннелирование сетей с ограниченным доступом и совершение спуфинг-атак с помощью поддельных беспроводных точек доступа.

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


Настройка лаборатории и знакомство с сервером


Лаборатория состоит из двух виртуальных машин (VM): Microsoft Windows VM, выступающей в роли клиента, и Ubuntu VM, действующей в качестве сервера.

В этом примере для каждой машины используются VMWare Workstation и сетевой мост. Допустимо применение частной виртуальной сети, но при этом необходимо убедиться, что обе машины принадлежат одной сети. Сервер будет выполнять два экземпляра Cobalt Strike Docker, собранных из официального образа Java Docker (Java — необходимое условие для Cobalt Strike). Снизу показано, как будет выглядеть лаборатория.

Написание DNS-серверов Linux, Хакеры, Информационная безопасность, Взлом, Google, Интернет, Длиннопост

Настройка лабораторного стенда для создания DNS-сервера

Сначала нужно создать виртуальную машину Ubuntu (Ubuntu VM). Для этого мы используем дистрибутив 16.04.1 LTS. Никаких особых требований здесь нет, но VM необходимо настроить на использование не менее 4 Гбайт ОЗУ и двух CPU. Если есть, можно задействовать существующую VM или хост. Закончив с операционной системой, необходимо установить среду разработки Go (см. главу 1).

После создания Ubuntu VM займитесь установкой утилиты контейнера виртуализации Docker. В разделе этой главы, посвященном прокси, мы будем использовать Docker для запуска нескольких экземпляров Cobalt Strike. Для установки Docker выполните в терминале:

Написание DNS-серверов Linux, Хакеры, Информационная безопасность, Взлом, Google, Интернет, Длиннопост

После этого повторно войдите в систему и убедитесь, что Docker установлен, выполнив следующую команду:

Написание DNS-серверов Linux, Хакеры, Информационная безопасность, Взлом, Google, Интернет, Длиннопост

После установки Docker с помощью следующей команды скачайте образ Java:

Написание DNS-серверов Linux, Хакеры, Информационная безопасность, Взлом, Google, Интернет, Длиннопост

Эта команда получит базовый образ Java Docker, не создавая контейнеры. Таким образом мы подготавливаемся к скорому выполнению сборок Cobalt Strike.

В завершение необходимо убедиться в том, что dnsmasq не запущен, потому что он слушает порт 53. В противном случае ваши DNS-серверы не смогут работать, так как они должны использовать именно этот порт. Если процесс dnsmasq запущен, завершите его по ID:

Написание DNS-серверов Linux, Хакеры, Информационная безопасность, Взлом, Google, Интернет, Длиннопост

Теперь нужно создать виртуальную машину Windows (Windows VM). Опять же можно использовать существующую машину. Никаких особых настроек делать не требуется, достаточно минимальных. Когда система заработает, установите для DNS-сервера IP-адрес системы Ubuntu.

Чтобы протестировать настройку лабораторного стенда и перейти к написанию DNS-серверов, мы начнем с создания простого сервера, который возвращает только А-записи. В GOPATH системы Ubuntu создайте каталог github.com/blackhat-go/bhg/ch-5/a_server и файл для хранения кода main.go. Снизу будет показан весь код для создания простого DNS-сервера.

Написание DNS-серверов Linux, Хакеры, Информационная безопасность, Взлом, Google, Интернет, Длиннопост

Написание DNS-сервера (/ch-5/a_server/main.go)

Код начинается с вызова HandleFunc(), он во многом напоминает пакет net/http. Первый аргумент функции является шаблоном запроса для сопоставления. Он станет применяться для указания DNS-серверам, какие запросы будут обрабатываться переданной функцией. Используя точку, мы сообщаем серверу, что предоставляемая во втором аргументе функция будет обрабатывать все запросы.

Следующий передаваемый в Handlefunc() аргумент — это функция, содержащая логику обработчика. Она получает два аргумента: ResponseWriter и сам запрос. Внутри обработчика сначала создается новое сообщение и устанавливается ответ. Затем создается ответ на каждый вопрос с помощью А-записи, которая реализует интерфейс RR. Эта часть будет различаться в зависимости от типа искомого вами ответа. Указатель на А-запись добавляется в поле Answer ответа с помощью append(). По завершении ответа его сообщение записывается вызывающему клиенту с помощью w.WriteMsg(). В конце для запуска сервера вызывается ListenAndServe(). Этот код интерпретирует все запросы в IP-адрес 127.0.0.1.

Запустив сервер, можно протестировать его с помощью dig. Убедитесь, что имя хоста, для которого выполняются запросы, разрешается в 127.0.0.1. Это будет означать, что все работает как надо:

Написание DNS-серверов Linux, Хакеры, Информационная безопасность, Взлом, Google, Интернет, Длиннопост

Обратите внимание на то, что сервер нужно будет запускать с помощью sudo или через корневую учетную запись (root), потому что он прослушивает привилегированный порт 53. Если сервер не запускается, может потребоваться завершить dnsmasq.

Создание DNS-сервера и прокси:


DNS-туннелирование — это техника извлечения данных, дающая возможность установить C2-канал из сетей с контролем исходящего трафика. Используя авторитетный DNS-сервер, злоумышленник может проложить маршрут через внутренние DNS-серверы организации и выйти через интернет, причем ему не потребуется прямое подключение к собственной инфраструктуре. Несмотря на медлительность такой атаки, защититься от нее сложно. DNS-туннелирование выполняется с помощью ряда открытых и проприетарных полезных нагрузок, одной из которых является Beacon от Cobalt Strike. В текущем разделе мы напишем собственный DNS-сервер и прокси, а также научимся с помощью Cobalt Strike мультиплексировать полезные нагрузки C2 для DNS-туннелирования.


Настройка Cobalt Strike:


Если вам доводилось использовать этот инструмент, то вы наверняка замечали, что по умолчанию team-сервер прослушивает порт 53. В связи с этим и с тем, что советует документация, в системе должен быть запущен только один сервер, поддерживая соотношение один к одному. Это может стать проблемой для средних и больших команд. Например, если у вас есть 20 команд, реализующих наступательные мероприятия против 20 отдельных организаций, то поддержка 20 систем, способных выполнять team-сервер, может стать затруднительной. Эта проблема касается не только Cobalt Strike и DNS, но и других протоколов, включая полезные нагрузки HTTP, такие как Metasploit Meterpreter и Empire. Несмотря на то что можно установить слушатели на различные порты, есть большая вероятность выхода трафика через такие стандартные TCP-порты, как 80 и 443. Отсюда возникает логичный вопрос: как вы и другие команды можете совместно использовать один порт и делать перенаправление на разных слушателей? Ответом будет, конечно же, прокси-сервер. Пора вернуться в лабораторию.

ПРИМЕЧАНИЕ


В реальных сценариях противодействия вам потребуется иметь несколько уровней маневрирования, абстрагирования и переадресации для маскировки team-сервера. Это можно реализовать с помощью UDP- и TCP-переадресации через небольшие вспомогательные серверы, использующие разных хостинг-провайдеров. Основной team-сервер и прокси также могут работать на разных системах. В этом случае кластер коллективного сервера размещается в обширной системе с большим объемом ОЗУ и мощным CPU.

Давайте запустим два экземпляра коллективного сервера в двух контейнерах Docker. Это позволит им прослушивать порт 53, а также даст каждому серверу возможность использовать собственную систему и, следовательно, собственный стек IP. Для сопоставления UDP-портов с хостом из контейнера мы будем применять встроенный в Docker сетевой механизм. Для начала скачайте пробную версию Cobalt Strike с https://trial.cobaltstrike.com/1. Для этого нужно создать пробную учетную запись, получив возможность скачать tar-архив. Теперь можно запускать team-серверы.


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

Написание DNS-серверов Linux, Хакеры, Информационная безопасность, Взлом, Google, Интернет, Длиннопост

Эта команда выполняет несколько действий. С ее помощью вы сообщаете Docker о необходимости удаления контейнера после выхода, а также о том, что после запуска будете с ним взаимодействовать. Далее идет сопоставление порта 2020 системы хоста с портом 53 в контейнере и порта 50051 с портом 50050. Затем каталог, содержащий архив Cobalt Strike, сопоставляется с каталогом данных в контейнере. Здесь можно указать любое имя каталога, и Docker без проблем его создаст. В завершение предоставляется образ, который нужно использовать (в данном случае Java), а также команда для выполнения при запуске.

Оказавшись внутри контейнера, запустите team-сервер с помощью следующих команд:

Написание DNS-серверов Linux, Хакеры, Информационная безопасность, Взлом, Google, Интернет, Длиннопост

Указываемый IP-адрес должен соответствовать текущей виртуальной машине, а не адресу контейнера.

Далее откройте новое окно терминала в хосте Ubuntu и перейдите в каталог с архивом Cobalt Strike. Выполните следующие команды для установки Java и запуска клиента Cobalt Strike:

Написание DNS-серверов Linux, Хакеры, Информационная безопасность, Взлом, Google, Интернет, Длиннопост

Должен запуститься Cobalt Strike GUI. После сообщения о пробной версии измените порт team-сервера на 50051, а также установите соответствующие имя пользователя и пароль.

Вы успешно подключились к серверу, полностью работающему в Docker-контейнере. Теперь повторим тот же процесс для запуска второго сервера. На этот раз будем сопоставлять другие порты. При этом вполне логичным будет увеличить значение порта на единицу. Выполните следующую команду в новом окне терминала, чтобы запустить новый контейнер и прослушивать порты 2021 и 50052:

Написание DNS-серверов Linux, Хакеры, Информационная безопасность, Взлом, Google, Интернет, Длиннопост

Из клиента Cobalt Strike создайте новое подключение, выбрав Cobalt Strike New Connection, изменив порт на 50052 и нажав Connect. Подключившись, вы должны увидеть в нижней части консоли две вкладки, с помощью которых можно переключаться между серверами.

Успешно завершив подключение к двум коллективным серверам, пора запустить два DNS-слушателя. Для создания слушателя выберите в меню пункт Configure Listeners. Он обозначен значком с изображением наушников. Из этого меню выберите Add, чтобы вызвать окно New Listener. Введите в нем следующее:

  • Name: DNS 1;

  • Payload: windows/beacon_dns/reverse_dns_txt;

  • Host: <IP address of host>;

  • Port: 0.

В этом примере установлен порт 80, но наша полезная нагрузка DNS по-прежнему использует порт 53. Это нормально. Порт 80 специально задействуется для гибридных полезных нагрузок. На скрине снизу показаны окно New Listener и информация, которую необходимо ввести.

Написание DNS-серверов Linux, Хакеры, Информационная безопасность, Взлом, Google, Интернет, Длиннопост

Добавление слушателя

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

Написание DNS-серверов Linux, Хакеры, Информационная безопасность, Взлом, Google, Интернет, Длиннопост

Добавление домена DNS-маячка

Введите в качестве DNS-маячка домен attacker1.com. Он должен соответствовать имени домена, куда полезная нагрузка будет отправлять сигналы. Далее отобразится сообщение о запуске нового слушателя. Повторите этот процесс на другом team-сервере, используя значения DNS2 и attacker2.com. Прежде чем задействовать этих двух слушателей, нужно написать промежуточный сервер, который будет проверять DNS-сообщения и соответствующим образом их перенаправлять. Это и будет ваш прокси.


Создание DNS-прокси:


Используемый вами на протяжении этой главы DNS-пакет облегчает написание функции-посредника — вы уже работали с некоторыми такими функциями в предыдущих разделах. Наш прокси должен уметь:

  • создавать функцию-обработчик для приема входящего запроса;

  • проверять в этом запросе вопрос и извлекать имя домена;

  • определять вышестоящий DNS-сервер, соответствующий этому имени домена;

  • обмениваться вопросом с этим вышестоящим DNS-сервером и писать ответ клиенту.

В функции можно прописать обработку attacker1.com и attacker2.com как статических значений, но такой вариант не удастся поддерживать. Вместо этого следует искать записи во внешнем для программы источнике, например в базе данных или файле конфигурации. В приведенном далее коде это реализуется с помощью формата domain.server, который перечисляет входящие домен и вышестоящий сервер через точку. Чтобы запустить программу, создайте функцию для парсинга файла, содержащего записи в этом формате. Запишите код снизу в новый файл main.go.

Написание DNS-серверов Linux, Хакеры, Информационная безопасность, Взлом, Google, Интернет, Длиннопост

Написание DNS-прокси (/ch-5/dns_proxy/main.go)

В этом коде сначала мы определяем функцию, которая парсит файл с информацией о конфигурации и возвращает map[string]string. Эта карта будет использоваться для поиска входящего домена и извлечения вышестоящего сервера.

Введите в терминале первую команду приведенного далее кода, чтобы записать следующую за echo строку в файл proxy.config. Затем нужно скомпилировать и запустить dns_proxy.go.

Написание DNS-серверов Linux, Хакеры, Информационная безопасность, Взлом, Google, Интернет, Длиннопост

Что мы здесь видим? Вывод представляет сопоставление между именами доменов team-серверов и портом, который прослушивает DNS-сервер Cobalt Strike. Напомним, что в двух отдельных контейнерах Docker мы сопоставили порты 2020 и 2021 с портом 53. Здесь же использовали быстрый и грязный путь создания основной конфигурации для инструмента, чтобы вам не пришлось хранить его в базе данных или другом постоянном хранилище.

Определив карты записей, можно написать обработчик. Давайте уточним код, добавив в функцию main() приведенный далее фрагмент, который должен следовать за парсингом файла конфигурации:

Написание DNS-серверов Linux, Хакеры, Информационная безопасность, Взлом, Google, Интернет, Длиннопост

Код начинается с вызова HandleFunc() с точкой для обработки всех входящих запросов, а также определения анонимной функции, то есть функции, которую мы не собираемся использовать повторно (у нее нет имени). Это удобная структура на случай, когда вам не нужно повторно задействовать некий блок кода. Если же ее применение в нескольких местах все же подразумевается, то необходимо объявлять и вызывать ее как именованную функцию. Далее идет проверка среза входящих вопросов, гарантирующая, что все вопросы переданы. Если же нет, происходит вызов HandleFailed() и возврат для раннего выхода из функции. Такой шаблон используется во всем обработчике. Если присутствует хотя бы один вопрос, можно безопасно получить запрашиваемое имя из первого вопроса. Разделять имя точкой нужно для извлечения имени домена. В результате этого не должно получаться значение меньше 1, но на всякий случай стоит проверить. Хвост среза — элементы в его конце — можно получить, применив в срезе оператор slice. Теперь нужно извлечь вышестоящий сервер из карты записей.

При извлечении значения из карты могут возвращаться одна или две переменные. Если ключ (в нашем случае имя домена) в карте присутствует, будет возвращено соответствующее значение. Если же домен отсутствует, возвращается пустая строка. Можно проверять, является ли возвращенное значение пустой строкой, но это окажется неэффективным, когда вы начнете работать с более сложными типами. Вместо этого мы задаем две переменные: первая — это значение ключа, а вторая — логическое значение, возвращающее true, если ключ найден. Убедившись в совпадении, мы обмениваемся запросом с вышестоящим сервером. Здесь мы просто подтверждаем, что имя домена, для которого получен запрос, настроено в постоянном хранилище. Далее записывается ответ вышестоящего сервера клиенту. Определив функцию-обработчик, мы запускаем сервер. В завершение можно собирать и запускать прокси.

После запуска мы протестируем его с помощью двух слушателей Cobalt Strike. Для этого сначала нужно создать два самостоятельных (stageless) исполняемых файла. В верхнем меню Cobalt Strike нажмите значок с изображением шестеренки и измените формат вывода на Windows Exe. Повторите процесс из каждого team-сервера. Скопируйте эти исполняемые файлы в Windows VM и запустите. DNS-сервер Windows VM должен иметь IP-адрес вашего Linux-хоста. В противном случае тест не сработает.

На это уйдет какое-то время, но в итоге вы должны увидеть, что в каждом team-сервере установлен маячок. Миссия выполнена!


Финальные штрихи:


Все отлично, но когда вам нужно изменить IP-адрес team-сервера или переадресатора, а также в случаях добавления записи, потребуется перезапускать сервер. Маячки, скорее всего, переживут этот процесс, но зачем рисковать, если есть лучшее решение? Можно использовать сигналы процесса, сообщая выполняющейся программе о необходимости перезагрузки файла конфигурации. Об этом трюке я впервые узнал от Мэтта Холта (Matt Holt), который реализовал его на прекрасном Caddy Server. На скрине снизу показана вся программа с уже добавленной логикой отправки сигнала процесса.

package main


import (

"bufio"

"fmt"

"log"

"os"

"os/signal"

"strings"

"sync"

"syscall"


"github.com/miekg/dns"

)


func parse(filename string) (map[string]string, error) {

records := make(map[string]string)

fh, err := os.Open(filename)

if err != nil {

return records, err

}

defer fh.Close()

scanner := bufio.NewScanner(fh)

for scanner.Scan() {

line := scanner.Text()

parts := strings.SplitN(line, ",", 2)

if len(parts) < 2 {

return records, fmt.Errorf("%s is not a valid line", line)

}

records[parts[0]] = parts[1]

}

log.Println("records set to:")

for k, v := range records {

fmt.Printf("%s -> %s\n", k, v)

}

return records, scanner.Err()

}


func main() {

var recordLock sync.RWMutex


records, err := parse("proxy.config")

if err != nil {

panic(err)

}


dns.HandleFunc(".", func(w dns.ResponseWriter, req *dns.Msg) {

if len(req.Question) == 0 {

dns.HandleFailed(w, req)

return

}

fqdn := req.Question[0].Name

parts := strings.Split(fqdn, ".")

if len(parts) >= 2 {

fqdn = strings.Join(parts[len(parts)-2:], ".")

}

recordLock.RLock()

match := records[fqdn]

recordLock.RUnlock()

if match == "" {

dns.HandleFailed(w, req)

return

}

resp, err := dns.Exchange(req, match)

if err != nil {

dns.HandleFailed(w, req)

return

}

if err := w.WriteMsg(resp); err != nil {

dns.HandleFailed(w, req)

return

}

})


go func() {

sigs := make(chan os.Signal, 1)

signal.Notify(sigs, syscall.SIGUSR1)


for sig := range sigs {

switch sig {

case syscall.SIGUSR1:

log.Println("SIGUSR1: reloading records")

recordLock.Lock()

parse("proxy.config")

recordLock.Unlock()

}

}

}()


log.Fatal(dns.ListenAndServe(":53", "udp", nil))


}

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

Перед обращением к карте в обработчике происходит вызов RLock для считывания значения в match. По завершении чтения вызывается RUnlock, освобождая карту для следующей горутины. В анонимной функции, выполняющейся в новой горутине, мы начинаем процесс прослушивания сигнала. Это делается с помощью канала типа os.Signal, передаваемого в вызове к signal.Notify() вместе с фактическим сигналом, получаемым каналом SIGUSR1, который сам является сигналом, зарезервированным для различных целей. В цикле перебора этих сигналов с помощью инструкции match определяется тип полученного сигнала.

Мы настроили мониторинг только одного сигнала, но в дальнейшем это можно изменить, так что данный шаблон окажется универсальным. В завершение перед перезагрузкой текущей конфигурации используется Lock() для блокирования всех горутин, которые могут попробовать произвести чтение из записей карты. Для продолжения выполнения применяется Unlock().

Давайте протестируем программу, запустив прокси и создав новый слушатель в существующем team-сервере. Используйте домен attacker3.com. При запущенном прокси измените файл proxy.config, добавив новую строку, направляющую домен на слушатель. Сигнализировать процессу о необходимости перезагрузки конфигурации можно с помощью kill, но сначала используйте ps и grep для определения его ID процесса:

Написание DNS-серверов Linux, Хакеры, Информационная безопасность, Взлом, Google, Интернет, Длиннопост

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

ССЫЛКА НА ТЕЛЕГРАМ КАНАЛ АВТОРА

Показать полностью 17
3

Необходимый минимум для фронтендера

Скажите честно, что действительно необходимо для того чтобы стать джуном фронтендером. Нужно ли досканально изучать typescript и подобные темы или достаточно основ html/css/js? Расскажите по подробнее что конкретно вы знали, когда устраивались на своё первое рабочее место джуном

3

Атомарные обновления в Zustand

Атомарные обновления в Zustand Кросспостинг, Pikabu Publish Bot, Frontend, React, Текст, Telegram (ссылка)

Я уже упоминал атомарные обновления ранее, когда говорил о проблемах контекста реакта.

Я называю обновления атомарными, если компонент обновляется только тогда, когда изменяются данные, которые он использует. У контекста реакта с этим большие проблемы, но и при использовании Zustand можно выстрелить себе в ногу.

Zustand сравнивает по ссылке предыдущее и текущее значение, возвращаемое из useStore(), и если объект изменился — происходит ре-рендер.

❌ В следующем примере у нас всегда будет возвращаться новый объект, и ре-рендер произойдёт даже если изменился только age, а lastName и firstName не изменились

const {firstName, lastName} = useStore(({firstName, lastName}) => ({firstName, lastName}));

Аналогичное поведение будет и в следующем случае

const {firstName, lastName} = useStore();

✅ Есть три варианта использования значений из стейта, которые поддерживают атомарные обновления:

1️⃣ Одиночные селекторы

const firstName = useStore((state) => state.firstName)
const lastName = useStore((state) => state.lastName)


2️⃣ Селектор, который возвращает объект + shallow - функция сравнения предыдущего и нового стейтов

const {firstName, lastName} = useStore(({firstName, lastName}) => ({
firstName,
lastName
}), shallow);


3️⃣ Автосгенерированных селекторы

const firstName = useStore.use.firstName();
const lastName = useStore.use.lastName();


Накидал небольшую демку в Codesandbox

https://t.me/cherkashindev/133

Показать полностью
6

AI для JavaScript и его применение в бизнес автоматизации


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

AI для JavaScript и его применение в бизнес автоматизации IT, Программирование, Удаленная работа, Разработка, Веб-разработка, Гифка, Длиннопост

Интерфейс платформы

Недавно в узле JavaScript, который может быть частью ваших разработок, появился ИИ ассистент, который готов закрывать весь объем работ, связанный с кодом:

  • написание

  • отладка ошибок

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

  • дальнейшая модификация

Как воспользоваться ИИ ассистентом?

Ассистент находится внутри JavaScript узла. Общение происходит в диалоговом окне ‘AI Chat’. В свою очередь, нейронка Нодуля обладает следующими навыками:

  • Возможность видеть ваш сценарий и структуру узлов

  • Способность анализировать уже имеющийся код в ноде JavaScript, откуда ассистент и был вызван

  • Доступ к структуре данных по левую сторону от JS узла.

AI для JavaScript и его применение в бизнес автоматизации IT, Программирование, Удаленная работа, Разработка, Веб-разработка, Гифка, Длиннопост

Сценарии использования

Прелесть AI ассистента на Нодуле в том, что он совершил семимильный шаг по пути реализации нашей миссии: теперь создание собственных микросервисов или построение сложных автоматизаций доступно даже тем, кто до этого в жизни с кодом не взаимодействовал! Рассмотрим 3 сценария использования, чтобы это доказать.

Сценарий #1 Работа с HTML

Рассмотрим сценарий, где нам нужна форма для сбора данных, которая будет доступна по webhook url. Такое решение может пригодиться в тысяче разных случаев. Сначала мы заполняем форму, а дальше информация передается куда вздумается: либо на другую ветку автоматизации на Нодуле для дальнейших преобразований, либо в иную систему. Как насчёт построить такой сценарий без написания и строчки кода?

AI для JavaScript и его применение в бизнес автоматизации IT, Программирование, Удаленная работа, Разработка, Веб-разработка, Гифка, Длиннопост

форма для компоновки емейла для рассылки по базе данных пользователей

Шаг 1. Отправим ИИ ассистенту запрос

Привет! Добавь к моему коду скрипт для создания HTML кода для формы с названием ‘создать емейл’. В ней должны быть следующие поля для заполнения: ‘тема письма’, ‘обзор’, ‘заголовок’, ‘апдейты платформы’, ‘полезные материалы’, ‘другие новости’. Снизу расположи кнопку ‘отправить’. Оформи HTML красивым дизайном и форматированием. Верни результат в виде JSON объекта “html”

Шаг 2. Заменяем наш код на полученный результат.

AI для JavaScript и его применение в бизнес автоматизации IT, Программирование, Удаленная работа, Разработка, Веб-разработка, Гифка, Длиннопост

Шаг 3. Запускаем один раз наш сценарий.

Так JavaScript модуль вернет нам “html” JSON объект для использования его в webhook response, где помимо этого мы меняем параметр типа контента на text/html для корректного отображения формы по ссылке из нашего входного webhook. 

AI для JavaScript и его применение в бизнес автоматизации IT, Программирование, Удаленная работа, Разработка, Веб-разработка, Гифка, Длиннопост

Теперь, открывая ваш webhook url, вам отобразиться форма для сбора данных.

Шаг 4. Отправка полученных данных.

Единственное, что остаётся, это сделать так, чтобы полученная через форму информация передавалась на webhook другого сценария для дальнейшей с ней работы. Естественно, писать сами мы ничего не будем:

AI для JavaScript и его применение в бизнес автоматизации IT, Программирование, Удаленная работа, Разработка, Веб-разработка, Гифка, Длиннопост

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

AI для JavaScript и его применение в бизнес автоматизации IT, Программирование, Удаленная работа, Разработка, Веб-разработка, Гифка, Длиннопост

Сценарий #2 Доступ к NPM пакетам

В мире насчитывается более миллиона NPM пакетов (готовые приложения для программистов, которое они добавляют в свой код), доступ к которым вам может обеспечить ИИ ассистент на Нодуле. Предположим, в вашем сценарии понадобился актуальный обменный курс USD/EUR для осуществления торговли в разных валютах и предоставления актуальной информации на сайте для клиентов. Нежели мучать себя поиском нужной API и чтением документации, озвучьте ваш запрос следующим образом:

AI для JavaScript и его применение в бизнес автоматизации IT, Программирование, Удаленная работа, Разработка, Веб-разработка, Гифка, Длиннопост

Для реализации задачи ассистент использует NPM библиотеку axios для отправки HTTP-запроса GET к ExchangeRate-API, который предоставляет последние обменные курсы. Он получает обменный курс 1 доллара США к 1 Евро и возвращает его в формате JSON.

Корректный результат не всегда достигается с первого раза: иногда получаем ошибки, иногда пустые значения на выходе. Главное не забывать, что отладка ошибок – это тоже не наша забота. Чтобы все было исправлено, попросите ИИ добавить в код console.log для детализации серверного ответа. Далее, возвращаете любую ошибку в чат с ИИ – и новый код перед глазами!

Сценарий #3 Преобразование данных

Также вы можете забыть о головной боли при преобразовании данных, таких как, например, форматирование даты. Вам ведь знакомо, когда системы отдают дату в одном формате, например, "YYYY-MM-DD", но другая система должна их принять в другом – “DD MMMM YYYY”

AI для JavaScript и его применение в бизнес автоматизации IT, Программирование, Удаленная работа, Разработка, Веб-разработка, Гифка, Длиннопост

Результат преобразования полученной через webhook даты формата ‘2023-07-11’:

AI для JavaScript и его применение в бизнес автоматизации IT, Программирование, Удаленная работа, Разработка, Веб-разработка, Гифка, Длиннопост

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

Альтернативный режим использования

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

AI для JavaScript и его применение в бизнес автоматизации IT, Программирование, Удаленная работа, Разработка, Веб-разработка, Гифка, Длиннопост

Сообщество лоу-код энтузиастов

В настоящее время сообщество платформы Нодуль активно набирает обороты и специалисты в области low-code присоединяются к нашему чату, где команда проекта рада фидбеку и готова помочь со всеми вопросами!

Важная ремарка: платформа находиться в бета и предоставляет бесплатный доступ для всех желающих!

Ждем вас на Нодуле и в Телеграмм сообществе!

Показать полностью 10

История gRPC от Google до open source

gRPC - это система удаленного вызова процедур (RPC) с открытым исходным кодом, которая была разработана в Google в 2015 году. Она использует HTTP/2 в качестве транспортного протокола и Protocol Buffers в качестве языка описания интерфейса и формата данных. gRPC позволяет определить и реализовать четыре типа сервисных методов: унарный, серверный потоковый, клиентский потоковый и двунаправленный потоковый. gRPC также поддерживает различные функции, такие как аутентификация, сжатие, отмена, тайм-ауты и метаданные.

История gRPC от Google до open source Инновации, Технологии, IT, Программирование, Разработка, Web, Программист

История gRPC началась с разработки внутренней системы RPC в Google под названием Stubby. Stubby был создан для обеспечения высокопроизводительной и надежной связи между микросервисами в распределенных системах. Stubby использовал Protocol Buffers для сериализации данных и HTTP/2 для передачи данных. Stubby также предоставлял различные функции, такие как балансировка нагрузки, отказоустойчивость, трассировка, мониторинг и безопасность.

В 2015 году Google решил выложить Stubby в открытый доступ под новым названием gRPC. Целью этого шага было расширить использование RPC во внешних проектах и сообществах, а также сделать RPC более доступным и универсальным для разных языков программирования и платформ. Google также хотел продвигать стандартизацию и совместимость RPC между разными системами.

С тех пор gRPC получил широкое распространение и признание в индустрии. Он используется многими компаниями и организациями, такими как Netflix, Cisco, Square, IBM, Docker, CoreOS и другими. Он также поддерживает множество языков программирования, таких как C#, C++, Dart, Go, Java, Kotlin, Node.js, Objective-C, PHP, Python, Ruby и Swift. Он также имеет большое и активное сообщество разработчиков и пользователей на GitHub и других платформах.

Интересные факты и фичи языков программирования у нас в канале, заходи :)

Показать полностью

Ведение блога о веб-дизайне в Telegram: Платформа для Инсайтов и Вдохновения

Ведение блога о веб-дизайне в Telegram: Платформа для Инсайтов и Вдохновения IT, Дизайн, Digital, Разработка, Программирование, Удаленная работа, Веб-дизайн, Дизайнер, Новости, Ux, Ui, Telegram, Канал, Сайт, Длиннопост, Telegram (ссылка)

Введение:

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

1. Преимущества блога в Telegram:

Ведение блога о веб-дизайне в Telegram: Платформа для Инсайтов и Вдохновения IT, Дизайн, Digital, Разработка, Программирование, Удаленная работа, Веб-дизайн, Дизайнер, Новости, Ux, Ui, Telegram, Канал, Сайт, Длиннопост, Telegram (ссылка)

Telegram предлагает ряд преимуществ для ведения блога о веб-дизайне:

- Широкая аудитория: Telegram имеет миллионы активных пользователей по всему миру, что позволяет достичь большей аудитории и получить обратную связь от разных людей.

- Простота использования: Создание и управление каналом в Telegram очень просто, что позволяет сосредоточиться на контенте и взаимодействии с подписчиками.

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

2. Содержание блога:

Ведение блога о веб-дизайне в Telegram: Платформа для Инсайтов и Вдохновения IT, Дизайн, Digital, Разработка, Программирование, Удаленная работа, Веб-дизайн, Дизайнер, Новости, Ux, Ui, Telegram, Канал, Сайт, Длиннопост, Telegram (ссылка)

Для успешного ведения блога о веб-дизайне в Telegram, важно предлагать интересный и полезный контент.

Вот несколько идей для контента:

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

- Обзоры и анализы: Рассматривайте новые тренды, инструменты и технологии веб-дизайна, а также проводите обзоры наиболее интересных проектов.

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

3. Взаимодействие с аудиторией:

Ведение блога о веб-дизайне в Telegram: Платформа для Инсайтов и Вдохновения IT, Дизайн, Digital, Разработка, Программирование, Удаленная работа, Веб-дизайн, Дизайнер, Новости, Ux, Ui, Telegram, Канал, Сайт, Длиннопост, Telegram (ссылка)

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

4. Сетевое взаимодействие:

Ведение блога о веб-дизайне в Telegram: Платформа для Инсайтов и Вдохновения IT, Дизайн, Digital, Разработка, Программирование, Удаленная работа, Веб-дизайн, Дизайнер, Новости, Ux, Ui, Telegram, Канал, Сайт, Длиннопост, Telegram (ссылка)

Не забывайте о возможностях сетевого взаимодействия в Telegram. Присоединяйтесь к другим каналам и группам, связанным с веб-дизайном, чтобы быть в курсе последних новостей и трендов. Общайтесь с коллегами и другими экспертами в сфере, чтобы обменяться опытом и получить новые идеи.

5. Регулярность и качество контента:

Ведение блога о веб-дизайне в Telegram: Платформа для Инсайтов и Вдохновения IT, Дизайн, Digital, Разработка, Программирование, Удаленная работа, Веб-дизайн, Дизайнер, Новости, Ux, Ui, Telegram, Канал, Сайт, Длиннопост, Telegram (ссылка)

Для успешного ведения блога в Telegram важно предлагать регулярный и качественный контент. Установите расписание публикаций и придерживайтесь его, чтобы ваши подписчики знали, что они могут ожидать нового материала от вас. Используйте разнообразные форматы контента, такие как текстовые посты, изображения, видео или даже интерактивные опросы, чтобы сделать ваш блог более привлекательным и разнообразным.

Заключение:

Ведение блога о веб-дизайне в Telegram: Платформа для Инсайтов и Вдохновения IT, Дизайн, Digital, Разработка, Программирование, Удаленная работа, Веб-дизайн, Дизайнер, Новости, Ux, Ui, Telegram, Канал, Сайт, Длиннопост, Telegram (ссылка)

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

Наш канал о дизайне:

Отдельное спасибо за подписку, тебе не сложно, а нас это мотивирует создавать контент ❤

Канал в тг

Показать полностью 6
3

TypeScript — satisfy или as

TypeScript — satisfy или as Кросспостинг, Pikabu Publish Bot, Typescript, Текст

Я думаю все знают о ключевом слове `as` в TypeScript. Мы используем его, когда нужно явно указать тип выражения, будь то переменная или функция. Когда мы используем `as`, происходит изменение типа выражения.

В TypeScript 4.9 появился оператор satisfies, который похож на оператор as, но работает немного иначе.

ℹ️ Он также проверяет, что выражение соответствует типу, но не изменяет его (тип).

Разницу легко увидеть на картинке.

При использовании as изменяется тип на Color, и мы теряем информацию об исходном типе объекта. Поэтому у нас появляется ошибка в месте вызова myColor.value.toUpperCase() , потому что компилятор думает, что value может быть также типа RGB, у которого нет метода toUpperCase .

При использовании satisfies ошибки нет, потому что исходная информация о типе сохранена.

Ещё по теме:

- Typescript’s new ‘satisfies’ operator
- Announcing TypeScript 4.9 Beta — The `satisfies` Operator

https://t.me/cherkashindev/116

Показать полностью
Отличная работа, все прочитано!