Full Code of olssonm/l5-very-basic-auth for AI

master 59ae0468eb07 cached
21 files
36.1 KB
10.1k tokens
27 symbols
1 requests
Download .txt
Repository: olssonm/l5-very-basic-auth
Branch: master
Commit: 59ae0468eb07
Files: 21
Total size: 36.1 KB

Directory structure:
gitextract_4ggz17vw/

├── .editorconfig
├── .github/
│   ├── FUNDING.yml
│   └── workflows/
│       └── test.yml
├── .gitignore
├── LICENSE.md
├── README.jp.md
├── README.md
├── composer.json
├── phpstan.neon
├── phpunit.xml
├── src/
│   ├── Console/
│   │   └── GeneratePassword.php
│   ├── Handlers/
│   │   ├── DefaultResponseHandler.php
│   │   └── ResponseHandler.php
│   ├── Http/
│   │   └── Middleware/
│   │       └── VeryBasicAuth.php
│   ├── VeryBasicAuthServiceProvider.php
│   ├── config.php
│   └── resources/
│       └── views/
│           └── default.blade.php
└── tests/
    ├── Fixtures/
    │   └── CustomResponseHandler.php
    ├── Pest.php
    ├── TestCase.php
    └── VeryBasicAuthTest.php

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
; This file is for unifying the coding style for different editors and IDEs.
; More information at http://editorconfig.org

root = true

[*]
charset = utf-8
indent_size = 4
indent_style = space
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

[*.md]
trim_trailing_whitespace = false

[*.{yml,yaml}]
indent_size = 2


================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms

github: [olssonm]


================================================
FILE: .github/workflows/test.yml
================================================
name: Run tests

on:
  push:
  pull_request:

jobs:
  php-tests:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        php: [8.5, 8.4, 8.3, 8.2]
        laravel: ['12.*', '13.*']
        exclude:
          - laravel: 13.*
            php: 8.2
          - laravel: 12.*
            php: 8.5

    name: P${{ matrix.php }} - L${{ matrix.laravel }}

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: ${{ matrix.php }}
          extensions: dom, curl, libxml, mbstring, zip
          tools: composer:v2
          coverage: none

      - name: Install dependencies
        run: |
          composer require "illuminate/support:${{ matrix.laravel }}" --no-interaction --no-progress --no-suggest
          composer update --prefer-dist --no-interaction --no-progress

      - name: Execute tests
        run: composer test


================================================
FILE: .gitignore
================================================
/vendor
composer.lock
.DS_Store
.phpunit.result.cache
.phpunit.cache
phpunit-output


================================================
FILE: LICENSE.md
================================================
# The MIT License (MIT)

Copyright (c) 2024 Marcus Olsson <contact@marcusolsson.me>

> Permission is hereby granted, free of charge, to any person obtaining a copy
> of this software and associated documentation files (the "Software"), to deal
> in the Software without restriction, including without limitation the rights
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> copies of the Software, and to permit persons to whom the Software is
> furnished to do so, subject to the following conditions:
>
> The above copyright notice and this permission notice shall be included in
> all copies or substantial portions of the Software.
>
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> THE SOFTWARE.


================================================
FILE: README.jp.md
================================================
# Laravel Very Basic Auth

[![Latest Version on Packagist][ico-version]][link-packagist]
[![Total downloads][ico-downloads]][link-packagist]
[![Software License][ico-license]](LICENSE.md)
[![Build Status][ico-build]][link-build]

![very-basic-auth](https://user-images.githubusercontent.com/907114/40575964-331559ce-60ef-11e8-8366-aba700fc5567.png)

**利用可能なドキュメントは以下です:**

🇬🇧 [English](README.md)  
🇯🇵 [日本語](README.jp.md)

Laravel 5 Very Basic AuthはLaravel標準の`auth.basic`とは違い、実際のデータベースの情報を使うことなくBasic認証を追加します。

<img width="400" alt="Screenshot" src="https://user-images.githubusercontent.com/907114/29876493-3907afd8-8d9d-11e7-8068-f461855c493b.png">

例えば、開発中のサイトにユーザーをアクセスさせたい時や、まだデータベースやモデルを用意していない時に使うと便利です。あなたのサイトがデータベースを利用していない場合でも、アクセスを制御することができます。

認証に失敗した場合には、"401 Unauthorized"のレスポンスを返します。

#### 注意点

Basic認証は望まないユーザーからのアクセスを排除することができますが、ブルートフォース攻撃に対しては厳密には安全ではありません。もしこのパッケージをセキュリティのために単独で利用するのであれば、ログインの試行回数を制限するために、少なくともApacheかNginxのrate-limitersを確認するべきです。

## インストール

Composer経由

``` bash
$ composer require olssonm/l5-very-basic-auth
```

このパッケージのv4.* (for Laravel 5.5)以降では、サービスプロバイダーからパッケージを読み込むのに、パッケージのオートディスカバリーを使用しています。パッケージをインストールすると、以下のメッセージが表示されるはずです。

```
Discovered Package: olssonm/l5-very-basic-auth
```

もしも手動でプロバイダーに追加したい場合は、composer.jsonファイルでオートディスカバリーを切って、

``` json
"extra": {
    "laravel": {
        "dont-discover": [
            "olssonm/l5-very-basic-auth"
        ]
    }
},
```

(`config/app.php`)のprovidersにプロバイダーを追加してください。

``` php
'providers' => [
    Olssonm\VeryBasicAuth\VeryBasicAuthServiceProvider::class
]
```

## 設定

`$ php artisan vendor:publish`のコマンドを実行し、`Provider: Olssonm\VeryBasicAuth\VeryBasicAuthServiceProvider`を選んで設定ファイルを公開してください。`$ php artisan vendor:publish --provider="Olssonm\VeryBasicAuth\VeryBasicAuthServiceProvider"`でも設定ファイルを公開することができます。

`very_basic_auth.php`のファイルがあなたの`app/config`ディレクトリにコピーされます。ここにusernameやpasswordなどの幾つかの設定を置くことができます。

### 注意

**デフォルトのパスワードはありません。** セキュリティのために(誰もが同じパスワードになってしまわないように)、インストール時にランダムなパスワードが設定されます。個別のパスワードを設定するためにもパッケージ設定の公開をして下さい。

#### ビューとメッセージ

`very_basic_auth.php`ファイルでは、メッセージの代わりにカスタマイズしたビューを設定することができます。

``` php
// ユーザーがオプトアウトするか、キャンセルを押した場合に表示されるメッセージ
'error_message'     => 'You have to supply your credentials to access this resource.',

// エラーメッセージの代わりにviewを使いたい場合は"error_view"のコメントアウトを外して下さい。
// この場合、あなたのデフォルトのレスポンスメッセージよりもエラービューが優先されます。
// 'error_view'        => 'very_basic_auth::default'
```

`error_view`のコメントアウトを外した場合、ミドルウェアは指定されたviewを探そうとします。このビュー名は通常と同じように`.blade.php`の拡張子無しで設定してください。

*以前のバージョンから2.1にアップグレードする場合、このkeyとvalueは公開された設定には存在しないので、自分自身で設定を追加する必要があります。*

## 使い方

このミドルウェアはルートを保護するのに`auth.very_basic`の短縮キーを使います。`Route::group()`に適用して複数のルートを保護することもできますし、個別に保護するルートを選ぶこともできます。

**グループを使う場合**
``` php
Route::group(['middleware' => 'auth.very_basic'], function() {
    Route::get('/', ['as' => 'start', 'uses' => 'StartController@index']);
    Route::get('/page', ['as' => 'page', 'uses' => 'StartController@page']);
});
```

**単独で使う場合**
``` php
Route::get('/', [
    'as' => 'start',
    'uses' => 'StartController@index',
    'middleware' => 'auth.very_basic'
]);
```

認証情報をルート上に記述することもできます。

``` php
Route::get('/', [
    'as' => 'start',
    'uses' => 'StartController@index',
    'middleware' => 'auth.very_basic:username,password'
]);
```

*Note:* 認証情報をルート上に記述した場合、設定ファイルの`very_basic_auth.php`より優先されます。


## テスト

``` bash
$ composer test
```

または

``` bash
$ phpunit
```

テストを実行する際は、Laravelは常にenvironmentの値を"testing"にします。`testing`が`very_basic_auth.php`の`envs`配列内に存在することを確認して下さい。

## ライセンス

MITライセンスです。 詳しくはこちらを見てください。[License File](LICENSE.md)

© 2024 [Marcus Olsson](https://marcusolsson.me).

[ico-version]: https://img.shields.io/packagist/v/olssonm/l5-very-basic-auth.svg?style=flat-square
[ico-license]: https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square
[ico-build]: https://img.shields.io/github/workflow/status/olssonm/l5-very-basic-auth/Run%20tests.svg?style=flat-square&label=tests
[ico-downloads]: https://img.shields.io/packagist/dt/olssonm/l5-very-basic-auth.svg?style=flat-square
[link-packagist]: https://packagist.org/packages/olssonm/l5-very-basic-auth
[link-build]: https://github.com/olssonm/l5-very-basic-auth/actions?query=workflow%3A%22Run+tests%22


================================================
FILE: README.md
================================================
# Laravel Very Basic Auth

[![Latest Version on Packagist][ico-version]][link-packagist]
[![Total downloads][ico-downloads]][link-packagist]
[![Software License][ico-license]](LICENSE.md)
[![Build Status][ico-build]][link-build]

![very-basic-auth](https://user-images.githubusercontent.com/907114/40575964-331559ce-60ef-11e8-8366-aba700fc5567.png)

**Documentation available in:**

🇬🇧 [English](README.md)  
🇯🇵 [日本語](README.jp.md)

This package allows you to add a HTTP Basic Auth filter on your routes, without the need to use a database – which the Laravel default `auth.basic`-middleware relies on.

<img width="400" alt="Screenshot" src="https://user-images.githubusercontent.com/907114/29876493-3907afd8-8d9d-11e7-8068-f461855c493b.png">

Perfect when you want to give your clients access to your development site before you have yet to set up your database and/or models. Or perhaps your site doesn't even use a database and you still wish to keep it protected.

On failed authentication the user will get a "401 Unauthorized" response.

#### A thing to note

While HTTP Basic Auth does give you a protection layer against unwanted visitors, it is still not strictly safe from brute-force attacks. If you are solely using this package for security, you should at least consider looking into Apache or Nginx rate-limiters to limit login attempts.

## Installation

Via Composer

``` bash
$ composer require olssonm/l5-very-basic-auth
```

Since v4.* (for Laravel 5.5) this package uses Package Auto-Discovery for loading the service provider. Once installed you should see the message

```
Discovered Package: olssonm/l5-very-basic-auth
```

If you would like to manually add the provider, turn off Auto-Discovery for the package in your composer.json-file:

``` json
"extra": {
    "laravel": {
        "dont-discover": [
            "olssonm/l5-very-basic-auth"
        ]
    }
},
```

And then add the provider in the providers array (`config/app.php`).

``` php
'providers' => [
    Olssonm\VeryBasicAuth\VeryBasicAuthServiceProvider::class
]
```

## Configuration

Run the command `$ php artisan vendor:publish` and select `Provider: Olssonm\VeryBasicAuth\VeryBasicAuthServiceProvider` to publish the configuration. You could also type `$ php artisan vendor:publish --provider="Olssonm\VeryBasicAuth\VeryBasicAuthServiceProvider"` to directly publish the files.

The file `very_basic_auth.php` will then be copied to your `app/config`-folder – here you can set various options such as username and password.

#### Note

**There is no default password**. Upon installation you will need to set your own username and password. Please publish the packages configuration to have the ability to set these. **If left empty, basic auth will not be active**.

### Environments

You may set the environments that the package should be applied for. You may simply use "`*`" to use in all environments (this is also the default).

``` php
'envs' => [
    '*'
],
```

Or

``` php
'envs' => [
    'production',
    'development',
    'local'
],
```

### Response handlers

When the authentication fails the response handler sends out an error response (see "Views and messages" for more about these options). By default the handler will be `\Olssonm\VeryBasicAuth\Handlers\DefaultResponseHandler` (see `response_handler` in `very_basic_auth.php`). You may however write your own response-logic if you so choose. The only requirement is that it implements the `\Olssonm\VeryBasicAuth\Handlers\ResponseHandler`-interface, and has an `__invoke`-method that accepts a request-object, like so:

``` php
use Illuminate\Http\Request;
use Olssonm\VeryBasicAuth\Handlers\ResponseHandler;

class CustomResponseHandler implements ResponseHandler
{
    public function __invoke(Request $request)
    {
        // Do some stuff
        return response('Custom response', 401);
    }
}
```


### Views and messages

In the `very_basic_auth.php`-configuration you have the ability to set a custom view instead of a message.

``` php
// Message to display if the user "opts out"/clicks "cancel"
'error_message'     => 'You have to supply your credentials to access this resource.',

// If you prefer to use a view with your error message you can uncomment "error_view".
// This will supersede your default response message
// 'error_view'        => 'very_basic_auth::default'
```

If you uncomment `error_view`, the middleware will try to find your specified view. You supply this value as usual (without the `.blade.php`-extention).

## Usage

The middleware uses the `auth.very_basic`-filter to protect routes. You can either use `Route::group()` to protect multiple routes, or chose just to protect them individually.

**Group**
``` php
Route::group(['middleware' => 'auth.very_basic'], function() {
    Route::get('/', ['as' => 'start', 'uses' => 'StartController@index']);
    Route::get('/page', ['as' => 'page', 'uses' => 'StartController@page']);
});
```

**Single**
``` php
Route::get('/', [
    'as' => 'start',
    'uses' => 'StartController@index',
    'middleware' => 'auth.very_basic'
]);
```

You may also set the credentials inline;

``` php
Route::get('/', [
    'as' => 'start',
    'uses' => 'StartController@index',
    'middleware' => 'auth.very_basic:username,password'
]);
```

*Note:* inline credentials always take president over the `very_basic_auth.php`-configuration file.

### Generating hash for password

If you want to generate a hash for your password, you can use the `artisan`-command:

``` bash
php artisan very-basic-auth:generate-password
```

It will ask you for a password, and then automatically insert the hash into your `.env`-file


## Testing

``` bash
$ composer test
```

or

``` bash
$ phpunit
```

Laravel always runs in the "testing" environment while running tests. Make sure that `testing` is set in the `envs`-array in `very_basic_auth.php`.

## Thank you

A big thank you to the people who has contributed to this package, among others:

**[kazuhei](https://github.com/kazuhei)** – for providing the awesome Japanese translation  
**[freekmurze](https://github.com/freekmurze)** – for additional information on package/vendor installations  
**[faiare](https://github.com/faiare)** – for pointing out and implementing the `realm`-attribute ([RFC7235](https://tools.ietf.org/html/rfc7235#section-2.2))

## License

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

© 2024 [Marcus Olsson](https://marcusolsson.me).

[ico-version]: https://img.shields.io/packagist/v/olssonm/l5-very-basic-auth.svg?style=flat-square
[ico-license]: https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square
[ico-build]: https://img.shields.io/github/actions/workflow/status/olssonm/l5-very-basic-auth/test.yml?branch=master&style=flat-square
[ico-downloads]: https://img.shields.io/packagist/dt/olssonm/l5-very-basic-auth.svg?style=flat-square
[link-packagist]: https://packagist.org/packages/olssonm/l5-very-basic-auth
[link-build]: https://github.com/olssonm/l5-very-basic-auth/actions?query=workflow%3A%22Run+tests%22


================================================
FILE: composer.json
================================================
{
    "name": "olssonm/l5-very-basic-auth",
    "description": "Laravel stateless HTTP basic auth without the need for a database",
    "license": "MIT",
    "keywords": [
        "olssonm",
        "laravel",
        "authentication",
        "http basic auth"
    ],
    "authors": [
        {
            "name": "Marcus Olsson",
            "email": "contact@marcusolsson.me",
            "homepage": "https://marcusolsson.me"
        }
    ],
    "homepage": "https://github.com/olssonm/l5-very-basic-auth",
    "require": {
        "php": "^8.2",
        "illuminate/support": "^12.0 || ^13.0"
    },
    "require-dev": {
        "laravel/helpers": "^1.1",
        "orchestra/testbench": "^10.0 || ^11.0",
        "pestphp/pest": "^3.7 || ^4.4",
        "pestphp/pest-plugin-laravel": "^3.1 || ^4.1",
        "phpstan/phpstan": "^2.0",
        "phpunit/phpunit": "^11.5.3 || ^12.5.12",
        "squizlabs/php_codesniffer": "^3.5 || ^4.0"
    },
    "minimum-stability": "dev",
    "prefer-stable": true,
    "autoload": {
        "psr-4": {
            "Olssonm\\VeryBasicAuth\\": "src"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "Olssonm\\VeryBasicAuth\\Tests\\": "tests"
        }
    },
    "config": {
        "allow-plugins": {
            "pestphp/pest-plugin": true
        },
        "sort-packages": true
    },
    "extra": {
        "branch-alias": {
            "dev-master": "11.x-dev"
        },
        "laravel": {
            "providers": [
                "Olssonm\\VeryBasicAuth\\VeryBasicAuthServiceProvider"
            ]
        }
    },
    "scripts": {
        "phpfix": "vendor/bin/phpcbf --standard=\"PSR12\" ./src --ignore=./src/resources/*",
        "phpsniff": "vendor/bin/phpcs --standard=\"PSR12\" ./src --ignore=./src/resources/*",
        "phpstan": "./vendor/bin/phpstan",
        "test": "vendor/bin/pest"
    }
}


================================================
FILE: phpstan.neon
================================================
parameters:
    level: 8
    paths:
      - src
    ignoreErrors:
      - identifier: missingType.generics


================================================
FILE: phpunit.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.5/phpunit.xsd"
    bootstrap="vendor/autoload.php"
    backupGlobals="false"
    colors="true"
    processIsolation="false"
    stopOnFailure="false"
    cacheDirectory=".phpunit.cache"
    backupStaticProperties="false"
>
    <testsuites>
        <testsuite name="Package Test Suite">
            <directory>tests</directory>
        </testsuite>
    </testsuites>
    <source>
        <include>
            <directory>src</directory>
        </include>
        <exclude>
            <directory suffix=".blade.php">src</directory>
        </exclude>
    </source>
</phpunit>


================================================
FILE: src/Console/GeneratePassword.php
================================================
<?php

namespace Olssonm\VeryBasicAuth\Console;

use Illuminate\Console\Command;
use Symfony\Component\Console\Attribute\AsCommand;

#[AsCommand('very-basic-auth:generate-password')]
class GeneratePassword extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'very-basic-auth:generate-password';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Allows to securely set the `BASIC_AUTH_PASSWORD` in your Laravel `.env` file.';

    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle(): int
    {
        $password = $this->promptForValidPassword();

        if ($this->writeNewEnvironmentFileWith($this->hashPassword($password))) {
            $this->info('The password has been set successfully.');
        }

        return static::SUCCESS;
    }

    /**
     * Keep asking for a password until a valid one is provided.
     */
    protected function promptForValidPassword(): string
    {
        while (true) {
            $password = (string) $this->secret('Please enter a password for the very basic auth');

            if (!$this->isPasswordAccepted($password)) {
                $this->error('The password must be at least 8 characters.');
                continue;
            }

            if (!$this->passwordsMatch($password)) {
                $this->error('The passwords do not match. Please try again.');
                continue;
            }

            return $password;
        }
    }

    /**
     * Determine if the provided password fulfills minimum requirements.
     */
    protected function isPasswordAccepted(?string $password): bool
    {
        return !empty($password) && strlen($password) >= 8;
    }

    /**
     * Ask for confirmation and ensure it matches.
     */
    protected function passwordsMatch(string $password): bool
    {
        return $password === (string) $this->secret('Please confirm your password');
    }

    /**
     * Hash the password using Laravel's configured hasher.
     */
    protected function hashPassword(string $password): string
    {
        return app()->make('hash')->make($password);
    }

    /**
     * Write a new environment file with the given password.
     *
     * @param string $password
     * @return bool
     */
    protected function writeNewEnvironmentFileWith(string $password): bool
    {
        $envPath = $this->laravel->environmentFilePath();
        $input = file_get_contents($envPath);

        $replaced = preg_replace_callback(
            $this->passwordReplacementPattern(),
            fn($matches) => 'BASIC_AUTH_PASSWORD="' . $password . '"',
            $input
        );

        if ($replaced === $input || $replaced === null) {
            $this->error('Unable to set password. No BASIC_AUTH_PASSWORD variable was found in the .env file. Please add it first');
            return false;
        }

        file_put_contents($envPath, $replaced);

        return true;
    }

    /**
     * Get a regex pattern that will match env BASIC_AUTH_PASSWORD with any password.
     *
     * @return string
     */
    protected function passwordReplacementPattern(): string
    {
        return '/^BASIC_AUTH_PASSWORD=.*$/m';
    }
}


================================================
FILE: src/Handlers/DefaultResponseHandler.php
================================================
<?php

namespace Olssonm\VeryBasicAuth\Handlers;

use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;

class DefaultResponseHandler implements ResponseHandler
{
    public function __invoke(Request $request): Response|JsonResponse
    {
        // Build header
        $header = [
            'WWW-Authenticate' => sprintf(
                'Basic realm="%s", charset="UTF-8"',
                config('very_basic_auth.realm', 'Basic Auth')
            ),
        ];

        // View
        $view = config('very_basic_auth.error_view');

        // If the request want's JSON, else view
        if ($request->wantsJson()) {
            return response()->json([
                'message' => config('very_basic_auth.error_message'),
            ], 401, $header);
        } elseif (isset($view)) {
            return response()->view($view, [], 401)
                ->withHeaders($header);
        }

        // Return default message
        return response()->make(config('very_basic_auth.error_message'), 401, $header);
    }
}


================================================
FILE: src/Handlers/ResponseHandler.php
================================================
<?php

namespace Olssonm\VeryBasicAuth\Handlers;

use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;

interface ResponseHandler
{
    public function __invoke(Request $request): Response|JsonResponse;
}


================================================
FILE: src/Http/Middleware/VeryBasicAuth.php
================================================
<?php

namespace Olssonm\VeryBasicAuth\Http\Middleware;

use Closure;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Olssonm\VeryBasicAuth\Handlers\ResponseHandler;
use Symfony\Component\HttpFoundation\Response;

class VeryBasicAuth
{
    protected ResponseHandler $responseHandler;

    public function __construct(ResponseHandler $responseHandler)
    {
        $this->responseHandler = $responseHandler;
    }

    /**
     * Handle an incoming request
     *
     * @param mixed $username
     * @param mixed $password
     */
    public function handle(Request $request, Closure $next, $username = null, $password = null): Response
    {
        $active = (count(array_intersect([
                '*',
                app()->environment(),
            ], config('very_basic_auth.envs'))) > 0);

        // Check if middleware is in use in current environment
        if ($active) {
            $authUsername = $username ?? config('very_basic_auth.user');
            $authPassword = $password ?? config('very_basic_auth.password');

            if (! $authUsername && ! $authPassword) {
                return $next($request);
            }

            $plainPassword = $request->getPassword();

            $isCorrectPassword = $plainPassword === $authPassword;

            if (! $isCorrectPassword) {
                try {
                    $isCorrectPassword = Hash::check($plainPassword, $authPassword);
                } catch (\Throwable $e) {
                    // If the password is not hashed, we will just return false
                    $isCorrectPassword = false;
                }
            }

            if ($request->getUser() !== $authUsername || !$isCorrectPassword) {
                return $this->deniedResponse($request);
            }
        }

        return $next($request);
    }

    /**
     * Return a error response
     *
     * @return \Illuminate\Http\Response|\Illuminate\Http\JsonResponse
     */
    private function deniedResponse(Request $request): Response|JsonResponse
    {
        return ($this->responseHandler)($request);
    }
}


================================================
FILE: src/VeryBasicAuthServiceProvider.php
================================================
<?php

namespace Olssonm\VeryBasicAuth;

use Illuminate\Support\ServiceProvider;
use Olssonm\VeryBasicAuth\Console\GeneratePassword;
use Olssonm\VeryBasicAuth\Handlers\DefaultResponseHandler;
use Olssonm\VeryBasicAuth\Handlers\ResponseHandler;

class VeryBasicAuthServiceProvider extends ServiceProvider
{
    /**
     * Path to config-file
     *
     * @var string
     */
    protected $config;

    /**
     * Path to stub
     *
     * @var string
     */
    protected $stub;

    /**
     * Constructor
     *
     * @param \Illuminate\Contracts\Foundation\Application $app
     * @return void
     */
    public function __construct($app)
    {
        $this->config = __DIR__ . '/config.php';

        parent::__construct($app);
    }

    /**
     * Perform post-registration booting of services.
     *
     * @return void
     */
    public function boot(\Illuminate\Routing\Router $router)
    {
        // Publishing of configuration
        $this->publishes([
            $this->config => config_path('very_basic_auth.php'),
        ]);

        // Load default view/s
        $this->loadViewsFrom(__DIR__ . '/resources/views', 'very_basic_auth');

        // Register middleware
        $router->aliasMiddleware('auth.very_basic', \Olssonm\VeryBasicAuth\Http\Middleware\VeryBasicAuth::class);

        // Register commands
        if ($this->app->runningInConsole()) {
            $this->commands([
                GeneratePassword::class,
            ]);
        }
    }

    /**
     * Register any package services.
     *
     * @return void
     */
    public function register()
    {
        // If the user doesn't set their own config, load default
        $this->mergeConfigFrom(
            $this->config,
            'very_basic_auth'
        );

        $this->app->bind(
            ResponseHandler::class,
            config('very_basic_auth.response_handler', DefaultResponseHandler::class)
        );
    }
}


================================================
FILE: src/config.php
================================================
<?php

/**
 * Configuration for the "HTTP Very Basic Auth"-middleware
 */

return [
    // Username
    'user' => env('BASIC_AUTH_USERNAME', ''),

    // Password
    'password' => env('BASIC_AUTH_PASSWORD', ''),

    // Environments where the middleware is active. Use "*" to protect all envs
    'envs' => [
        '*',
    ],

    // Response handler for the error responses
    'response_handler' => \Olssonm\VeryBasicAuth\Handlers\DefaultResponseHandler::class,

    // Message to display if the user "opts out"/clicks "cancel"
    'error_message' => 'You have to supply your credentials to access this resource.',

    // Message to display in the auth dialog in some browsers (mainly Internet Explorer).
    // Realm is also used to define a "space" that should share credentials.
    'realm' => 'Basic Auth',

    // If you prefer to use a view with your error message you can uncomment "error_view".
    // This will supersede your default response message
    // 'error_view'        => 'very_basic_auth::default'
];


================================================
FILE: src/resources/views/default.blade.php
================================================
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Error</title>
        <style media="screen">
            html {
                font-family: 'helvetica neue', helvetica, arial, sans-serif;
                background-color: #ecf0f1;
            }

            .box {
                width: 50%;
                min-width: 400px;
                margin: 0 auto;
                padding: 30px;
                background-color: #fff;
            }

            code {
                font-size: 110%;
                color: #e74c3c;
                background-color: #ecf0f1;
                padding: 1px 4px;
            }
        </style>
    </head>
    <body style="margin-bottom: 38px;">
        <div class="box">
            <h3>This is the default view for the olssonm/l5-very-basic-auth-package.</h3>
            <p>
                To customize this, simply edit your <code>very_basic_auth</code>-configuration file and set
                <code>error_view</code> to your own custom blade-template (the default is <code>very_basic_auth::default</code>).
            </p>
        </div>
    </body>
</html>


================================================
FILE: tests/Fixtures/CustomResponseHandler.php
================================================
<?php

namespace Olssonm\VeryBasicAuth\Tests\Fixtures;

use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Olssonm\VeryBasicAuth\Handlers\ResponseHandler;

class CustomResponseHandler implements ResponseHandler
{
    public function __invoke(Request $request): Response|JsonResponse
    {
        return response('Custom response', 401);
    }
}


================================================
FILE: tests/Pest.php
================================================
<?php

use Illuminate\Support\Facades\Route;
use Olssonm\VeryBasicAuth\Http\Middleware\VeryBasicAuth;
use Olssonm\VeryBasicAuth\Tests\TestCase;

uses(TestCase::class)
    ->beforeEach(function () {
        // Set default config for testing
        config()->set('very_basic_auth.user', 'test');
        config()->set('very_basic_auth.password', 'test');
    
        Route::get('/', fn () => 'ok')->middleware(VeryBasicAuth::class)->name('default');
        Route::get('/test', fn () => 'ok')->middleware(VeryBasicAuth::class);
        Route::get('/inline', fn () => 'ok')->middleware(
            sprintf('auth.very_basic:%s,%s', config('very_basic_auth.user'), config('very_basic_auth.password'))
        )->name('inline');
    })
    ->in(__DIR__);


================================================
FILE: tests/TestCase.php
================================================
<?php

namespace Olssonm\VeryBasicAuth\Tests;

use Olssonm\VeryBasicAuth\VeryBasicAuthServiceProvider;
use Orchestra\Testbench\TestCase as OrchestraTestCase;

abstract class TestCase extends OrchestraTestCase
{
    protected function setUp(): void
    {
        parent::setUp();
    }

    protected function getPackageProviders($app)
    {
        return [
            VeryBasicAuthServiceProvider::class,
        ];
    }

    public static function tearDownAfterClass(): void
    {
        parent::tearDownAfterClass();
    }
}


================================================
FILE: tests/VeryBasicAuthTest.php
================================================
<?php

use Illuminate\Support\Str;
use Olssonm\VeryBasicAuth\Handlers\DefaultResponseHandler;
use Olssonm\VeryBasicAuth\Handlers\ResponseHandler;
use Olssonm\VeryBasicAuth\Http\Middleware\VeryBasicAuth;
use Olssonm\VeryBasicAuth\Tests\Fixtures\CustomResponseHandler;

use function Pest\Laravel\get;
use function Pest\Laravel\withHeaders;

test('basic auth filter is set', function () {
    expect(in_array(VeryBasicAuth::class, $this->app->router->getMiddleware()))->toBeTrue();
    expect(array_key_exists('auth.very_basic', $this->app->router->getMiddleware()));
});

test('config file is installed', function () {
    expect(file_exists(__DIR__.'/../src/config.php'))->toBeTrue();
});

test('install package', function () {
    $this->artisan('vendor:publish', [
        '--provider' => 'Olssonm\VeryBasicAuth\VeryBasicAuthServiceProvider',
    ])->assertExitCode(0);

    expect(file_exists(config_path('very_basic_auth.php')))->toBeTrue();
});

test('request with no credentials and no config passes', function () {
    config()->set('very_basic_auth.user', '');
    config()->set('very_basic_auth.password', '');

    $response = get('/');

    expect($response->getStatusCode())->toEqual(200);
    expect($response->headers->get('WWW-Authenticate'))->toEqual(null);
});

test('request with no credentials fails', function () {
    $response = get('/');

    expect($response->getStatusCode())->toEqual(401);
    expect($response->headers->get('WWW-Authenticate'))->toEqual(sprintf('Basic realm="%s", charset="UTF-8"', config('very_basic_auth.realm')));
    expect($response->getContent())->toEqual(config('very_basic_auth.error_message'));
});

test('request with incorrect credentials fails - text/html', function () {
    $response = withHeaders([
        'PHP_AUTH_USER' => str_random(20),
        'PHP_AUTH_PW' => str_random(20),
    ])->get('/');

    expect($response->getStatusCode())->toEqual(401);
    expect(requestHeader($response))->toEqual('text/html; charset=utf-8');
    expect($response->headers->get('WWW-Authenticate'))->toEqual(sprintf('Basic realm="%s", charset="UTF-8"', config('very_basic_auth.realm')));
    expect($response->getContent())->toEqual(config('very_basic_auth.error_message'));
});

test('request with incorrect credentials fails - hashed password', function () {

    config()->set('very_basic_auth.user', 'test');
    config()->set('very_basic_auth.password', app()->make('hash')->make('test'));

    $response = withHeaders([
        'PHP_AUTH_USER' => str_random(20),
        'PHP_AUTH_PW' => str_random(20),
    ])->get('/');

    expect($response->getStatusCode())->toEqual(401);
});

test('request with incorrect credentials fails - json', function () {
    $response = withHeaders([
        'PHP_AUTH_USER' => str_random(20),
        'PHP_AUTH_PW' => str_random(20),
        'Accept' => 'application/json',
    ])->get('/');

    $content = json_decode($response->getContent());

    expect($response->getStatusCode())->toEqual(401);
    expect($response->headers->get('content-type'))->toEqual('application/json');
    expect(json_last_error())->toEqual(JSON_ERROR_NONE);
    expect($content->message)->toEqual(config('very_basic_auth.error_message'));
    expect($response->headers->get('WWW-Authenticate'))->toEqual(sprintf('Basic realm="%s", charset="UTF-8"', config('very_basic_auth.realm')));
});

test('request with incorrect credentials fails - view', function () {
    config()->set('very_basic_auth.error_view', 'very_basic_auth::default');

    $response = withHeaders([
        'PHP_AUTH_USER' => str_random(20),
        'PHP_AUTH_PW' => str_random(20),
    ])->get('/');

    expect($response->getStatusCode())->toEqual(401);
    expect(requestHeader($response))->toEqual('text/html; charset=utf-8');
    expect($response->headers->get('WWW-Authenticate'))->toEqual(sprintf('Basic realm="%s", charset="UTF-8"', config('very_basic_auth.realm')));

    $this->assertStringContainsStringIgnoringCase('This is the default view for the olssonm/l5-very-basic-auth-package', $response->getContent());
});

test('request with correct credentials passes', function () {
    $response = withHeaders([
        'PHP_AUTH_USER' => config('very_basic_auth.user'),
        'PHP_AUTH_PW' => config('very_basic_auth.password'),
    ])->get('/');

    expect($response->getStatusCode())->toEqual(200);
    expect($response->getContent())->toEqual('ok');
});

test('request with correct credentials passes - hashed password', function () {
    config()->set('very_basic_auth.user', 'test');
    config()->set('very_basic_auth.password', app()->make('hash')->make('test'));

    $response = withHeaders([
        'PHP_AUTH_USER' => 'test',
        'PHP_AUTH_PW' => 'test',
    ])->get('/');

    expect($response->getStatusCode())->toEqual(200);
    expect($response->getContent())->toEqual('ok');
});

test('environments', function () {
    config()->set('very_basic_auth.envs', ['production']);
    get('/')->assertStatus(200);

    config()->set('very_basic_auth.envs', ['local']);
    get('/')->assertStatus(200);

    config()->set('very_basic_auth.envs', ['*']);
    get('/')->assertStatus(401);

    config()->set('very_basic_auth.envs', ['testing']);
    get('/')->assertStatus(401);
});

test('request with incorrect inline credentials fails', function () {
    $response = withHeaders([
        'PHP_AUTH_USER' => str_random(20),
        'PHP_AUTH_PW' => str_random(20),
    ])->get('/inline');

    expect($response->getStatusCode())->toEqual(401);
    expect($response->getContent())->toEqual(config('very_basic_auth.error_message'));
});

test('request with correct inline credentials passes', function () {
    $response = withHeaders([
        'PHP_AUTH_USER' => config('very_basic_auth.user'),
        'PHP_AUTH_PW' => config('very_basic_auth.password'),
    ])->get('/inline');

    expect($response->getStatusCode())->toEqual(200);
    expect($response->getContent())->toEqual('ok');
});

test('test response handlers', function () {
    // Custom response handler
    app()->bind(
        ResponseHandler::class,
        CustomResponseHandler::class
    );

    $response = get('/test');

    expect($response->getStatusCode())->toEqual(401);
    expect($response->getContent())->toEqual('Custom response');

    // Default response handler
    app()->bind(
        ResponseHandler::class,
        DefaultResponseHandler::class
    );

    $response = get('/test');

    expect($response->getStatusCode())->toEqual(401);
    expect($response->getContent())->toEqual(config('very_basic_auth.error_message'));
});

// Test for the console command PasswordGenerateCommand
test('console command sets password in .env file', function () {
    $envPath = base_path('.env');

    // Clean up any existing .env before the test
    if (file_exists($envPath)) {
        unlink($envPath);
    }

    // Create a fresh .env
    file_put_contents($envPath, "APP_NAME=Laravel\nBASIC_AUTH_PASSWORD=test");

    $password = 'password' . uniqid();

    // Simulate user input for the console command
    $this->artisan('very-basic-auth:generate-password')
        ->expectsQuestion('Please enter a password for the very basic auth', $password)
        ->expectsQuestion('Please confirm your password', $password)
        ->assertExitCode(0);

    // Reload env-variables to make sure the newest value is available
    $this->artisan('config:cache');
    $hashedPassword = config('very_basic_auth.password');

    expect($hashedPassword)->not->toBeNull();
    expect(app()->make('hash')->check($password, $hashedPassword))->toBeTrue();
    expect(config('app.name'))->toEqual('Laravel');
});

function requestHeader($response): string
{
    return Str::lower($response->headers->get('content-type'));
}
Download .txt
gitextract_4ggz17vw/

├── .editorconfig
├── .github/
│   ├── FUNDING.yml
│   └── workflows/
│       └── test.yml
├── .gitignore
├── LICENSE.md
├── README.jp.md
├── README.md
├── composer.json
├── phpstan.neon
├── phpunit.xml
├── src/
│   ├── Console/
│   │   └── GeneratePassword.php
│   ├── Handlers/
│   │   ├── DefaultResponseHandler.php
│   │   └── ResponseHandler.php
│   ├── Http/
│   │   └── Middleware/
│   │       └── VeryBasicAuth.php
│   ├── VeryBasicAuthServiceProvider.php
│   ├── config.php
│   └── resources/
│       └── views/
│           └── default.blade.php
└── tests/
    ├── Fixtures/
    │   └── CustomResponseHandler.php
    ├── Pest.php
    ├── TestCase.php
    └── VeryBasicAuthTest.php
Download .txt
SYMBOL INDEX (27 symbols across 8 files)

FILE: src/Console/GeneratePassword.php
  class GeneratePassword (line 8) | #[AsCommand('very-basic-auth:generate-password')]
    method handle (line 30) | public function handle(): int
    method promptForValidPassword (line 44) | protected function promptForValidPassword(): string
    method isPasswordAccepted (line 66) | protected function isPasswordAccepted(?string $password): bool
    method passwordsMatch (line 74) | protected function passwordsMatch(string $password): bool
    method hashPassword (line 82) | protected function hashPassword(string $password): string
    method writeNewEnvironmentFileWith (line 93) | protected function writeNewEnvironmentFileWith(string $password): bool
    method passwordReplacementPattern (line 119) | protected function passwordReplacementPattern(): string

FILE: src/Handlers/DefaultResponseHandler.php
  class DefaultResponseHandler (line 9) | class DefaultResponseHandler implements ResponseHandler
    method __invoke (line 11) | public function __invoke(Request $request): Response|JsonResponse

FILE: src/Handlers/ResponseHandler.php
  type ResponseHandler (line 9) | interface ResponseHandler
    method __invoke (line 11) | public function __invoke(Request $request): Response|JsonResponse;

FILE: src/Http/Middleware/VeryBasicAuth.php
  class VeryBasicAuth (line 12) | class VeryBasicAuth
    method __construct (line 16) | public function __construct(ResponseHandler $responseHandler)
    method handle (line 27) | public function handle(Request $request, Closure $next, $username = nu...
    method deniedResponse (line 69) | private function deniedResponse(Request $request): Response|JsonResponse

FILE: src/VeryBasicAuthServiceProvider.php
  class VeryBasicAuthServiceProvider (line 10) | class VeryBasicAuthServiceProvider extends ServiceProvider
    method __construct (line 32) | public function __construct($app)
    method boot (line 44) | public function boot(\Illuminate\Routing\Router $router)
    method register (line 70) | public function register()

FILE: tests/Fixtures/CustomResponseHandler.php
  class CustomResponseHandler (line 10) | class CustomResponseHandler implements ResponseHandler
    method __invoke (line 12) | public function __invoke(Request $request): Response|JsonResponse

FILE: tests/TestCase.php
  class TestCase (line 8) | abstract class TestCase extends OrchestraTestCase
    method setUp (line 10) | protected function setUp(): void
    method getPackageProviders (line 15) | protected function getPackageProviders($app)
    method tearDownAfterClass (line 22) | public static function tearDownAfterClass(): void

FILE: tests/VeryBasicAuthTest.php
  function requestHeader (line 213) | function requestHeader($response): string
Condensed preview — 21 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (42K chars).
[
  {
    "path": ".editorconfig",
    "chars": 344,
    "preview": "; This file is for unifying the coding style for different editors and IDEs.\n; More information at http://editorconfig.o"
  },
  {
    "path": ".github/FUNDING.yml",
    "chars": 65,
    "preview": "# These are supported funding model platforms\n\ngithub: [olssonm]\n"
  },
  {
    "path": ".github/workflows/test.yml",
    "chars": 950,
    "preview": "name: Run tests\n\non:\n  push:\n  pull_request:\n\njobs:\n  php-tests:\n    runs-on: ubuntu-latest\n\n    strategy:\n      matrix:"
  },
  {
    "path": ".gitignore",
    "chars": 84,
    "preview": "/vendor\ncomposer.lock\n.DS_Store\n.phpunit.result.cache\n.phpunit.cache\nphpunit-output\n"
  },
  {
    "path": "LICENSE.md",
    "chars": 1140,
    "preview": "# The MIT License (MIT)\n\nCopyright (c) 2024 Marcus Olsson <contact@marcusolsson.me>\n\n> Permission is hereby granted, fre"
  },
  {
    "path": "README.jp.md",
    "chars": 4226,
    "preview": "# Laravel Very Basic Auth\n\n[![Latest Version on Packagist][ico-version]][link-packagist]\n[![Total downloads][ico-downloa"
  },
  {
    "path": "README.md",
    "chars": 7087,
    "preview": "# Laravel Very Basic Auth\n\n[![Latest Version on Packagist][ico-version]][link-packagist]\n[![Total downloads][ico-downloa"
  },
  {
    "path": "composer.json",
    "chars": 1882,
    "preview": "{\n    \"name\": \"olssonm/l5-very-basic-auth\",\n    \"description\": \"Laravel stateless HTTP basic auth without the need for a"
  },
  {
    "path": "phpstan.neon",
    "chars": 107,
    "preview": "parameters:\n    level: 8\n    paths:\n      - src\n    ignoreErrors:\n      - identifier: missingType.generics\n"
  },
  {
    "path": "phpunit.xml",
    "chars": 746,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<phpunit\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:noName"
  },
  {
    "path": "src/Console/GeneratePassword.php",
    "chars": 3342,
    "preview": "<?php\n\nnamespace Olssonm\\VeryBasicAuth\\Console;\n\nuse Illuminate\\Console\\Command;\nuse Symfony\\Component\\Console\\Attribute"
  },
  {
    "path": "src/Handlers/DefaultResponseHandler.php",
    "chars": 1069,
    "preview": "<?php\n\nnamespace Olssonm\\VeryBasicAuth\\Handlers;\n\nuse Illuminate\\Http\\JsonResponse;\nuse Illuminate\\Http\\Request;\nuse Ill"
  },
  {
    "path": "src/Handlers/ResponseHandler.php",
    "chars": 245,
    "preview": "<?php\n\nnamespace Olssonm\\VeryBasicAuth\\Handlers;\n\nuse Illuminate\\Http\\JsonResponse;\nuse Illuminate\\Http\\Request;\nuse Ill"
  },
  {
    "path": "src/Http/Middleware/VeryBasicAuth.php",
    "chars": 2144,
    "preview": "<?php\n\nnamespace Olssonm\\VeryBasicAuth\\Http\\Middleware;\n\nuse Closure;\nuse Illuminate\\Http\\JsonResponse;\nuse Illuminate\\H"
  },
  {
    "path": "src/VeryBasicAuthServiceProvider.php",
    "chars": 1941,
    "preview": "<?php\n\nnamespace Olssonm\\VeryBasicAuth;\n\nuse Illuminate\\Support\\ServiceProvider;\nuse Olssonm\\VeryBasicAuth\\Console\\Gener"
  },
  {
    "path": "src/config.php",
    "chars": 1027,
    "preview": "<?php\n\n/**\n * Configuration for the \"HTTP Very Basic Auth\"-middleware\n */\n\nreturn [\n    // Username\n    'user' => env('B"
  },
  {
    "path": "src/resources/views/default.blade.php",
    "chars": 1189,
    "preview": "<!DOCTYPE html>\n<html>\n    <head>\n        <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n        <t"
  },
  {
    "path": "tests/Fixtures/CustomResponseHandler.php",
    "chars": 392,
    "preview": "<?php\n\nnamespace Olssonm\\VeryBasicAuth\\Tests\\Fixtures;\n\nuse Illuminate\\Http\\JsonResponse;\nuse Illuminate\\Http\\Request;\nu"
  },
  {
    "path": "tests/Pest.php",
    "chars": 752,
    "preview": "<?php\n\nuse Illuminate\\Support\\Facades\\Route;\nuse Olssonm\\VeryBasicAuth\\Http\\Middleware\\VeryBasicAuth;\nuse Olssonm\\VeryBa"
  },
  {
    "path": "tests/TestCase.php",
    "chars": 531,
    "preview": "<?php\n\nnamespace Olssonm\\VeryBasicAuth\\Tests;\n\nuse Olssonm\\VeryBasicAuth\\VeryBasicAuthServiceProvider;\nuse Orchestra\\Tes"
  },
  {
    "path": "tests/VeryBasicAuthTest.php",
    "chars": 7748,
    "preview": "<?php\n\nuse Illuminate\\Support\\Str;\nuse Olssonm\\VeryBasicAuth\\Handlers\\DefaultResponseHandler;\nuse Olssonm\\VeryBasicAuth\\"
  }
]

About this extraction

This page contains the full source code of the olssonm/l5-very-basic-auth GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 21 files (36.1 KB), approximately 10.1k tokens, and a symbol index with 27 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!