Skip to content

Instantly share code, notes, and snippets.

@SoftCreatR
Created November 19, 2024 08:33
Show Gist options
  • Select an option

  • Save SoftCreatR/0bb999089ca49368aed39e97d1cd8bb0 to your computer and use it in GitHub Desktop.

Select an option

Save SoftCreatR/0bb999089ca49368aed39e97d1cd8bb0 to your computer and use it in GitHub Desktop.

Revisions

  1. SoftCreatR created this gist Nov 19, 2024.
    145 changes: 145 additions & 0 deletions facebook-deauth.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,145 @@
    <?php

    /*
    * Copyright by SoftCreatR.dev.
    *
    * License: https://softcreatr.dev/license-terms
    *
    * 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.
    *
    * The above copyright notice and this disclaimer notice shall be included in all
    * copies or substantial portions of the Software.
    */

    use wcf\data\user\User;
    use wcf\data\user\UserAction;
    use wcf\system\email\Email;
    use wcf\system\email\mime\MimePartFacade;
    use wcf\system\email\mime\RecipientAwareTextMimePart;
    use wcf\system\email\UserMailbox;
    use wcf\system\exception\SystemException;
    use wcf\util\JSON;

    use function wcf\functions\exception\logThrowable;

    // Include WSC
    require __DIR__ . '/global.php';

    /**
    * Decode a Base64 URL-encoded string.
    *
    * @throws SystemException If decoding fails.
    */
    function base64UrlDecode(string $input): string
    {
    $remainder = \strlen($input) % 4;

    if ($remainder) {
    $input .= \str_repeat('=', 4 - $remainder);
    }

    $decoded = \base64_decode(\strtr($input, '-_', '+/'), true);

    if ($decoded === false) {
    throw new SystemException('Base64 decoding failed.');
    }

    return $decoded;
    }

    /**
    * Parse and verify a signed request.
    *
    * @throws SystemException If the signed request is invalid.
    */
    function parseSignedRequest(string $signedRequest, string $secret): array
    {
    $parts = \explode('.', $signedRequest, 2);

    if (\count($parts) !== 2) {
    throw new SystemException('Signed request format is invalid.');
    }

    [$encodedSignature, $payload] = $parts;

    $signature = base64UrlDecode($encodedSignature);
    $decodedPayload = base64UrlDecode($payload);
    $data = JSON::decode($decodedPayload);

    if (!\is_array($data)) {
    throw new SystemException('Payload decoding failed.');
    }

    if (\strtoupper($data['algorithm'] ?? '') !== 'HMAC-SHA256') {
    throw new SystemException('Unknown algorithm. Expected HMAC-SHA256.');
    }

    $expectedSignature = \hash_hmac('sha256', $payload, $secret, true);

    if (!\hash_equals($expectedSignature, $signature)) {
    throw new SystemException('Bad Signed JSON signature!');
    }

    return $data;
    }

    // Retrieve the signed request from the request parameters
    $signedRequest = $_REQUEST['signed_request'] ?? null;

    if (!$signedRequest) {
    exit;
    }

    try {
    // Parse and verify the signed request
    $result = parseSignedRequest($signedRequest, FACEBOOK_PRIVATE_KEY);
    } catch (SystemException $e) {
    logThrowable($e);

    exit;
    }

    // Extract the user ID from the parsed data
    $userID = $result['user_id'] ?? null;

    if ($userID && \is_string($userID)) {
    $authData = 'facebook:' . $userID;
    $user = User::getUserByAuthData($authData);

    if ($user->userID > 0) {
    try {
    // Generate a secure lost password key
    $lostPasswordKey = \bin2hex(\random_bytes(20));

    // Prepare the data to update the user
    $updateData = [
    'authData' => '',
    'lostPasswordKey' => $lostPasswordKey,
    'lastLostPasswordRequestTime' => TIME_NOW,
    ];

    // Execute the update action
    (new UserAction([$user], 'update', ['data' => $updateData]))->executeAction();

    // Prepare and send the lost password email
    $email = new Email();
    $email->addRecipient(new UserMailbox($user));
    $email->setSubject($user->getLanguage()->getDynamicVariable('wcf.user.lostPassword.mail.subject'));
    $email->setBody(new MimePartFacade([
    new RecipientAwareTextMimePart('text/html', 'email_lostPassword'),
    new RecipientAwareTextMimePart('text/plain', 'email_lostPassword'),
    ]));
    $email->send();
    } catch (Throwable $e) {
    logThrowable($e);

    exit;
    }
    }
    }