// 
// Decompiled by Procyon v0.6.0
// 

package com.nimbusds.jose.proc;

import com.nimbusds.jose.JWEDecrypter;
import com.nimbusds.jose.JWSVerifier;
import java.util.ListIterator;
import java.util.List;
import java.security.Key;
import com.nimbusds.jose.PlainObject;
import com.nimbusds.jose.JWEObject;
import com.nimbusds.jose.JWSObject;
import com.nimbusds.jose.JOSEException;
import java.text.ParseException;
import com.nimbusds.jose.JOSEObject;
import com.nimbusds.jose.Payload;
import com.nimbusds.jose.crypto.factories.DefaultJWEDecrypterFactory;
import com.nimbusds.jose.crypto.factories.DefaultJWSVerifierFactory;
import com.nimbusds.jose.shaded.jcip.ThreadSafe;

@ThreadSafe
public class DefaultJOSEProcessor<C extends SecurityContext> implements ConfigurableJOSEProcessor<C>
{
    private JOSEObjectTypeVerifier<C> jwsTypeVerifier;
    private JOSEObjectTypeVerifier<C> jweTypeVerifier;
    private JWSKeySelector<C> jwsKeySelector;
    private JWEKeySelector<C> jweKeySelector;
    private JWSVerifierFactory jwsVerifierFactory;
    private JWEDecrypterFactory jweDecrypterFactory;
    
    public DefaultJOSEProcessor() {
        this.jwsTypeVerifier = DefaultJOSEObjectTypeVerifier.JOSE;
        this.jweTypeVerifier = DefaultJOSEObjectTypeVerifier.JOSE;
        this.jwsVerifierFactory = new DefaultJWSVerifierFactory();
        this.jweDecrypterFactory = new DefaultJWEDecrypterFactory();
    }
    
    @Override
    public JOSEObjectTypeVerifier<C> getJWSTypeVerifier() {
        return this.jwsTypeVerifier;
    }
    
    @Override
    public void setJWSTypeVerifier(final JOSEObjectTypeVerifier<C> jwsTypeVerifier) {
        this.jwsTypeVerifier = jwsTypeVerifier;
    }
    
    @Override
    public JWSKeySelector<C> getJWSKeySelector() {
        return this.jwsKeySelector;
    }
    
    @Override
    public void setJWSKeySelector(final JWSKeySelector<C> jwsKeySelector) {
        this.jwsKeySelector = jwsKeySelector;
    }
    
    @Override
    public JOSEObjectTypeVerifier<C> getJWETypeVerifier() {
        return this.jweTypeVerifier;
    }
    
    @Override
    public void setJWETypeVerifier(final JOSEObjectTypeVerifier<C> jweTypeVerifier) {
        this.jweTypeVerifier = jweTypeVerifier;
    }
    
    @Override
    public JWEKeySelector<C> getJWEKeySelector() {
        return this.jweKeySelector;
    }
    
    @Override
    public void setJWEKeySelector(final JWEKeySelector<C> jweKeySelector) {
        this.jweKeySelector = jweKeySelector;
    }
    
    @Override
    public JWSVerifierFactory getJWSVerifierFactory() {
        return this.jwsVerifierFactory;
    }
    
    @Override
    public void setJWSVerifierFactory(final JWSVerifierFactory factory) {
        this.jwsVerifierFactory = factory;
    }
    
    @Override
    public JWEDecrypterFactory getJWEDecrypterFactory() {
        return this.jweDecrypterFactory;
    }
    
    @Override
    public void setJWEDecrypterFactory(final JWEDecrypterFactory factory) {
        this.jweDecrypterFactory = factory;
    }
    
    @Override
    public Payload process(final String compactJOSE, final C context) throws ParseException, BadJOSEException, JOSEException {
        return this.process(JOSEObject.parse(compactJOSE), context);
    }
    
    @Override
    public Payload process(final JOSEObject joseObject, final C context) throws BadJOSEException, JOSEException {
        if (joseObject instanceof JWSObject) {
            return this.process((JWSObject)joseObject, context);
        }
        if (joseObject instanceof JWEObject) {
            return this.process((JWEObject)joseObject, context);
        }
        if (joseObject instanceof PlainObject) {
            return this.process((PlainObject)joseObject, context);
        }
        throw new JOSEException("Unexpected JOSE object type: " + joseObject.getClass());
    }
    
    @Override
    public Payload process(final PlainObject plainObject, final C context) throws BadJOSEException {
        if (this.jwsTypeVerifier == null) {
            throw new BadJOSEException("Unsecured (plain) JOSE object rejected: No JWS header typ (type) verifier is configured");
        }
        this.jwsTypeVerifier.verify(plainObject.getHeader().getType(), context);
        throw new BadJOSEException("Unsecured (plain) JOSE objects are rejected, extend class to handle");
    }
    
    @Override
    public Payload process(final JWSObject jwsObject, final C context) throws BadJOSEException, JOSEException {
        if (this.jwsTypeVerifier == null) {
            throw new BadJOSEException("JWS object rejected: No JWS header typ (type) verifier is configured");
        }
        this.jwsTypeVerifier.verify(jwsObject.getHeader().getType(), context);
        if (this.getJWSKeySelector() == null) {
            throw new BadJOSEException("JWS object rejected: No JWS key selector is configured");
        }
        if (this.getJWSVerifierFactory() == null) {
            throw new JOSEException("No JWS verifier is configured");
        }
        final List<? extends Key> keyCandidates = this.getJWSKeySelector().selectJWSKeys(jwsObject.getHeader(), context);
        if (keyCandidates == null || keyCandidates.isEmpty()) {
            throw new BadJOSEException("JWS object rejected: Another algorithm expected, or no matching key(s) found");
        }
        final ListIterator<? extends Key> it = keyCandidates.listIterator();
        while (it.hasNext()) {
            final JWSVerifier verifier = this.getJWSVerifierFactory().createJWSVerifier(jwsObject.getHeader(), (Key)it.next());
            if (verifier == null) {
                continue;
            }
            final boolean validSignature = jwsObject.verify(verifier);
            if (validSignature) {
                return jwsObject.getPayload();
            }
            if (!it.hasNext()) {
                throw new BadJWSException("JWS object rejected: Invalid signature");
            }
        }
        throw new BadJOSEException("JWS object rejected: No matching verifier(s) found");
    }
    
    @Override
    public Payload process(final JWEObject jweObject, final C context) throws BadJOSEException, JOSEException {
        if (this.jweTypeVerifier == null) {
            throw new BadJOSEException("JWE object rejected: No JWE header typ (type) verifier is configured");
        }
        this.jweTypeVerifier.verify(jweObject.getHeader().getType(), context);
        if (this.getJWEKeySelector() == null) {
            throw new BadJOSEException("JWE object rejected: No JWE key selector is configured");
        }
        if (this.getJWEDecrypterFactory() == null) {
            throw new JOSEException("No JWE decrypter is configured");
        }
        final List<? extends Key> keyCandidates = this.getJWEKeySelector().selectJWEKeys(jweObject.getHeader(), context);
        if (keyCandidates == null || keyCandidates.isEmpty()) {
            throw new BadJOSEException("JWE object rejected: Another algorithm expected, or no matching key(s) found");
        }
        final ListIterator<? extends Key> it = keyCandidates.listIterator();
        while (it.hasNext()) {
            final JWEDecrypter decrypter = this.getJWEDecrypterFactory().createJWEDecrypter(jweObject.getHeader(), (Key)it.next());
            if (decrypter == null) {
                continue;
            }
            try {
                jweObject.decrypt(decrypter);
            }
            catch (final JOSEException e) {
                if (it.hasNext()) {
                    continue;
                }
                throw new BadJWEException("JWE object rejected: " + e.getMessage(), e);
            }
            if (!"JWT".equalsIgnoreCase(jweObject.getHeader().getContentType())) {
                return jweObject.getPayload();
            }
            final JWSObject nestedJWS = jweObject.getPayload().toJWSObject();
            if (nestedJWS == null) {
                return jweObject.getPayload();
            }
            return this.process(nestedJWS, context);
        }
        throw new BadJOSEException("JWE object rejected: No matching decrypter(s) found");
    }
}
