• Как на JavaScript расшифровать строку с помощью ключа?

    alsolovyev
    @alsolovyev
    ¯\_(ツ)_/¯ Enjoy life, Eat well & Laugh often
    Так (для nodejs)?
    const crypto = require("crypto");
    
    const encryptedData =
      "jPNGTNLtGIBc7Jv2UXj7a3FNQk13eUJ5T3VIUXlOS0ZVOEpnMUpPMnhvQXg5bE5kMGFHejVxaTFnYTA9";
    const key = "qEExPE+jkJxQUt8fSO+XwzXgRGh6kLHy+lWEe6Z8T6s=";
    
    const decodedKey = Buffer.from(key, "base64");
    const decodedData = Buffer.from(encryptedData, "base64");
    const ivLength = 16; 
    
    const iv = decodedData.slice(0, ivLength);
    const encryptedText = decodedData.slice(ivLength);
    
    const decipher = crypto.createDecipheriv("aes-256-cbc", decodedKey, iv);
    
    try {
      let decrypted = decipher.update(encryptedText, null, "utf8");
      decrypted += decipher.final("utf8");
      console.log("Расшифрованная строка:", decrypted);
    } catch (error) {
      console.error("Ошибка расшифровки:", error.message);
    }
    Ответ написан
    4 комментария
  • Как на JavaScript расшифровать строку с помощью ключа?

    @ab1
    Key лучше обрезать до qEExPE+jkJxQUt8fSO+XwzXgRGh6kLHy
    и установить padding в None тогда работает в обе стороны
    6723ee70cea23058961837.png
    6723ee79b6a60901668459.png
    Ответ написан
    2 комментария
  • Как на JavaScript расшифровать строку с помощью ключа?

    Lynn
    @Lynn
    nginx, js, css
    С подсказкой от ab1 стало понятно что в PHP ключ (key) не декодируется из base64, а используется как есть. Т.е. из этой строки используются только 32 байта, а остальное просто мусор.

    И тогда всё работает.

    # key
    $ echo qEExPE+jkJxQUt8fSO+XwzXgRGh6kLHy+lWEe6Z8T6s= | xxd -l 32 -ps -c 256
    7145457850452b6a6b4a785155743866534f2b58777a5867524768366b4c4879
    # iv
    $ echo jPNGTNLtGIBc7Jv2UXj7a3FNQk13eUJ5T3VIUXlOS0ZVOEpnMUpPMnhvQXg5bE5kMGFHejVxaTFnYTA9 | base64 -d | xxd -l 16 -ps 
    8cf3464cd2ed18805cec9bf65178fb6b
    # encrypted text
    $ echo jPNGTNLtGIBc7Jv2UXj7a3FNQk13eUJ5T3VIUXlOS0ZVOEpnMUpPMnhvQXg5bE5kMGFHejVxaTFnYTA9 | base64 -d | cut -b 17-
    qMBMwyByOuHQyNKFU8Jg1JO2xoAx9lNd0aGz5qi1ga0=
    # результат
    $ echo qMBMwyByOuHQyNKFU8Jg1JO2xoAx9lNd0aGz5qi1ga0= | openssl AES-256-CBC -d -a -K 7145457850452b6a6b4a785155743866534f2b58777a5867524768366b4c4879 -iv 8CF3464CD2ED18805CEC9BF65178FB6B
    /playlist.m3u8+1729705980


    Ну и код на JS используя встроенный crypto.subtle:
    // Вспомогательные функции
    const B = (str) => Uint8Array.from(str, c => c.charCodeAt(0));
    const S = (buf) => String.fromCharCode(...new Uint8Array(buf));
    
    // дано
    const encryptedData = "jPNGTNLtGIBc7Jv2UXj7a3FNQk13eUJ5T3VIUXlOS0ZVOEpnMUpPMnhvQXg5bE5kMGFHejVxaTFnYTA9";
    const key = "qEExPE+jkJxQUt8fSO+XwzXgRGh6kLHy+lWEe6Z8T6s=";
    
    const iv = B(atob(encryptedData).slice(0, 16));
    const cryptoKey = await crypto.subtle.importKey(
    	'raw',
    	// На самом деле используется только 32 байта из key
    	B(key.slice(0, 32)),
    	'AES-CBC',
    	true,
    	['encrypt', 'decrypt']
    );
    
    const encryptedText = B(atob(atob(encryptedData).slice(16)));
    
    let decrypted = S(await crypto.subtle.decrypt({ name: 'AES-CBC', iv }, cryptoKey, encryptedText));
    
    console.log(decrypted); // /playlist.m3u8+1729705980
    Ответ написан
    2 комментария
  • Почему я получаю ошибку invalid operation: err (variable of type Error) is not an interface при проверке типа переменной?

    Я полностью присоединюсь к ответу выше, просто хочу дополнить.

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

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

    package main
    
    import (
    	"fmt"
    )
    
    type MyError struct {
    	Message string
    }
    
    func (e MyError) Error() string {
    	return e.Message
    }
    
    func main() {
    	// Возвращаем из функции нашу кастомную ошибку, но в виде интерфейса error
    	err := foo()
    
    	if err == nil {
    		fmt.Println("Нет ошибки")
    	// И теперь тут приводим error к нашему типу MyError и проверяем
    	} else if myErr, ok := err.(MyError); ok {
    		fmt.Printf("Ура! Нужный нам тип ошибки: %v\n", myErr.Message)
    	} else {
    		fmt.Println("Какой-то другой тип ошибки:", err)
    	}
    
    	// Проверка одной из "подстав" Go
    
    	err = bad()
    	if err != nil {
    		fmt.Println("Упс... Как так... Не nil...")
    	} else {
    		fmt.Println("Должно вывестись это, но не выводится...")
    	}
    
    	err = good()
    	if err != nil {
    		fmt.Println("Это не должно выводиться, всё верно.")
    	} else {
    		fmt.Println("Ошибки нет, всё верно.")
    	}
    }
    
    func foo() error {
    	err := MyError{"Ой! Ошибка MyError!"}
    	// err := fmt.Errorf("Ой! Обычная ошибка!")
    	// var err error = nil
    	return err
    }
    
    func bad() error {
    	var p *MyError = nil // Вроде же nil, но не работает....
    	// p = &MyError{"Ой!"} // Пробуем создать ошибку, и всё работает.
    
    	if p == nil {
    		fmt.Println("Ну nil же-ж... Должно же-ж работать", p)
    	}
    
    	return p
    }
    
    func good() error {
    	// return MyError{"Ой!"}
    
            // Буквально пишем "nil", никаких указателей, которые равны nil, это прямой выстрел в ногу
    	return nil
    }


    https://go.dev/play/p/2YcWcH9oqel
    Ответ написан
    Комментировать
  • Какой фреймворк для Go изучать в 2024 году?

    Если http:
    Взять какой-нибудь хороший роутер, например https://github.com/julienschmidt/httprouter
    И на его основе сделать врапперы и мидлвари под себя по необходимости.
    Если работаете в какой-то конторе, то там уже должен быть фреймворк для микросервисов, заточенный под инфраструктуру компании. Потому что если сервисы делаются все по-разному, это беда.

    Если grpc:
    Особых вариантов нет, нужно использовать protoc.
    При необходимости подключить плагины, чтобы был сваггер и гейтвей в http
    github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway
    github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2

    Почему не предлагаю какой-то большой конкретный фреймфорк? Если бы вы сказали, что веб-приложения будете писать, можно было бы посоветовать что-то типа gin, но вы сказали про микросервисы. С ними такая специфика, что надо как конструктор собирать себе стек под задачу, иначе будет неудобно.
    Ответ написан
    3 комментария
  • Почему я получаю ошибку invalid operation: err (variable of type Error) is not an interface при проверке типа переменной?

    https://go.dev/play/p/eDi3J3Zzcdg

    package main
    
    import "fmt"
    
    type MyError struct {
    	Message string
    }
    
    func (e MyError) Error() string {
    	return e.Message
    }
    
    func (e MyError) Smth() {
    }
    
    type SomeInterface interface {
    	Smth()
    }
    
    func main() {
    	var err SomeInterface
    	err = MyError{"Something went wrong"}
    
    	// Проверяем, реализует ли err интерфейс error
    	if _, ok := err.(error); ok {
    		fmt.Println("err реализует интерфейс error")
    	} else {
    		fmt.Println("err НЕ реализует интерфейс error")
    	}
    }


    У вас получилось, что тип переменной err это структура, но нужно чтобы тип был каким-нибудь интерфейсом.

    В моем примере я создал интерфейс SomeInterface и добавил вашему типу метод, чтобы он этому интерфейсу удовлетворял. Теперь данный ассершн имеет смысл.

    P.S. С пустым интерфейсом тоже работать будет https://go.dev/play/p/Yz0M1Wzopua
    Ответ написан
    Комментировать
  • Зачем в языке Go приняты отступы в 8 символов?

    Там не 8 символов, там tab. Вы можете настроить в вашем текстовом редакторе размер табуляции в нужное вам количество символов.
    Ответ написан
    Комментировать
  • Почему при выборке первых трех строк, MySQL просматривает все записи таблицы?

    @Akina
    Сетевой и системный админ, SQL-программист.
    почему этот запрос просматривает так много записей?


    Таков принцип работы у этой СУБД. MySQL сначала выбирает все соответствующие условиям отбора записи, и только потом применяет к ним ограничение количества. Правда, обычно в запросе ещё присутствует и сортировка.

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

    Мне возвращается первые 3 строки.

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

    Вот, полюбопытствуйте: FIDDLE. Кстати, забавно, что без хинта оптимизатор выбирает вовсе даже не первичный индекс... Более того, в данном конкретном случае этому есть совершенно точное и строгое объяснение - попробуйте его найти.
    Ответ написан
    Комментировать
  • Почему при выборке первых трех строк, MySQL просматривает все записи таблицы?

    @Everything_is_bad
    Без явно указания сортировки, каждая субд по разному интерпретируют "первые" строки. Всегда явно задавай поле по которые должен считаться порядок.
    Ответ написан
    Комментировать
  • Как правильно настроить локальное окружение для веб-разработки на Go?

    Есть достаточно много утилит, которые могут следить за папкой с исходниками и пересобирать приложение.
    Например https://github.com/cosmtrek/air

    Ну и для разработки будет гораздо быстрее и удобнее запускать не в докере, билдя каждый раз контейтер, а использовать go run
    Ответ написан
    Комментировать
  • Как в RabbitMQ обработать все сообщения а затем удалить очередь и закрыть соединение?

    @yarkin
    Я не из мира PHP, но полагаю что можно попробовать basic_get вместо basic_consume, или попробовать опцию $nowait=true
    Ответ написан
    Комментировать
  • Как в RabbitMQ обработать все сообщения а затем удалить очередь и закрыть соединение?

    mayton2019
    @mayton2019
    Bigdata Engineer
    Очередь - бесконечная по дизайну. Поэтому прикладной софт никогда сам не может решить
    прочитал-ли он последнее сообщение или нет. Сетевой протокол тоже в этом смысле не помошник
    потому-что шлет сообщения пачками и тоже нельзя гарантировать что пачка - последняя.

    Единственный разумный выход - если producer создает специальное сообщение-терминатор
    которое как-бы сигнализирует что все дескыть конец.
    Ответ написан
    Комментировать
  • Как в RabbitMQ обработать все сообщения а затем удалить очередь и закрыть соединение?

    2ord
    @2ord
    Странная затея насчёт удаления очереди.
    Ну если так надо, то отправляй сообщение о том, что окончились сообщения. Тогда обработчик очереди получит его и будет знать, что очередь можно удалять.
    Ответ написан
    Комментировать
  • Как узнать в какой кодировке строка и раскодировать ее?

    Rsa97
    @Rsa97
    Для правильного вопроса надо знать половину ответа
    Это запись в Windows-1251, отображаемая в UTF-8.
    Ä == 0xC4 == Д
    è == 0xE8 == и
    ð == 0xF0 == р
    ...
    Дирижёр Владимир Спиваков
    Ответ написан
    4 комментария
  • Как реализовывать JWT Symfony Logout?

    @apapacy
    Статья на которую Вы ссылаетесь содержит две распрстианенные ошибки в использовании JWT.
    1. JWT используется для того чтобы не нужно было ходить в базу данных за данными пользователеля. Данные пользователя хранятся в JWT. Это немного увеличивает нагрузку на сеть, но сразу снижает в два раза количество запросов в базу данных. А это критично для нагруженных сервисов. Кроме того позволяет вынести авторизацию в отдельный миуросервис.
    2. Вы наверное спросите а как же быть, если данные изменятся. Для этого сокращают время действия токена до минимального значения. Чтобы не проходить повторно процедуру авторизации, для возобновления действия этого токена выдается долгосрочный токен, предъявив котрый можно обновить краткосрочный токен и тем самым получить обновленные данные.

    Возникает вопрос а что делать если пользователь был забанен или как в вашем случае разлогинился. Или просто его критически важные данные поменялись. Для этого организуют реестр аннулирования токенов, в котором записи хранятся на время действия токена. Такой реестр будет иметь сравнительно небольшой размер так как время хранения краткосрочных токенов невысоко. Его лучше организовать на быстрой базе данных key/value.

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

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

    Про разлогине нужно еще иметь в виду что он всегда будет немного сбойной операцией. Так как во время разлогина может отсутствовать интернет и вызов api закончится со сбоем.
    Ответ написан
    Комментировать
  • Как в React отправлять стейт на сервер при каждом его изменении?

    TMProject
    @TMProject
    Frontend developer React/Redux
    //Перед обновление стейта сохраняешь текущую версию
    const oldState = { ...state }
    //Обновляешь стейт
    setState({ foo: 'bar' });
    
    //Этот код нужно выполнять в юзефект с депсами стейта
    //Это массив измененных свойств 
    const changedProperties = {};
    for (const key in state) {
      if (state.hasOwnProperty(key) && oldState[key] !== state[key]) {
        changedProperties[key] = state[key];
      }
    }
    
    //Проверяем если были обновления и отправляем
    if (Object.keys(changedProperties).length > 0) {
      fetch('/endpoint', {
        method: 'POST',
        body: JSON.stringify(changedProperties),
        headers: {
          'Content-Type': 'application/json'
        }
      }).then((response) => {
        if (response) {
          console.log('Данные успешно обновлены на сервере');
        } else {
          console.log('Не удалось обновить данные на сервере');
          // В случае ошибки апдейтп можно откатить  стейт
          setState(oldState);
      });
    }


    По коду сам смотри куда тебе проще запихнуть
    Ответ написан
    Комментировать
  • Как удалить коммиты на сайте GitLab?

    sergey-kuznetsov
    @sergey-kuznetsov Куратор тега Git
    Автоматизатор
    Нельзя. В веб-интерфейсе нет инструментов перебазирования или доступа к консоли.
    Но вы можете легко откатить изменения к тому состоянию, которое осталось локально.
    git push --force
    Ответ написан
    Комментировать
  • Знак вопроса перед параметром метода это ошибка в PHP?

    @vaajnur
    битриксоид
    Типы для параметров и возвращаемых значений могут быть помечены как обнуляемые путем добавления префикса в виде знака вопроса. Это означает, что указанные параметры и возвращаемые значения, могут быть как указанного типа, так и NULL.

    php.net/manual/ru/migration71.new-features.php
    Ответ написан
    Комментировать
  • Как привязать footer к низу экрана в Twitter Bootstrap?

    Sergei_Erjemin
    @Sergei_Erjemin
    Улыбайся, будь самураем...
    Блин… что за советы… там есть встроенный класс: navbar-fixed-bottom

    <div class="navbar-fixed-bottom row-fluid">
          <div class="navbar-inner">
              <div class="container">
    
    Ответ написан
    7 комментариев