Crypt-MagicSignatures-Envelope

 view release on metacpan or  search on metacpan

lib/Crypt/MagicSignatures/Envelope.pm  view on Meta::CPAN

    # Append all defined signatures
    foreach ( @{$param{sigs}} ) {

      # No value is given
      next unless $_->{value};

      # Create new array reference if not already existing
      $self->{sigs} //= [];

      # Start new signature value
      my %sig = ( value => $_->{value} );
      $sig{key_id} = $_->{key_id} if exists $_->{key_id};

      # Add signature to signature array
      push(@{$self->{sigs}}, \%sig);
    };
  }

  # Envelope is defined as a string
  else {
    my $string = shift;

    # Construct object
    $self = bless { sigs => [] }, $class;

    # Create empty object
    return $self unless $string;

    $string = trim $string;

    # Message is me-xml
    if (index($string, '<') == 0) {

      # Parse xml string
      my $dom = Mojo::DOM->new(xml => 1)->parse($string);

      # Extract envelope from env or provenance
      my $env = $dom->at('env');
      $env = $dom->at('provenance') unless $env;

      # Envelope doesn't exist or is in wrong namespace
      if (!$env || $env->namespace ne $ME_NS) {
        carp 'Invalid envelope data';
        return;
      };

      # Retrieve and edit data
      my $data = $env->at('data');

      # The envelope is empty
      unless (defined $data) {
        carp 'No data payload defined';
        return;
      };

      my $temp;

      # Add data type if given
      $self->data_type( $temp ) if $temp = $data->attr->{type};

      # Add decoded data
      $self->data( b64url_decode( $data->text ) );

      # The envelope is empty
      unless ($self->data) {
        carp 'No data payload defined';
        return;
      };

      # Check algorithm
      if (($temp = $env->at('alg')) &&
            (uc $temp->text ne 'RSA-SHA256')) {
        carp 'Algorithm is not supported';
        return;
      };

      # Check encoding
      if (($temp = $env->at('encoding')) &&
            (lc $temp->text ne 'base64url')) {
        carp 'Encoding is not supported' and return;
      };

      # Find signatures
      $env->find('sig')->each(
        sub {
          my $sig_text = $_->text or return;

          my %sig = ( value => _trim_all $sig_text );

          if ($temp = $_->attr->{key_id}) {
            $sig{key_id} = $temp;
          };

          # Add sig to array
          push( @{ $self->{sigs} }, \%sig );
        });
    }

    # Message is me-json
    elsif (index($string, '{') == 0) {
      my $env;

      # Parse json object
      $env = decode_json $string;

      unless (defined $env) {
        return;
      };

      # Clone datastructure
      foreach (qw/data data_type encoding alg sigs/) {
        $self->{$_} = delete $env->{$_} if exists $env->{$_};
      };

      $self->data( b64url_decode( $self->data ));

      # Envelope is empty
      return unless $self->data;

      # Unknown parameters
      carp 'Unknown parameters: ' . join(',', %$env)

lib/Crypt/MagicSignatures/Envelope.pm  view on Meta::CPAN

=pod

=head1 NAME

Crypt::MagicSignatures::Envelope - MagicEnvelopes for the Salmon Protocol


=head1 SYNOPSIS

  use Crypt::MagicSignatures::Key;
  use Crypt::MagicSignatures::Envelope;

  # Generate a new MagicKey for signing messages
  my $mkey = Crypt::MagicSignatures::Key->generate(size => 1024);

  # Fold a new envelope
  my $me = Crypt::MagicSignatures::Envelope->new(
    data => 'Some arbitrary string.'
  );

  # Sign magic envelope
  $me->sign($mkey);

  # Extract the public key
  my $mkey_public = $mkey->to_string;

  # Verify the signature of the envelope
  if ($me->verify($mkey_public)) {
    print 'Signature is verified!';
  };


=head1 DESCRIPTION

L<Crypt::MagicSignatures::Envelope> implements MagicEnvelopes
with MagicSignatures as described in the
L<MagicSignatures Specification|http://salmon-protocol.googlecode.com/svn/trunk/draft-panzer-magicsig-01.html>
to sign messages of the
L<Salmon Protocol|http://www.salmon-protocol.org/>.
MagicSignatures is a
"robust mechanism for digitally signing nearly arbitrary messages".

B<This module is an early release! There may be significant changes in the future.>


=head1 ATTRIBUTES

=head2 alg

  my $alg = $me->alg;

The algorithm used for signing the MagicEnvelope.
Defaults to C<RSA-SHA256>, which is the only supported algorithm.


=head2 data

  my $data = $me->data;
  $me->data('Hello world!');

The decoded data folded in the MagicEnvelope.


=head2 data_type

  my $data_type = $me->data_type;
  $me->data_type('text/plain');

The Mime type of the data folded in the MagicEnvelope.
Defaults to C<text/plain>.


=head2 dom

  # Fold an xml message
  my $me = Crypt::MagicSignatures::Envelope->new( data => <<'XML' );
  <?xml version='1.0' encoding='UTF-8'?>
  <entry xmlns='http://www.w3.org/2005/Atom'>
    <author><uri>alice@example.com</uri></author>
  </entry>
  XML

  # Define an xml mime type
  $me->data_type('application/atom+xml');

  print $me->dom->at('author > uri')->text;
  # alice@example.com

The L<Mojo::DOM> object of the decoded data,
in the case the MagicEnvelope contains XML.

B<This attribute is experimental and may change without warnings!>


=head2 encoding

  my $encoding = $me->encoding;

The encoding of the MagicEnvelope.
Defaults to C<base64url>, which is the only encoding supported.


=head2 signature

  my $sig = $me->signature;
  my $sig = $me->signature('key-01');

A signature of the MagicEnvelope.
For retrieving a specific signature, pass a key id,
otherwise a default signature will be returned.

If a matching signature is found, the signature
is returned as a hash reference,
containing base64url encoded data for C<value>
and possibly a C<key_id>.
If no matching signature is found, a C<false> value is returned.


=head2 signature_base

  my $base = $me->signature_base;

The L<signature base string|http://salmon-protocol.googlecode.com/svn/trunk/draft-panzer-magicsig-01.html#sbs>
of the MagicEnvelope.


=head2 signed

  # With key id
  if ($me->signed('key-01')) {
    print 'MagicEnvelope is signed with key-01.';
  }

  # Without key id
  elsif ($me->signed) {
    print 'MagicEnvelope is signed.';
  }

  else {
    print 'MagicEnvelope is not signed.';
  };

Returns a C<true> value in case the MagicEnvelope is signed at least once.
Accepts optionally a C<key_id> and returns a C<true> value, if the
MagicEnvelope was signed with this specific key.


=head1 METHODS



( run in 1.357 second using v1.01-cache-2.11-cpan-5b529ec07f3 )