altcha-1.0.0/tests/src/Functional/AltchaBasicTest.php

tests/src/Functional/AltchaBasicTest.php
<?php

namespace Drupal\Tests\altcha\Functional;

use Drupal\Component\Utility\Html;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Url;
use Drupal\Tests\BrowserTestBase;
use Drupal\user\UserInterface;

/**
 * Test basic functionality for the ALTCHA module.
 *
 * @group altcha
 *
 * @dependencies captcha
 */
class AltchaBasicTest extends BrowserTestBase {

  use StringTranslationTrait;

  /**
   * A normal user.
   *
   * @var \Drupal\user\UserInterface
   */
  protected UserInterface $normalUser;

  /**
   * An admin user.
   *
   * @var \Drupal\user\UserInterface
   */
  protected UserInterface $adminUser;

  /**
   * The hmac key.
   *
   * @var string
   */
  protected string $secretKey;

  /**
   * Modules to enable.
   *
   * @var string[]
   */
  protected static $modules = ['altcha', 'captcha', 'user'];

  /**
   * {@inheritdoc}
   */
  protected $defaultTheme = 'stark';

  /**
   * The ALTCHA widget xpath selector.
   *
   * @var string
   */
  protected string $altchaSelector = '//input[@name="captcha_token"]';

  /**
   * The default ALTCHA library, included with the module.
   *
   * @var string
   */
  protected string $defaultLibrary = 'assets/vendor/altcha/altcha.min.js';

  /**
   * {@inheritdoc}
   */
  protected function setUp(): void {
    parent::setUp();
    \Drupal::moduleHandler()->loadInclude('captcha', 'inc');

    // Create a normal user.
    $this->normalUser = $this->drupalCreateUser();

    // Create an admin user.
    $permissions = [
      'access administration pages',
      'administer site configuration',
      'administer CAPTCHA settings',
      'skip CAPTCHA',
      'administer permissions',
      'administer altcha',
    ];

    $this->adminUser = $this->drupalCreateUser($permissions);
  }

  /**
   * The hmac secret key.
   */
  protected function testInstallation(): void {
    $this->assertNotEmpty($this->secretKey);
    $this->assertEquals(64, strlen($this->secretKey));
  }

  /**
   * Test access to the administration page.
   */
  public function testAdminAccess(): void {
    $this->drupalLogin($this->adminUser);

    $this->drupalGet('admin/config/people/captcha/altcha');
    $this->assertSession()->pageTextNotContains($this->t('Access denied'));

    $this->drupalLogout();
  }

  /**
   * Test the ALTCHA settings form.
   */
  public function testSettingsForm(): void {
    $this->drupalLogin($this->adminUser);

    $this->drupalGet('admin/config/people/captcha/altcha');

    $this->drupalLogout();
  }

  /**
   * Testing the protection of the user login form.
   */
  public function testLoginForm(): void {
    // Validate login process.
    $this->drupalLogin($this->normalUser);
    $this->drupalLogout();

    $this->drupalGet('user/login');

    // ALTCHA should not be configured yet.
    $this->assertSession()->elementNotExists('xpath', $this->altchaSelector);

    // Enable 'altcha/ALTCHA' on login form.
    captcha_set_form_id_setting('user_login_form', 'altcha/ALTCHA');
    $result = captcha_get_form_id_setting('user_login_form');

    // ALTCHA should be configured.
    $this->assertNotNull($result, 'A configuration has been found for CAPTCHA point: user_login_form');
    $this->assertEquals($result->getCaptchaType(), 'altcha/ALTCHA', 'Altcha type has been configured for CAPTCHA point: user_login_form');

    // Test the sentinel API version.
    $this->config('altcha.settings')
      ->set('integration_type', 'sentinel_api')
      ->save();
    $this->config('altcha.settings')->set('sentinel_api_url', 'https://example.com')->save();
    $this->config('altcha.settings')->set('sentinel_api_key', 'key_hello')->save();
    $this->config('altcha.settings')->set('sentinel_api_secret', 'sec_test')->save();

    $options = [
      'query' => [
        'apiKey' => 'key_hello',
      ],
    ];

    $this->drupalGet('user/login');

    // An ALTCHA should exist with challenge url matching the configuration.
    $this->assertSession()->elementExists('xpath', $this->altchaSelector);
    $this->assertSession()
      ->responseContains(Html::escape(Url::fromUri('https://example.com/v1/challenge', $options)
        ->toString()));

    // Test the API SAAS version.
    $this->config('altcha.settings')
      ->set('integration_type', 'saas_api')
      ->save();
    $this->config('altcha.settings')->set('saas_api_key', 'test')->save();
    $this->config('altcha.settings')->set('saas_api_region', 'eu')->save();
    $this->config('altcha.settings')->set('max_number', 20000)->save();

    $options = [
      'query' => [
        'apiKey' => 'test',
        'maxnumber' => 20000,
      ],
    ];

    $this->drupalGet('user/login');

    // An ALTCHA should exist with challenge url matching the configuration.
    $this->assertSession()->elementExists('xpath', $this->altchaSelector);
    $this->assertSession()
      ->responseContains(Html::escape(Url::fromUri('https://eu.altcha.org/api/v1/challenge', $options)
        ->toString()));

    // Test the Self-hosted version.
    $this->config('altcha.settings')
      ->set('integration_type', 'self_hosted')
      ->save();
    \Drupal::service('altcha.secret_manager')->generateSecretKey();

    $this->drupalGet('user/login');
    $this->assertSession()->elementExists('xpath', $this->altchaSelector);
    $this->assertSession()
      ->responseContains(Html::escape(Url::fromRoute('altcha.challenge')
        ->toString()));

    // Check auto verification attribute.
    $this->config('altcha.settings')
      ->set('auto_verification', 'onsubmit')
      ->save();
    $this->drupalGet('user/login');
    $element = $this->xpath('//altcha-widget[@auto="onsubmit"]');
    $this->assertNotEmpty($element, 'auto verification should be enabled and onsubmit.');

    // Check the maxnumber attribute.
    $this->config('altcha.settings')->set('max_number', 10000)->save();
    $this->drupalGet('user/login');
    $element = $this->xpath('//altcha-widget[@maxnumber="10000"]');
    $this->assertNotEmpty($element, 'maxnumber should be enabled and equal to 10000');

    // Validate that the login attempt fails.
    $edit['name'] = $this->normalUser->getAccountName();
    $edit['pass'] = $this->normalUser->getPassword();

    $this->drupalGet('user/login');
    $this->submitForm($edit, $this->t('Log in'));
    $this->assertSession()
      ->pageTextContains($this->t('The answer you entered for the CAPTCHA was not correct.'));

    // Make sure the user did not start a session.
    $this->assertFalse($this->drupalUserIsLoggedIn($this->normalUser));
  }

  /**
   * Tests if the library override works.
   *
   * By default, the module library should be added to an ALTCHA form.
   * When a library override is configured the override library should be added
   * to the form and not the default library.
   *
   * Test the 4 possible override methods:
   *  - CDN
   *  - Stream wrapper (file uri)
   *  - Path relative to drupal root
   *  - Path relative to server root
   */
  public function testLibraryOverrideUrl() {
    // Enable 'altcha/ALTCHA' on login form.
    captcha_set_form_id_setting('user_login_form', 'altcha/ALTCHA');
    $result = captcha_get_form_id_setting('user_login_form');

    // ALTCHA should be configured.
    $this->assertNotNull($result, 'A configuration has been found for CAPTCHA point: user_login_form');
    $this->assertEquals($result->getCaptchaType(), 'altcha/ALTCHA', 'Altcha type has been configured for CAPTCHA point: user_login_form');

    // Now go to the login page where the ALTCHA form will be rendered.
    $this->drupalGet('user/login');

    // An ALTCHA should exist.
    $this->assertSession()->elementExists('xpath', $this->altchaSelector);

    // The default library should be loaded via script tag.
    $this->assertSession()->elementExists('xpath', "//head//script[contains(@src, '{$this->defaultLibrary}')]");

    // 1. Library override CDN url.
    $this->validateLibraryOverride(
      'https://cdn.example.com/js/altcha.min.js',
      'https://cdn.example.com/js/altcha.min.js',
    );

    // 2. Library override public file uri.
    $this->validateLibraryOverride(
      'public://libraries/altcha/js/altcha-public-fs-library.min.js',
      'files/libraries/altcha/js/altcha-public-fs-library.min.js',
    );

    // 3. Library override url relative to the drupal web root.
    $this->validateLibraryOverride(
      'libraries/js/altcha-relative-path-library.min.js',
      'libraries/js/altcha-relative-path-library.min.js',
    );

    // 4. Library override url absolute to the server root.
    $this->validateLibraryOverride(
      \Drupal::root() . '/libraries/js/altcha-absolute-path-library.min.js',
      'libraries/js/altcha-absolute-path-library.min.js',
    );
  }

  /**
   * Helper function to validate library overrides.
   *
   * @param string $override
   *   The override to be configured in ALTCHA settings.
   * @param string $expectation
   *   The expected script src to be loaded in the html head.
   */
  protected function validateLibraryOverride(string $override, string $expectation): void {
    $this->config('altcha.settings')->set('library_override', $override)->save();

    // Reload the login page to apply the changes.
    $this->drupalGet('user/login');
    // An ALTCHA should still exist on the form.
    $this->assertSession()->elementExists('xpath', $this->altchaSelector);

    // Verify that the script tag with the library URL is added to the page.
    // We expect this to be in the <head> section of the page.
    $this->assertSession()->elementExists('xpath', "//head//script[contains(@src, '$expectation')]");
    // The default library should not be available.
    $this->assertSession()->elementNotExists('xpath', "//head//script[contains(@src, '{$this->defaultLibrary}')]");

    // When the override does not exactly match the expectation, make sure the
    // override is not just included in the page without any manipulation.
    // Example: "//head//script[contains(@src, 'libraries/altcha.js')]" xpath
    // would also match the override "/var/www/html/libraries/altcha.js".
    if ($override !== $expectation) {
      $this->assertSession()->elementNotExists('xpath', "//head//script[contains(@src, '$override')]");
    }
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc