<commit_before>import Crypto
import Fluent
import Vapor

public protocol JWTUserRegistration: Decodable {
    var password: String { get }
}

public protocol JWTCustomPayloadKeychainUser: Content {
    associatedtype P: JWTKeychainPayload

    static var passwordKey: KeyPath<Self, HashedPassword> { get }
    static var userIdentifierKey: KeyPath<Self, String> { get }

    static var bCryptCost: Int { get }

    static func load(on: Request) throws -> Future<Self>
    static func logIn(on: Request) throws -> Future<Self>
    static func register(on: Request) throws -> Future<Self>

    associatedtype R: JWTUserRegistration

    init(_: R) throws
}

extension JWTCustomPayloadKeychainUser {
    public static var bCryptCost: Int {
        return 4
    }
}

public protocol JWTKeychainUser: JWTCustomPayloadKeychainUser where P == Payload {}

extension JWTCustomPayloadKeychainUser where Self: Model, Self.Database: QuerySupporting, Self: Content {
    public static func logIn(on request: Request) throws -> Future<Self> {
        guard
            let userIdentifierProperty = try reflectProperty(forKey: userIdentifierKey),
            let passwordProperty = try reflectProperty(forKey: passwordKey)
        else {
            // TODO: better error?
            throw JWTKeychainError.invalidIdentifier
        }

        let content = request.content

        return flatMap(
            to: Self.self,
            content[String.self, at: userIdentifierProperty.path],
            content[String.self, at: passwordProperty.path]
        ) { userIdentifier, password in
            return try query(on: request)
                .filter(userIdentifierKey, .equals, .data(userIdentifier))
                .first()
                .map(to: Self.self, userOrNotFound)
                .map(to: Self.self) { user in
                    guard
                        let password = password,
                        let created = Data(base64Encoded: user[keyPath: passwordKey].value),
                        try BCrypt.verify(password, created: created)
                    else {
                        throw JWTKeychainError.incorrectPassword
                    }

                    return user
            }
        }
    }

    public static func register(on request: Request) throws -> Future<Self> {
        let content = request.content

        return try content
            .decode(R.self)
            .flatMap(to: Self.self) { registration in
                if registration.password.count < 8 {
                    throw JWTKeychainError.weakPassword
                }
                return try Self(registration).save(on: request)
            }
    }
}

extension JWTCustomPayloadKeychainUser where
    Self: Model, Self.Database: QuerySupporting, Self.ID: StringInitializable
{
    public static func load(on request: Request) throws -> Future<Self> {
        let payload: P = try request.payload()

        guard let id = ID(string: payload.sub.value) else {
            throw JWTKeychainError.invalidIdentifier
        }

        return try find(id, on: request).map(to: Self.self, userOrNotFound)
    }
}

private func userOrNotFound<U>(_ user: U?) throws -> U {
    guard let user = user else {
        throw JWTKeychainError.userNotFound
    }

    return user
}<commit_msg>Use Userlogin value to log in<commit_after>import Crypto
import Fluent
import Vapor

public protocol JWTKeychainUserLogin: Decodable {
    var password: String { get }
}

public protocol JWTKeychainUserPublic: Encodable {}

public protocol JWTKeychainUserRegistration: Decodable {
    var password: String { get }
}

public protocol JWTKeychainUserUpdate: Decodable {}

public protocol JWTCustomPayloadKeychainUser: Content, Model where
    Self.Database: QuerySupporting, Self.ID: StringInitializable
{
    associatedtype Login: JWTKeychainUserLogin
    associatedtype Payload: JWTKeychainPayload
//    associatedtype Public: JWTKeychainUserPublic
    associatedtype Registration: JWTKeychainUserRegistration
//    associatedtype Update: JWTKeychainUserUpdate

    static var bCryptCost: Int { get }

    static func logIn(with: Login, on: Request) throws -> Future<Self?>
    init(_: Registration) throws

    var password: HashedPassword { get }

//    func asPublic() throws -> Public
//    func update(_ : Update) throws -> Self
}

extension JWTCustomPayloadKeychainUser {
    public static var bCryptCost: Int {
        return 4
    }
}

public protocol JWTKeychainUser: JWTCustomPayloadKeychainUser where Payload == JWTKeychain.Payload {}

extension JWTCustomPayloadKeychainUser {
    public static func load(on request: Request) throws -> Future<Self> {
        let payload: Payload = try request.payload()

        guard let id = ID(string: payload.sub.value) else {
            throw JWTKeychainError.invalidIdentifier
        }

        return try find(id, on: request).map(to: Self.self, userOrNotFound)
    }

    public static func logIn(on request: Request) throws -> Future<Self> {
        return try request
            .content
            .decode(Login.self)
            .flatMap(to: Self.self) { login in
                return try logIn(with: login, on: request)
                    .map(to: Self.self, userOrNotFound)
                    .map(to: Self.self) { user in
                        guard
                            let created = Data(base64Encoded: user.password.value),
                            try BCrypt.verify(login.password, created: created)
                        else {
                            throw JWTKeychainError.incorrectPassword
                        }

                        return user
                }
        }
    }

    public static func register(on request: Request) throws -> Future<Self> {
        let content = request.content

        return try content
            .decode(Registration.self)
            .flatMap(to: Self.self) { registration in
                if registration.password.count < 8 {
                    throw JWTKeychainError.weakPassword
                }
                return try Self(registration).save(on: request)
            }
    }
}

private func userOrNotFound<U>(_ user: U?) throws -> U {
    guard let user = user else {
        throw JWTKeychainError.userNotFound
    }

    return user
}
{'fraction_non_alphanumeric': 0.07565162110616656, 'fraction_numerical': 0.0012714558169103624, 'mean_word_length': 2.17988883274381, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 31, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3420603', 'n_tokens_mistral': 1659, 'n_tokens_neox': 1598, 'n_words': 465}