#!/usr/bin/perl

eval 'exec /usr/bin/perl  -S $0 ${1+"$@"}'
    if 0; # not running under some shell

# $Id: club_auth 144285 2007-03-15 15:21:04Z nanardon $

use strict;
use warnings;
use Getopt::Long;

GetOptions( 'g' => \my $check_group, 'no-chk-exp' => \my $noexpire, )
  or die "Wrong options\n";

# cache is keep 30 minutes (in second)
my $cache_life = 1800;

# Possible value are:
# standard, silver, vip, gold, platinum
# unset value assume we need standard
my %club_level = (
    ALUMINIUM => 1,
    MANDRIVA  => 2,
    VIP       => 3,
    STANDARD  => 4,
    SILVER    => 5,
    GOLD      => 6,
    PLATINUM  => 7,
);

my $count = 0;

# mapping from level_id to perm level
my %perm_levels = map { $club_level{$_} => $count++ } (
    qw(
      ALUMINIUM
      STANDARD
      SILVER
      VIP
      GOLD
      PLATINUM
      MANDRIVA
      )
);

sub perm_level {
    my ($level) = @_;

    # perm order to apply:
    return $perm_levels{$level} || 0;
}

my ( $login, $password );
if ( $ENV{USER} && defined( $ENV{PASS} ) ) {
    ( $login, $password ) = ( $ENV{USER}, $ENV{PASS} );
}
else {
    $login    = <STDIN>;
    $password = <STDIN>;
    chomp($login);
    chomp($password);
}

sub get_data_rest {
    use LWP::UserAgent ();
    use HTTP::Request  ();

    # Need to perform http_s_, so making mandatory here:
    use Crypt::SSLeay;
    use HTML::Entities;

    my $ua = LWP::UserAgent->new;
    my $http =
      HTTP::Request->new(
        POST => 'https://my.mandriva.com/rest/authenticate.php', );
    $http->content_type('application/x-www-form-urlencoded');
    $http->content(
        sprintf(
            'username=%s&password=%s&return=userData&use_cs4_fix=1',
            $login, $password,
        )
    );

    my $res = $ua->request($http);
    if ( $res->is_success() ) {
        use XML::Simple;
        my $ref = XMLin( $res->content() );
        if ( -d '/var/cache/clubauth' ) {
            my $filename = unpack( 'H*', $login );
            if ( open( my $h, '>', "/var/cache/clubauth/$filename" ) ) {
                printf $h "%s\n%d\n", crypt( $password, '$1$clubauth' ),
                  $ref->{code},;
                print $h $res->content();
                close($h);
            }
        }
        return $ref;
    }
    return;
}

sub get_data_cache {
    -d '/var/cache/clubauth' or return;
    my $filename = unpack( 'H*', $login );
    my @stat = stat("/var/cache/clubauth/$filename") or return;
    if (@stat) {
        if ( $stat[9] > scalar(time) - $cache_life ) {
            open( my $h, '<', "/var/cache/clubauth/$filename" ) or return;
            my $cached_password = <$h>;
            chomp($cached_password);
            my $passwd_mismatch;
            if ( crypt( $password, '$1$clubauth' ) ne $cached_password ) {
                $passwd_mismatch = 1;
            }
            my $ref;
            $ref->{code} = <$h>;
            chomp( $ref->{code} );
            my $rest_data = '';
            while (<$h>) {
                $rest_data .= $_;
            }
            close($h);
            if (   ( $passwd_mismatch && !$ref->{code} )
                || ( !$passwd_mismatch && $ref->{code} ) )
            {
                return { code => 1 };
            }
            elsif ( $passwd_mismatch && $ref->{code} ) {
                return;
            }
            else {
                use XML::Simple;
                return XMLin($rest_data) || {};
            }
        }
        else {
            unlink("/var/cache/clubauth/$filename");    # cleaning
        }
    }
    return;
}

my $ref = get_data_cache() || get_data_rest();

if ($ref) {

# if code, or level of member is less than the level need, exit with failure, aka 1
    if ( $ref->{code} ) {
        exit( $ref->{code} );
    }
    if ($check_group) {
        use Date::Parse;
        foreach my $g (@ARGV) {
            $ref->{data}{groups}{$g} or next;
            if ( !$noexpire ) {
                $ref->{data}{groups}{$g}{'dateExpires'} or next;
                my $time = str2time( $ref->{data}{groups}{$g}{'dateExpires'} )
                  or next;
                next if ( $time < time() );
            }
            exit(0);
        }
        exit(1);
    }
    else {

        # First arg is the level need
        my $need_level = $club_level{ uc( $ARGV[0] || '' ) } || $ARGV[0] || '5';
        exit(
            perm_level( $ref->{data}{club_level} ) < perm_level($need_level) );
    }
    require Data::Dumper;
    print Data::Dumper::Dumper($ref);
}
else {
    exit(1);
}
