• Почему bcrypt ложно срабатывает?

    LexxXell
    @LexxXell Автор вопроса
    Программист и немного IT-журналист
    Как выяснили в комментариях, проблема в длине токенов, т.к. bcrypt может принять в себя только 72 байта.

    Для конкретного случая - использование bcrypt для хеширования jwt токенов, можно использовать только сингатурную часть токена, в этом случае bcrypt работает.
    const jwt = require('jsonwebtoken');
    const bcrypt = require('bcryptjs');
    
    const payload = {
      sub: 1,
      email: 'testt@test.test'
    }
    
    const token1 = jwt.sign(payload, 'secret_1');
    const token1Signature = token1.split('.').pop()
    const token1SignatureHashed = bcrypt.hashSync(token1Signature, 5);
    
    const token2 = jwt.sign(payload, 'secret_2');
    const token2Signature = token2.split('.').pop()
    const token2SignatureHashed = bcrypt.hashSync(token2Signature, 5);
    
    console.log(`Token1 sig: ${token1Signature}\n`);
    console.log(`Token1 sig hashed: ${token1SignatureHashed}\n`);
    console.log(`Token2 sig: ${token2Signature}\n`);
    console.log(`Token2 sig hashed: ${token2SignatureHashed}\n`);
    
    console.log(`Compare token1Sig vs token1SigHashed: ${bcrypt.compareSync(token1Signature, token1SignatureHashed)}`);
    console.log(`Compare token1Sig vs token2SigHashed: ${bcrypt.compareSync(token1Signature, token2SignatureHashed)}`);
    console.log(`Compare token2Sig vs token2SigHashed: ${bcrypt.compareSync(token2Signature, token2SignatureHashed)}`);
    console.log(`Compare token2Sig vs token1SigHashed: ${bcrypt.compareSync(token2Signature, token1SignatureHashed)}`);

    Вывод в консоль:
    Token1 sig: Z_cIJxKYkQsUWbu1hiRBiFjQOVGehfvcEH1SxJtBBvM
    
    Token1 sig hashed: $2a$05$4yGh8r.YeNsrV3D9i/snMe6QMT1Pt7ZKBOlCZpSypcEdO4xZEnx7K
    
    Token2 sig: XCVtQYxAGDcMMqCQBIitRyok61zJhzcr3c6PZppID2I
    
    Token2 sig hashed: $2a$05$okXRKv85XY88Tg/RhBwuoOwNfGNtjVm8gFI8dzm79SXSvWMTKrULa
    
    Compare token1Sig vs token1SigHashed: true
    Compare token1Sig vs token2SigHashed: false
    Compare token2Sig vs token2SigHashed: true
    Compare token2Sig vs token1SigHashed: false
    Ответ написан
    Комментировать
  • Как правильно сделать поля createdAt, changedAt и lastActivityAt для модели в mongoose?

    LexxXell
    @LexxXell Автор вопроса
    Программист и немного IT-журналист
    Для полей createdAt и changedAt решение нашел.
    Mongoose 4+ поддерживает автоматическое создание вышеуказанных полей. Схема изменится так:
    const someSchema = mongoose.Schema(
        {
            lastActivityAt: { type: Date, default: Date.now },
        },
        { timestamps: true }
    )


    Касательно поля lastActivityAt, то я не нашел элегантного способа, и его придется обновлять "вручную" в коде, при обращении. Можно было бы использовать методы pre и post, но в конкретном случае это не подходит, т.к. изменять поле lastActivityAt нужно не при каждом обращении, я только для конкретных функций.
    Моё решение, получать экземпляр так:
    const instance = await someModel.findOne( <FilterQuery> )
        ? await someModel.findOneAndUpdate(
            <FilterQuery>,
            { lastActivityAt: Date.now() }
        )
        : await someModel.create( <ObjectQuery> );
    Ответ написан
    Комментировать
  • Как отключить автоматическое закрытие сессии в Selenium+Firefox?

    LexxXell
    @LexxXell Автор вопроса
    Программист и немного IT-журналист
    Как вариант решения - использовать созданный заранее профиль (в котором уже пройдена аутентификация в нужном сервисе), и подключать его при запуске:
    from selenium import webdriver
    from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
    from selenium.webdriver.firefox.options import Options as FirefoxOptnions
    
    webdriver_host = "http://127.0.0.1:4444/wd/hub"
    desired_capabilities = DesiredCapabilities.FIREFOX
    
    options = FirefoxOptnions()
    # Вот тут указываем путь к папке профиля
    options.profile = "../profiles/c63u9jz2.default-release-1" 
    
    driver = webdriver.Remote(
        webdriver_host,
        desired_capabilities,
        options=options,
    )


    Это позволит возобновлять сессию при перезапусках.
    Ответ написан
    Комментировать
  • Почему возникает ошибка при сериализации имени файла?

    LexxXell
    @LexxXell Автор вопроса
    Программист и немного IT-журналист
    Проверить какую ошибку выдаёт сериалайзер:
    print(file_serializer.errors)
    В конкретном случае ошибка в превышении длины строки имени файла:
    {'video_file': [ErrorDetail(string='Ensure this filename has at most 100 characters (it has 120).', code='max_length')]}

    По умолчанию длина была 100 символов.

    Решение - указать большую длину имени файла:
    video_file = models.FileField("Clip", upload_to=get_new_video_file_path, null=True, blank=True, max_length=255)
    Ответ написан
    Комментировать
  • Как в сериалайзере подменить значение полей на значения из родителя?

    LexxXell
    @LexxXell Автор вопроса
    Программист и немного IT-журналист
    Нашел решение
    Дописываем проперти в модель:
    class Clip(models.Model):
        parent = models.ForeignKey('self', on_delete=models.CASCADE, null=True, blank=True)
        name = models.CharField("Clip name", max_length=150)
        video_file = models.FileField("Clip", upload_to="clips", null=True)
        thumbnail = models.ImageField("Thumbnail", upload_to="thumbnails/", null=True)
        youtube_link = models.URLField("Link to clip on YouTube", blank=True)
    
        @property
        def get_name(self):
            if self.parent is not None:
                return Clip.objects.get(id=self.parent.id).name
            return self.name
    
        @property
        def get_artist(self):
            if self.parent is not None:
                return Clip.objects.get(id=self.parent.id).artist
            return self.artist
    
        @property
        def get_thumbnail(self):
            if self.parent is not None:
                return Clip.objects.get(id=self.parent.id).thumbnail.name
            return self.thumbnail.name
    
        @property
        def get_youtube_link(self):
            if self.parent is not None:
                return Clip.objects.get(id=self.parent.id).youtube_link
            return self.youtube_link


    а в сериализаторе обращаеся к ним по serializers.ReadOnlyField
    class ClipSerializer(serializers.ModelSerializer):
    
        name = serializers.ReadOnlyField(source="get_name")
        artist = serializers.ReadOnlyField(source="get_artist")
        thumbnail = serializers.ReadOnlyField(source="get_thumbnail")
        youtube_link = serializers.ReadOnlyField(source="get_youtube_link")
    
        class Meta:
            model = Clip
            exclude = [
                "video_file",
            ]


    Важно учитывать, что теперь это сериализатор преимущественно для GET запросов. Для POST и PUT запросов стоит создать копию исходного сериализатора и использовать его.
    Ответ написан
    Комментировать
  • Как Celery выполняет таски, последовательно или параллельно?

    LexxXell
    @LexxXell Автор вопроса
    Программист и немного IT-журналист
    Всё, разобрался. Роутинг, очереди и ограничение одновременно-выполняемых воркером задач.
    Ответ написан
    Комментировать
  • Какой софт нужен для интерактивного стрима по HL2?

    LexxXell
    @LexxXell Автор вопроса
    Программист и немного IT-журналист
    Судя по активности ответов. Проще самому написать, что в общем-то и сделал.
    Ответ написан
    Комментировать
  • Unity: Как отобразить несколько спрайтов в одном объекте?

    LexxXell
    @LexxXell Автор вопроса
    Программист и немного IT-журналист
    Распишу подробнее решение, которое предложил GavriKos.

    Скрипт должен выглядеть так:
    using UnityEngine;
    
    public class Wheel : MonoBehaviour {
    
      [SerializeField] // Теперь поле Cup появится у компонента скрипта в Inspector
      SpriteRenderer Cup;
    
      void OnMouseDown(){
        Cup.enabled = !Cup.enabled; // переключаем видимость спрайта
      }
    }


    В поле Cup, появившееся у компонента скрипта в Inspector, перетаскиваем из иерархии спрайт колпака.

    Все работает.
    Ответ написан
    Комментировать