#!/usr/bin/env python3
#
# Copyright (c) 2024 The NetBSD Foundation, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#

"""require_user_login is a hook to verify new changeset authorship
matches login name as determined by the LOGNAME environment variable.

Usage:
  [netbsd_hooks]
  domain = pkgsrc.org

  [hooks]
  pretxnchangegroup.require_user_login = python:....require_user_login.hook

"""

import os

from mercurial.i18n import _
from mercurial import (
    error,
    pycompat,
    registrar,
)
from mercurial.utils import stringutil


configtable = {}
configitem = registrar.configitem(configtable)

# [netbsd_hooks]
# domain = pkgsrc.org
configitem(
    b'netbsd_hooks',
    b'domain',
    default=None,
)


MAX_ERRORS = 3


def hook(ui, repo, hooktype, node=None, **kwargs):
    if hooktype != b'pretxnchangegroup':
        raise error.Abort(
            _(b'Unsupported hook type %r') % pycompat.bytestr(hooktype)
        )
    domain = ui.config(b'netbsd_hooks', b'domain')
    if not domain:
        raise error.Abort(_(b'netbsd_hooks.domain not configured'))
    logname = os.getenvb(b'LOGNAME')
    if not logname:
        raise error.Abort(_(b'LOGNAME unset or empty'))
    user = logname + b'@' + domain
    ctx = repo.unfiltered()[node]
    errors = []
    for revid in repo.changelog.revs(start=ctx.rev()):
        rev = repo[revid]
        if stringutil.email(rev.user()) != user:
            errors.append(rev.user())
            if len(errors) == MAX_ERRORS:
                errors.append(b'...')
                break
    if errors:
        raise error.Abort(
            _(b'user %s forbidden to impersonate others: %s') %
            (user, b', '.join(errors),))
