/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 
/* vim: set ts=2 et sw=2 tw=80: */
/*
  Copyright 2013-2021 The Libfossil Authors, see LICENSES/BSD-2-Clause.txt

  SPDX-License-Identifier: BSD-2-Clause-FreeBSD
  SPDX-FileCopyrightText: 2021 The Libfossil Authors
  SPDX-ArtifactOfProjectName: Libfossil
  SPDX-FileType: Code

  Heavily indebted to the Fossil SCM project (https://fossil-scm.org).
*/

/***************************************************************************
  This file contains routines related to working with user authentication.
*/
#include "fossil-scm/internal.h"
#include "fossil-scm/hash.h"
#include "fossil-scm/confdb.h"


FSL_EXPORT char * fsl_sha1_shared_secret( fsl_cx * const f,
                                          char const * zLoginName,
                                          char const * zPw ){
    if(!f || !zPw || !zLoginName) return 0;
    else{
        fsl_sha1_cx hash = fsl_sha1_cx_empty;
        unsigned char zResult[20];
        char zDigest[41];
        if(!f->cache.projectCode){
            f->cache.projectCode = fsl_config_get_text(f, FSL_CONFDB_REPO,
                                                       "project-code", 0);
            /*
              fossil(1) returns a copy of zPw here if !f->cache.projectCode,
              with the following comment:
            */
            /* On the first xfer request of a clone, the project-code is not yet
            ** known.  Use the cleartext password, since that is all we have.
            */
            if(!f->cache.projectCode) return 0;
        }
        fsl_sha1_update(&hash, f->cache.projectCode,
                        fsl_strlen(f->cache.projectCode));
        fsl_sha1_update(&hash, "/", 1);
        fsl_sha1_update(&hash, zLoginName, fsl_strlen(zLoginName));
        fsl_sha1_update(&hash, "/", 1);
        fsl_sha1_update(&hash, zPw, fsl_strlen(zPw));
        fsl_sha1_final(&hash, zResult);
        fsl_sha1_digest_to_base16(zResult, zDigest);
        return fsl_strndup( zDigest, FSL_STRLEN_SHA1 );
    }
}

FSL_EXPORT char * fsl_repo_login_group_name(fsl_cx * const f){
  return f
    ? fsl_config_get_text(f, FSL_CONFDB_REPO,
                          "login-group-name", 0)
    : 0;
}

FSL_EXPORT char * fsl_repo_login_cookie_name(fsl_cx * const f){
  fsl_db * db;
  if(!f || !(db = fsl_cx_db_repo(f))) return 0;
  else{
    char const * sql =
      "SELECT 'fossil-' || substr(value,1,16)"
      "  FROM config"
      " WHERE name IN ('project-code','login-group-code')"
      " ORDER BY name /*sort*/";
    return fsl_db_g_text(db, 0, sql);
  }
}

FSL_EXPORT int fsl_repo_login_search_uid(fsl_cx * const f, char const * zUsername,
                                         char const * zPasswd,
                                         fsl_id_t * userId){
  int rc;
  char * zSecret;
  fsl_db * db;
  if(!f || !userId
     || !zUsername || !*zUsername
     || !zPasswd /*??? || !*zPasswd*/){
    return FSL_RC_MISUSE;
  }
  else if(!(db = fsl_needs_repo(f))){
    return FSL_RC_NOT_A_REPO;
  }
  *userId = 0;
  zSecret = fsl_sha1_shared_secret(f, zUsername, zPasswd );
  if(!zSecret) return FSL_RC_OOM;
  rc = fsl_db_get_id(db, userId,
                     "SELECT uid FROM user"
                     " WHERE login=%Q"
                     "   AND length(cap)>0 AND length(pw)>0"
                     "   AND login NOT IN ('anonymous','nobody','developer','reader')"
                     "   AND (pw=%Q OR (length(pw)<>40 AND pw=%Q))",
                     zUsername, zSecret, zPasswd);
  fsl_free(zSecret);
  return rc;
}

FSL_EXPORT int fsl_repo_login_clear( fsl_cx * const f, fsl_id_t userId ){
  fsl_db * db;
  if(!f) return FSL_RC_MISUSE;
  else if(!(db = fsl_needs_repo(f))) return FSL_RC_NOT_A_REPO;
  else{
    int const rc = fsl_db_exec(db,
                       "UPDATE user SET cookie=NULL, ipaddr=NULL, "
                       " cexpire=0 WHERE "
                       " CASE WHEN %"FSL_ID_T_PFMT">=0 THEN uid=%"FSL_ID_T_PFMT""
                       " ELSE uid>0 END"
                       " AND login NOT IN('anonymous','nobody',"
                       " 'developer','reader')",
                       (fsl_id_t)userId, (fsl_id_t)userId);
    if(rc){
      fsl_cx_uplift_db_error(f, db);
    }
    return rc;
  }
}

#undef MARKER
