gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[reclaim-ui] 186/459: update to new API and structure


From: gnunet
Subject: [reclaim-ui] 186/459: update to new API and structure
Date: Fri, 11 Jun 2021 23:24:38 +0200

This is an automated email from the git hooks/post-receive script.

martin-schanzenbach pushed a commit to branch master
in repository reclaim-ui.

commit 2c45b2119483571b93cb5a1c5466ba35dbfaab41
Author: Schanzenbach, Martin <mschanzenbach@posteo.de>
AuthorDate: Fri Feb 7 17:48:06 2020 +0100

    update to new API and structure
---
 src/app/attestation.ts                             |   5 +-
 src/app/attribute.ts                               |   1 +
 .../authorization-request.component.ts             |   2 +-
 .../edit-attestations.component.html               |   3 -
 .../edit-attestations.component.ts                 |  35 +--
 src/app/edit-identity/edit-identity.component.html |  42 +--
 src/app/edit-identity/edit-identity.component.ts   | 309 ++++++++-------------
 src/app/identity-list/identity-list.component.html |  16 +-
 src/app/identity-list/identity-list.component.ts   | 110 ++++----
 src/app/open-id.service.ts                         |  10 +-
 src/app/reclaim.service.ts                         |  21 +-
 11 files changed, 217 insertions(+), 337 deletions(-)

diff --git a/src/app/attestation.ts b/src/app/attestation.ts
index a71d114..efd5012 100644
--- a/src/app/attestation.ts
+++ b/src/app/attestation.ts
@@ -1,6 +1,9 @@
+import { Attribute } from './attribute';
+
 export class Attestation {
   constructor(public name: string,
               public id: string,
               public value: string,
-              public type: string) {}
+              public type: string,
+              public attributes: Attribute[]) {}
 }
diff --git a/src/app/attribute.ts b/src/app/attribute.ts
index f720887..2dbce4f 100644
--- a/src/app/attribute.ts
+++ b/src/app/attribute.ts
@@ -1,6 +1,7 @@
 export class Attribute {
   constructor(public name: string,
               public id: string,
+              public attestation: string,
               public value: string,
               public type: string,
               public flag: string) {}
diff --git a/src/app/authorization-request/authorization-request.component.ts 
b/src/app/authorization-request/authorization-request.component.ts
index 9e62709..fa7b77b 100644
--- a/src/app/authorization-request/authorization-request.component.ts
+++ b/src/app/authorization-request/authorization-request.component.ts
@@ -21,7 +21,7 @@ export class AuthorizationRequestComponent implements OnInit {
   }
 
   getRefScope() {
-    return this.oidcService.getRefScope();
+    return this.oidcService.getAttestedScope();
   }
 
   isClientVerified() {
diff --git a/src/app/edit-attestations/edit-attestations.component.html 
b/src/app/edit-attestations/edit-attestations.component.html
index 6a218a5..bcfff6b 100644
--- a/src/app/edit-attestations/edit-attestations.component.html
+++ b/src/app/edit-attestations/edit-attestations.component.html
@@ -70,9 +70,6 @@
         <li>Types and values may not be empty!</li>
       </ul>
     </div>
-    <button class="btn btn-primary mb-4" (click)="getFhGAttestation()">
-      <span class="fa fa-user"></span> Get Fraunhofer Credentials
-    </button>
     <hr/>
     <!-- Edit card buttons -->
     <div>
diff --git a/src/app/edit-attestations/edit-attestations.component.ts 
b/src/app/edit-attestations/edit-attestations.component.ts
index 713128a..6281998 100644
--- a/src/app/edit-attestations/edit-attestations.component.ts
+++ b/src/app/edit-attestations/edit-attestations.component.ts
@@ -17,7 +17,6 @@ export class EditAttestationsComponent implements OnInit {
   identity: Identity;
   attestations: Attestation[];
   newAttestation: Attestation;
-  attestationValues: {}; //FIXME fix bad API design
 
   constructor(private reclaimService: ReclaimService,
               private identityService: IdentityService,
@@ -25,9 +24,8 @@ export class EditAttestationsComponent implements OnInit {
               private router: Router) { }
 
   ngOnInit() {
-    this.newAttestation = new Attestation('', '', '', '');
+    this.newAttestation = new Attestation('', '', '', '', []);
     this.identity = new Identity('','');
-    this.attestationValues = {};
     this.attestations = [];
     this.activatedRoute.params.subscribe(p => {
       if (p['id'] === undefined) {
@@ -60,18 +58,8 @@ export class EditAttestationsComponent implements OnInit {
   }
 
   private updateAttestation() {
-    this.reclaimService.getAttestation(this.identity).subscribe(attestation => 
{
+    this.reclaimService.getAttestations(this.identity).subscribe(attestation 
=> {
       this.attestations = attestation;
-      for (let i = 0; i < this.attestations.length; i++) {
-        this.reclaimService.parseAttest(this.attestations[i]).subscribe(values 
=>{
-          this.attestationValues[this.attestations[i].id] = values;
-        },
-        err => {
-          //this.errorInfos.push("Error parsing attestation ``" + 
attestation.name + "''");
-          console.log(err);
-        });
-
-      }
     },
     err => {
       //this.errorInfos.push("Error retrieving attestation for ``" + 
identity.name + "''");
@@ -202,23 +190,8 @@ export class EditAttestationsComponent implements OnInit {
   }
 
 
-
+  //FIXME
   isAttestationValid(attestation: Attestation) {
-    //FIXME JWT specific
-    //FIXME the expiration of the JWT should be a property of the attestation
-    //Not part of the values
-    const now = Date.now().valueOf() / 1000;
-    if (this.attestationValues[attestation.id] === undefined) {
-      return false;
-    }
-    if (this.attestationValues[attestation.id]['exp'] === 'undefined') {
-      return false;
-    }
-    return this.attestationValues[attestation.id]['exp'] > now;
-  }
-
-  getFhGAttestation() {
-    localStorage.setItem('userForAttestation', this.identity.name);
-    window.location.href = 
"http://localhost:4567/authorize?redirect_uri=http%3A%2F%2Flocalhost:4200%2Findex.html&client_id=reclaimid&response_type=code&scopes=openid";;
+    return true;
   }
 }
diff --git a/src/app/edit-identity/edit-identity.component.html 
b/src/app/edit-identity/edit-identity.component.html
index a6c1db5..9d004d1 100644
--- a/src/app/edit-identity/edit-identity.component.html
+++ b/src/app/edit-identity/edit-identity.component.html
@@ -10,7 +10,7 @@
     <div>
       <h6 class="card-subtitle mb-2">Attributes:</h6>
       <!-- Missing attributes -->
-      <table class="table pb-1" *ngIf="isAttributeMissing() || 
isReferenceMissing()">
+      <table class="table pb-1" *ngIf="isAttributeMissing() || 
isAttestedMissing()">
         <thead>
           <tr>
               <th>Attribute Name</th>
@@ -26,20 +26,20 @@
             <td>
             </td>
           </tr>
-          <tr [class.openid]="inOpenIdFlow()" 
[class.alert-danger]="newReference.name === missing.name" class="text-primary" 
*ngFor="let missing of missingReferences">
+          <tr [class.openid]="inOpenIdFlow()" 
[class.alert-danger]="newAttested.name === missing.name" class="text-primary" 
*ngFor="let missing of missingAttested">
             <td><div style="min-width: 15em">{{missing.name}}</div></td>
             <td>
-              <select (change)="missing.ref_id=$event.target.value; ">
+              <select (change)="missing.attestation=$event.target.value; ">
                 <option value="">Attestation</option>
                 <option *ngFor="let attest of attestations" 
value={{attest.id}}>
                   {{attest.name}}
                 </option>
               </select>
 
-              <select *ngIf="missing.ref_id !== ''" 
(change)="missing.ref_value=$event.target.value">
+              <select *ngIf="missing.attestation !== ''" 
(change)="missing.value=$event.target.value">
                 <option value="">Source</option>
-                <option *ngFor="let claim of 
attestationValuesForReference(missing.ref_id)" value={{claim}}>
-                  {{claim}}
+                <option *ngFor="let claim of 
attestationValuesForAttested(missing)" value={{claim.name}}>
+                  {{claim.name}}
                 </option>
               </select>
             </td>
@@ -62,13 +62,13 @@
             <td><div style="min-width: 15em">{{ attribute.name }}</div></td>
             <td>
               <input *ngIf="!isAttestation(attribute)" placeholder="Value" 
[(ngModel)]="attribute.value">
-              <span *ngIf="isAttestation(attribute)" >{{ attribute.value }} 
issued by {{ getIssuer(attribute) }} as ``{{ getReferencedName(attribute) 
}}''</span>
+              <span *ngIf="isAttestation(attribute)" >{{ attribute.value }} 
issued by {{ getIssuer(attribute) }} as ``{{ attribute.value }}''</span>
             </td>
             <td>
               <button class="btn btn-primary" 
(click)="deleteAttribute(attribute)" *ngIf="!isAttestation(attribute)">
                 <span class="fa fa-trash"></span>
               </button>
-              <button class="btn btn-primary"  
(click)="deleteReferenceByAttribute(attribute)" 
*ngIf="isAttestation(attribute)">
+              <button class="btn btn-primary"  
(click)="deleteAttribute(attribute)" *ngIf="isAttestation(attribute)">
                 <span class="fa fa-trash"></span>
               </button>
             </td>
@@ -82,32 +82,32 @@
             </td>
             <td>
               <button [disabled]="!canAddAttribute(newAttribute)" class="btn 
btn-primary"  (click)="addAttribute()">
-                <span class="fa fa-plus"></span> 
+                <span class="fa fa-plus"></span>
               </button>
             </td>
           </tr>
-          <tr [class.alert-danger]="isRefInConflict(newReference)" *ngIf="0 != 
attestations.length">
+          <tr [class.alert-danger]="isAttestedInConflict(newAttested)" 
*ngIf="0 != attestations.length">
             <td>
-              <input [class.text-danger]="!referenceNameValid(newReference)" 
placeholder="Reference" [(ngModel)]="newReference.name">
+              <input [class.text-danger]="!attestedNameValid(newAttested)" 
placeholder="Attested attribute" [(ngModel)]="newAttested.name">
             </td>
             <td>
-              <select (change)="newReference.ref_id=$event.target.value; ">
+              <select (change)="newAttested.attestation=$event.target.value; ">
                 <option value="">Attestation</option>
                 <option *ngFor="let attest of attestations" 
value={{attest.id}}>
                 {{attest.name}}
                 </option>
               </select>
 
-              <select *ngIf="newReference.ref_id !== ''" 
(change)="newReference.ref_value=$event.target.value">
+              <select *ngIf="newAttested.attestation !== ''" 
(change)="newAttested.value=$event.target.value">
                 <option value="">Source</option>
-                <option *ngFor="let claim of 
attestationValuesForReference(newReference)" value={{claim}}>
-                  {{claim}}
+                <option *ngFor="let claim of 
attestationValuesForAttested(newAttested)" value={{claim.name}}>
+                  {{claim.name}}
                 </option>
               </select>
             </td>
 
             <td>
-              <button [disabled]="!canAddReference(newReference)" class="btn 
btn-primary"  (click)="addReference()">
+              <button [disabled]="!canAddAttested(newAttested)" class="btn 
btn-primary"  (click)="addAttested()">
                 <span class="fa fa-plus"></span> 
               </button>
             </td>
@@ -126,17 +126,17 @@
       </ul>
     </div>
     <!-- optional attributes information -->
-    <div *ngIf="optionalReferences.length !== 0" class="text-primary">
+    <div *ngIf="optionalAttested.length !== 0" class="text-primary">
       <span class="fa fa-openid"></span> You may optionally provide 
attestations for:
       <ul>
-        <li *ngFor="let reference of 
optionalReferences"><strong>{{reference.name}}</strong>
+        <li *ngFor="let attribute of 
optionalAttested"><strong>{{attribute.name}}</strong>
       </ul>
     </div>
-    <!-- Reference creation warning -->
-    <div *ngIf="!referenceNameValid(newReference) || 
!referenceValueValid(newReference) || !referenceIDValid(newReference)" 
class="alert alert-primary alert-dismissible fade show" role="alert">
+    <!-- Attested creation warning -->
+    <div *ngIf="!attestedNameValid(newAttested) || 
!attestedValueValid(newAttested)" class="alert alert-primary alert-dismissible 
fade show" role="alert">
       <span class="fa fa-warning"></span> Note:
       <ul>
-        <li>Only use alphanumeric reference names.</li>
+        <li>Only use alphanumeric attribute names.</li>
         <li>You cannot define the same name twice.</li>
         <li>IDs and values may not be empty!</li>
       </ul>
diff --git a/src/app/edit-identity/edit-identity.component.ts 
b/src/app/edit-identity/edit-identity.component.ts
index 76fbdc9..9366c10 100644
--- a/src/app/edit-identity/edit-identity.component.ts
+++ b/src/app/edit-identity/edit-identity.component.ts
@@ -7,7 +7,6 @@ import { NamestoreService } from '../namestore.service';
 import { OpenIdService } from '../open-id.service';
 import { Attribute } from '../attribute';
 import { Attestation } from '../attestation';
-import { Reference } from '../reference';
 import { IdentityService } from '../identity.service';
 import { finalize } from 'rxjs/operators';
 import { from, forkJoin, EMPTY } from 'rxjs';
@@ -20,18 +19,16 @@ import { from, forkJoin, EMPTY } from 'rxjs';
 export class EditIdentityComponent implements OnInit {
 
   identity: Identity;
-  showReferences: Boolean;
   attributes: Attribute[];
   attestations: Attestation[];
   attestationValues: {};
   requestedAttributes: Attribute[];
   missingAttributes: Attribute[];
   newAttribute: Attribute;
-  references: Reference[];
-  newReference: Reference;
-  missingReferences: Reference[];
-  requestedReferences: Reference[];
-  optionalReferences: Reference[];
+  newAttested: Attribute;
+  missingAttested: Attribute[];
+  requestedAttested: Attribute[];
+  optionalAttested: Attribute[];
 
   constructor(private reclaimService: ReclaimService,
               private identityService: IdentityService,
@@ -44,11 +41,11 @@ export class EditIdentityComponent implements OnInit {
   ngOnInit() {
     this.attributes = [];
     this.attestations = [];
-    this.optionalReferences = [];
+    this.optionalAttested = [];
     this.attestationValues = {};
     this.identity = new Identity('','');
-    this.newAttribute = new Attribute('', '', '', 'STRING', '');
-    this.newReference = new Reference('', '', '', '');
+    this.newAttribute = new Attribute('', '', '', '', 'STRING', '');
+    this.newAttested = new Attribute('', '', '', '', 'STRING', '');
       this.activatedRoute.params.subscribe(p => {
       if (p['id'] === undefined) {
         return;
@@ -59,7 +56,6 @@ export class EditIdentityComponent implements OnInit {
             if (ids[i].name == p['id']) {
               this.identity = ids[i];
               this.updateAttributes();
-              this.updateReferences();
               this.updateAttestations();
             }
           }
@@ -73,18 +69,25 @@ export class EditIdentityComponent implements OnInit {
     this.reclaimService.getAttributes(this.identity).subscribe(attributes => {
       this.attributes = [];
       this.requestedAttributes = [];
+      this.requestedAttested = [];
       if (attributes === null) {
         this.getMissingAttributes();
         return;
       }
       let i;
+      this.attributes = attributes;
       for (i = 0; i < attributes.length; i++) {
-        this.attributes.push(attributes[i]);
-        if (this.oidcService.getScope().includes(attributes[i].name)) {
+        if ((attributes[i].attestation === '') &&
+            this.oidcService.getScope().includes(attributes[i].name)) {
           this.requestedAttributes.push(attributes[i]);
         }
+        if ((attributes[i].attestation !== '') &&
+            this.oidcService.getAttestedScope().includes(attributes[i].name)) {
+          this.requestedAttested.push(attributes[i]);
+        }
       }
       this.getMissingAttributes();
+      this.getMissingAttested();
     },
     err => {
       //this.errorInfos.push("Error retrieving attributes for ``" + 
identity.name + "''");
@@ -117,7 +120,7 @@ export class EditIdentityComponent implements OnInit {
     }
     this.missingAttributes = [];
     for (i = 0; i < scopes.length; i++) {
-      const attribute = new Attribute('', '', '', 'STRING', '');
+      const attribute = new Attribute('', '', '', '', 'STRING', '');
       attribute.name = scopes[i];
       this.missingAttributes.push(attribute);
     }
@@ -155,7 +158,7 @@ export class EditIdentityComponent implements OnInit {
 
   canSaveIdentity() {
     return (this.canSaveAttribute() &&
-            this.canSaveReference());
+            this.canSaveAttested());
   }
 
   canSaveAttribute() {
@@ -167,30 +170,30 @@ export class EditIdentityComponent implements OnInit {
       !this.isInConflict(this.newAttribute);
   }
 
-  canSaveReference() {
-    if (this.canAddReference(this.newReference)) {
+  canSaveAttested() {
+    if (this.canAddAttested(this.newAttested)) {
       return true;
     }
-    return ((this.newReference.name === '') &&
-      (this.newReference.ref_value === '') &&
-      (this.newReference.ref_id === '')) &&
-      !this.isRefInConflict(this.newReference);
+    return ((this.newAttested.name === '') &&
+      (this.newAttested.attestation === '') &&
+      (this.newAttested.id === '')) &&
+      !this.isAttestedInConflict(this.newAttested);
   }
 
 
-  isRefInConflict(reference) {
+  isAttestedInConflict(attested) {
     let i;
-    if (undefined !== this.missingReferences) {
-      for (i = 0; i < this.missingReferences.length; i++) {
-        if (reference.name ===
-          this.missingReferences[i].name) {
+    if (undefined !== this.missingAttested) {
+      for (i = 0; i < this.missingAttested.length; i++) {
+        if (attested.name ===
+          this.missingAttested[i].name) {
           return true;
         }
       }
     }
-    if (undefined !== this.references) {
-      for (i = 0; i < this.references.length; i++) {
-        if (reference.name === this.references[i].name) {
+    if (undefined !== this.attributes) {
+      for (i = 0; i < this.attributes.length; i++) {
+        if (attested.name === this.attributes[i].name) {
           return true;
         }
       }
@@ -201,7 +204,6 @@ export class EditIdentityComponent implements OnInit {
 
   saveIdentity() {
     this.saveIdentityAttributes();
-    this.saveIdentityReferences();
   }
 
   saveIdentityAttributes() {
@@ -315,17 +317,18 @@ export class EditIdentityComponent implements OnInit {
       this.requestedAttributes.length;
   }
 
-  private saveIdentityReferences() {
-    this.storeReferences()
+  private saveIdentityAttested() {
+    this.storeAttested()
       .pipe(
         finalize(() => {
-          this.newReference.name = '';
-          this.newReference.ref_value = '';
-          this.newReference.ref_id = '';
+          this.newAttested.name = '';
+          this.newAttested.attestation = '';
+          this.newAttested.id = '';
+          this.newAttested.value = '';
         }))
       .subscribe(res => {
         //FIXME success dialog/banner
-        this.updateReferences();
+        this.updateAttributes();
       },
       err => {
         console.log(err);
@@ -333,11 +336,10 @@ export class EditIdentityComponent implements OnInit {
       });
   }
 
-  deleteReference(reference) {
-    this.reclaimService.deleteReference(this.identity, reference)
+  deleteAttested(attribute) {
+    this.reclaimService.deleteAttribute(this.identity, attribute)
       .subscribe(res => {
         //FIXME info dialog
-        this.updateReferences();
         this.updateAttributes();
       },
       err => {
@@ -347,52 +349,36 @@ export class EditIdentityComponent implements OnInit {
   }
 
 
-  getMissingReferences() {
-    const refscopes = this.oidcService.getRefScope();
+  getMissingAttested() {
+    const refscopes = this.oidcService.getAttestedScope();
     let i;
-    for (i = 0; i < this.requestedReferences.length; i++) {
+    for (i = 0; i < this.requestedAttested.length; i++) {
       for (var j = 0; j < refscopes.length; j++) {
-        if (this.requestedReferences[i].name === refscopes[j][0] ) {
+        if (this.requestedAttested[i].name === refscopes[j][0] ) {
           refscopes.splice(j,1);
         }
       }
     }
-    this.missingReferences = [];
-    this.optionalReferences = [];
+    this.missingAttested = [];
+    this.optionalAttested = [];
     for (i = 0; i < refscopes.length; i++) {
-      const reference = new Reference('', '', '', '');
+      const attribute = new Attribute('', '', '', '', 'STRING', '');
       if (refscopes[i][1] === true)
       {
-        reference.name = refscopes[i][0];
-        this.missingReferences.push(reference);
+        attribute.name = refscopes[i][0];
+        this.missingAttested.push(attribute);
       }
       if (refscopes[i][1] === false)
       {
-        reference.name = refscopes[i][0];
-        this.optionalReferences.push(reference);
+        attribute.name = refscopes[i][0];
+        this.optionalAttested.push(attribute);
       }
     }
   }
 
-  toggleShowRef() {
-    this.showReferences = !this.showReferences;
-  }
-
   private updateAttestations() {
-    this.reclaimService.getAttestation(this.identity).subscribe(attestations 
=> {
+    this.reclaimService.getAttestations(this.identity).subscribe(attestations 
=> {
       this.attestations = attestations;
-      //FIXME this is not how this API should work
-      //The API should already return attributes which can be used...
-      for (let i = 0; i < this.attestations.length; i++) {
-        this.reclaimService.parseAttest(this.attestations[i]).subscribe(values 
=>{
-          this.attestationValues[this.attestations[i].id]=values;
-        },
-        err => {
-          //this.errorInfos.push("Error parsing attestation ``" + 
attestation.name + "''");
-          console.log(err);
-        });
-
-      }
     },
     err => {
       //this.errorInfos.push("Error retrieving attestation for ``" + 
identity.name + "''");
@@ -400,68 +386,45 @@ export class EditIdentityComponent implements OnInit {
     });
   }
 
-  private updateReferences() {
-    this.reclaimService.getReferences(this.identity).subscribe(references => {
-      this.references = [];
-      this.requestedReferences = [];
-      if (references === null) {
-        this.getMissingReferences();
-        return;
-      }
-      const scope = this.oidcService.getRefScope();
-      let i;
-      for (i = 0; i < references.length; i++) {
-        this.references.push(references[i]);
-        let j;
-        for (j = 0; j < scope.length; j++) {
-          if (references[i].name === scope[j][0] ) {
-            this.requestedReferences.push(references[i]);
-          }
-        }
-      }
-      this.getMissingReferences();
-    },
-    err => {
-      //this.errorInfos.push("Error retrieving references for ``" + 
identity.name + "''");
-      console.log(err);
-    });
-  }
-
-  private storeReferences() {
+  private storeAttested() {
     const promises = [];
     let i;
-    if (undefined !== this.missingReferences) {
-      for (i = 0; i < this.missingReferences.length; i++) {
-        if ((this.missingReferences[i].ref_value === '') || 
(this.missingReferences[i].ref_id === '')) {
-          console.log("EmptyReferences: " + this.missingReferences[i]);
+    if (undefined !== this.missingAttested) {
+      for (i = 0; i < this.missingAttested.length; i++) {
+        if ((this.missingAttested[i].value === '') || 
(this.missingAttested[i].attestation !== '')) {
+          console.log("Empty Attestation: " + this.missingAttested[i]);
           continue;
         }
-        console.log("MissingReferences: " + this.missingReferences[i]);
-        promises.push(from(this.reclaimService.addReference(
-          this.identity, this.missingReferences[i])));
+        console.log("Missing Attestation: " + this.missingAttested[i]);
+        promises.push(from(this.reclaimService.addAttribute(
+          this.identity, this.missingAttested[i])));
       }
     }
-    if (undefined !== this.references) {
-      for (i = 0; i < this.references.length; i++) {
+    if (undefined !== this.attributes) {
+      for (i = 0; i < this.attributes.length; i++) {
+        if (this.attributes[i].attestation === '') {
+          continue;
+        }
         promises.push(
-          from(this.reclaimService.addReference(this.identity, 
this.references[i])));
+          from(this.reclaimService.addAttribute(this.identity, 
this.attributes[i])));
       }
     }
-    if ((this.newReference.ref_value !== '') || (this.newReference.ref_id !== 
'')) {
-      promises.push(from(this.reclaimService.addReference(this.identity, 
this.newReference)));
+    if ((this.newAttested.value !== '') && (this.newAttested.attestation !== 
'')
+        && (this.newAttested.name !== '')) {
+      promises.push(from(this.reclaimService.addAttribute(this.identity, 
this.newAttested)));
     }
 
     return forkJoin(promises);
   }
 
-  addReference() {
-    this.storeReferences()
+  addAttested() {
+    this.storeAttested()
     .pipe(
       finalize(() => {
-        this.newReference.name = '';
-        this.newReference.ref_value= '';
-        this.newReference.ref_id = '';
-        this.updateReferences();
+        this.newAttested.name = '';
+        this.newAttested.value= '';
+        this.newAttested.id = '';
+        this.newAttested.attestation = '';
         this.updateAttributes();
       }))
       .subscribe(res => {
@@ -476,65 +439,65 @@ export class EditIdentityComponent implements OnInit {
 
 
   isAttestation(attribute) {
-    if (attribute.flag ==='1') {
+    if (attribute.attestation !== '') {
       return true;
     }
     return false;
   }
 
-  canAddReference(reference) {
-    if ((reference.name === '') || (reference.ref_value === '') || 
(reference.ref_id === '')) {
+  canAddAttested(attribute) {
+    if ((attribute.name === '') || (attribute.value === '') || 
(attribute.attestation === '')) {
       return false;
     }
-    if (reference.name.indexOf(' ') >= 0) {
+    if (attribute.name.indexOf(' ') >= 0) {
       return false;
     }
-    return !this.isRefInConflict(reference);
+    return !this.isAttestedInConflict(attribute);
   }
 
-  referenceNameValid(reference) {
-    if (reference.name === '' && reference.ref_value === '' && 
reference.ref_id === '') {
+  attestedNameValid(attribute) {
+    if (attribute.name === '' && attribute.value === '' && 
attribute.attestation === '') {
       return true;
     }
-    if (reference.name.indexOf(' ') >= 0) {
+    if (attribute.name.indexOf(' ') >= 0) {
       return false;
     }
-    if (!/^[a-zA-Z0-9-_]+$/.test(reference.name)) {
+    if (!/^[a-zA-Z0-9-_]+$/.test(attribute.name)) {
       return false;
     }
-    return !this.isRefInConflict(reference);
+    return !this.isAttestedInConflict(attribute);
   }
 
-  referenceValueValid(reference: Reference) {
-    if (reference.ref_value === '') {
-      return reference.name === '';
+  attestedValueValid(attribute: Attribute) {
+    if (attribute.value === '') {
+      return attribute.name === '';
     }
     return true;
   }
 
-  referenceIDValid(reference: Reference) {
-    if (reference.ref_id === '') {
-      return reference.name === '';
+  attestedAttestationValid(attribute: Attribute) {
+    if (attribute.attestation === '') {
+      return attribute.name === '';
     }
     return true;
   }
 
 
-  isRefRequested(reference: Reference) {
-    if (undefined === this.requestedReferences) {
+  isAttestedRequested(attribute: Attribute) {
+    if (undefined === this.requestedAttested) {
       return false;
     } else {
       return -1 !==
-        this.requestedReferences.indexOf(reference);
+        this.requestedAttested.indexOf(attribute);
     }
   }
 
   isAttrRefRequested(attribute: Attribute) {
-    if (undefined === this.requestedReferences) {
+    if (undefined === this.requestedAttested) {
       return false;
     } else {
-      for (var j = 0; j < this.requestedReferences.length; j++) {
-        if (attribute.name === this.requestedReferences[j].name) {
+      for (var j = 0; j < this.requestedAttested.length; j++) {
+        if (attribute.name === this.requestedAttested[j].name) {
           return true;
         }
       }
@@ -542,31 +505,31 @@ export class EditIdentityComponent implements OnInit {
     }
   }
 
-  isoptRefRequested(reference: Reference) {
-    if (undefined === this.optionalReferences) {
+  isoptAttestedRequested(attribute: Attribute) {
+    if (undefined === this.optionalAttested) {
       return false;
     } else {
       return -1 !==
-        this.optionalReferences.indexOf(reference);
+        this.optionalAttested.indexOf(attribute);
     }
   }
 
-  isReferenceMissing() {
+  isAttestedMissing() {
     if (!this.inOpenIdFlow()) {
       return false;
     }
-    if (undefined === this.requestedReferences) {
+    if (undefined === this.requestedAttested) {
       return false;
     }
-    for (var i = 0; i < this.oidcService.getRefScope().length; i++) {
-      if (this.oidcService.getRefScope()[i][1] === true) {
+    for (var i = 0; i < this.oidcService.getAttestedScope().length; i++) {
+      if (this.oidcService.getAttestedScope()[i][1] === true) {
         var j;
-        for (j = 0; j < this.requestedReferences.length; j++) {
-          if (this.oidcService.getRefScope()[i][0] === 
this.requestedReferences[j].name){
+        for (j = 0; j < this.requestedAttested.length; j++) {
+          if (this.oidcService.getAttestedScope()[i][0] === 
this.requestedAttested[j].name){
             break;
           }
         }
-        if (j === this.requestedReferences.length){
+        if (j === this.requestedAttested.length){
           return true;
         }
       }
@@ -585,9 +548,9 @@ export class EditIdentityComponent implements OnInit {
   });
   }*/
 
-  isReferenceValid(reference: Reference) {
+  isAttestedValid(attribute: Attribute) {
     for (let i = 0; i < this.attestations.length; i++) {
-      if (reference.ref_id === this.attestations[i].id) {
+      if (attribute.attestation === this.attestations[i].id) {
         return this.isAttestationValid(this.attestations[i]);
       }
     }
@@ -598,22 +561,22 @@ export class EditIdentityComponent implements OnInit {
     //FIXME JWT specific
     //FIXME the expiration of the JWT should be a property of the attestation
     //Not part of the values
-    const now = Date.now().valueOf() / 1000;
-    if (this.attestationValues[attestation.id] === undefined) {
-      return false;
-    }
-    if (this.attestationValues[attestation.id]['exp'] === 'undefined') {
-      return false;
-    }
-    return this.attestationValues[attestation.id]['exp'] > now;
+    return true;
   }
 
+  attestationValuesForAttested(attribute: Attribute) {
+    for (let i = 0; i < this.attestations.length; i++) {
+      if (this.attestations[i].id == attribute.attestation) {
+        return this.attestations[i].attributes;
+      }
+    }
+  }
 
   isAnyAttestationInvalid() {
     if (!this.inOpenIdFlow()) {
       return false;
     }
-    if (undefined === this.requestedReferences) {
+    if (undefined === this.requestedAttested) {
       return false;
     }
     for (var j = 0; j < this.attestations.length; j++) {
@@ -624,42 +587,10 @@ export class EditIdentityComponent implements OnInit {
     return false;
   }
 
-  attestationValuesForReference(reference: Reference) {
-    return Object.keys(this.attestationValues[reference.ref_id]);
-  }
-
-  //FIXME JWT specific, this should be provided as part of API
-  private findReferenceForAttribute(attribute: Attribute) {
-    if (this.references === undefined) {
-      return null;
-    }
-    for (let i = 0; i < this.references.length; i++) {
-      if (this.references[i].ref_id === attribute.id) {
-        return this.references[i];
-      }
-    }
-    return null;
-  }
+  //FIXME attestations need an issuer field
   getIssuer(attribute: Attribute) {
-    let ref = this.findReferenceForAttribute(attribute);
-    if (null != ref && (this.attestationValues[ref.ref_id] !== undefined)) {
-      return this.attestationValues[ref.ref_id]['iss'];
-    }
-    return "UNKNOWN";
-  }
-  getReferencedName(attribute: Attribute) {
-    let ref = this.findReferenceForAttribute(attribute);
-    if (null != ref) {
-      return ref.ref_value;
-    }
     return "UNKNOWN";
   }
-  deleteReferenceByAttribute(attribute: Attribute) {
-    let ref = this.findReferenceForAttribute(attribute);
-    if (null != ref) {
-      this.deleteReference(ref);
-    }
-  }
 
   getFhGAttestation() {
     localStorage.setItem('userForAttestation', this.identity.name);
diff --git a/src/app/identity-list/identity-list.component.html 
b/src/app/identity-list/identity-list.component.html
index 18c9ffb..de47837 100644
--- a/src/app/identity-list/identity-list.component.html
+++ b/src/app/identity-list/identity-list.component.html
@@ -76,7 +76,7 @@
     <div class="alert alert-secondary fade show" 
*ngIf="!hasAttributes(identity)">
       This identity has no attributes. Maybe try <a class="buttonlink" 
[routerLink]="['/edit-identity', identity.name]">adding some?</a>
     </div>
-    <div *ngIf="isAttributeMissing(identity) || isReferenceMissing(identity)" 
class="alert alert-danger alert-dismissible fade show" role="alert">
+    <div *ngIf="isAttributeMissing(identity) || isAttestedMissing(identity)" 
class="alert alert-danger alert-dismissible fade show" role="alert">
       <span class="fa fa-openid"></span> This identity cannot be used because 
it's missing requested information:
       <ul>
         <li *ngFor="let attr of getMissing(identity)">{{attr}}</li>
@@ -87,13 +87,13 @@
       </button>
     </div>
     <div *ngIf="isReqReferenceInvalid(identity)" class="alert alert-danger 
alert-dismissible fade show" role="alert">
-      <span class="fa fa-openid"></span> This identity cannot be used because 
one or more references are invalid.
+      <span class="fa fa-openid"></span> This identity cannot be used because 
one or more attested attributes are invalid.
       <button class="btn btn-primary" (click)="editIdentity(identity)">
         <span class="fa fa-pencil-square-o"></span> Edit
       </button>
     </div>
-    <div *ngIf="(0 < requestedReferences[identity.pubkey]?.length) && 
inOpenIdFlow()" class="alert alert-danger alert-dismissible fade show" 
role="alert">
-      <span class="fa fa-openid"></span> Please note that sharing references 
might disclose additional information stored in the attestation.
+    <div *ngIf="(0 < requestedAttested[identity.pubkey]?.length) && 
inOpenIdFlow()" class="alert alert-danger alert-dismissible fade show" 
role="alert">
+      <span class="fa fa-openid"></span> Please note that sharing attested 
attributes might disclose additional information stored in the attestation.
     </div>
     <div class="card-body">
       <!-- Attribute table --> 
@@ -103,11 +103,11 @@
         </h6>
         <table class="table pb-1">
           <tbody>
-            <tr [class.openid]="inOpenIdFlow()" 
[class.text-primary]="isRequested(identity, attribute) || 
isAttrRefRequested(identity, attribute)"
-               [class.text-secondary]="!isAttrRefRequested(identity, 
attribute) && isAttestation(attribute)"
+            <tr [class.openid]="inOpenIdFlow()" 
[class.text-primary]="isRequested(identity, attribute) || 
isAttestedRequested(identity, attribute)"
+               [class.text-secondary]="!isAttestedRequested(identity, 
attribute) && isAttestation(attribute)"
                *ngFor="let attribute of attributes[identity.pubkey]">
               <td>
-                <div style="min-width: 15em"><span 
*ngIf="isRequested(identity, attribute) || isAttrRefRequested(identity, 
attribute)" class="fa fa-openid"></span> {{attribute.name}}</div>
+                <div style="min-width: 15em"><span 
*ngIf="isRequested(identity, attribute) || isAttestedRequested(identity, 
attribute)" class="fa fa-openid"></span> {{attribute.name}}</div>
               </td>
               <td>
                 <div *ngIf="attribute.value.length <= 20" style="min-width: 
15em">{{attribute.value}}</div>
@@ -123,7 +123,7 @@
       <div>
 
         <div>
-          <button *ngIf="canAuthorize(identity)" [disabled]="!inOpenIdFlow() 
|| isAttributeMissing(identity) || isReferenceMissing(identity) || 
!isClientVerified() || isReqReferenceInvalid(identity)" 
(click)="loginIdentity(identity)" class="btn btn-primary mr-1 openid-login">
+          <button *ngIf="canAuthorize(identity)" [disabled]="!inOpenIdFlow() 
|| isAttributeMissing(identity) || isAttestedMissing(identity) || 
!isClientVerified() || isReqReferenceInvalid(identity)" 
(click)="loginIdentity(identity)" class="btn btn-primary mr-1 openid-login">
             <span *ngIf="isClientVerified()"><i class="fa fa-openid"></i> 
Share from this identity</span>
             <span *ngIf="!isClientVerified()"><i class="fa 
fa-exclamation-circle"></i> Sharing disabled</span>
           </button>
diff --git a/src/app/identity-list/identity-list.component.ts 
b/src/app/identity-list/identity-list.component.ts
index cd7e172..bc7ab63 100644
--- a/src/app/identity-list/identity-list.component.ts
+++ b/src/app/identity-list/identity-list.component.ts
@@ -2,7 +2,7 @@ import { Component, OnInit } from '@angular/core';
 import { ActivatedRoute, Router } from '@angular/router';
 
 import { Attribute } from '../attribute';
-import { Reference } from '../reference';
+import { Attestation } from '../attestation';
 import { GnsService } from '../gns.service';
 import { Identity } from '../identity';
 import { IdentityService } from '../identity.service';
@@ -22,12 +22,12 @@ import { from, forkJoin, EMPTY } from 'rxjs';
 export class IdentityListComponent implements OnInit {
 
   requestedAttributes: any;
-  requestedReferences: any;
+  requestedAttested: any;
   missingAttributes: any;
-  missingReferences: any;
-  optionalReferences: any;
+  missingAttestations: any;
+  optionalAttested: any;
   attributes: any;
-  references: any;
+  attestations: any;
   identities: Identity[];
   showConfirmDelete: any;
   connected: any;
@@ -46,14 +46,14 @@ export class IdentityListComponent implements OnInit {
 
   ngOnInit() {
     this.attributes = {};
-    this.references = {};
+    this.attestations = {};
     this.identities = [];
     this.showConfirmDelete = null;
     this.requestedAttributes = {};
     this.missingAttributes = {};
-    this.requestedReferences = {};
-    this.missingReferences = {};
-    this.optionalReferences = {};
+    this.requestedAttested = {};
+    this.missingAttestations = {};
+    this.optionalAttested = {};
     this.connected = false;
     this.modalOpened = false;
     if (undefined !== this.route.snapshot.queryParams["code"]) {
@@ -95,59 +95,46 @@ export class IdentityListComponent implements OnInit {
     }
     this.missingAttributes[identity.pubkey] = [];
     for (i = 0; i < scopes.length; i++) {
-      const attribute = new Attribute('', '', '', 'STRING', '');
+      const attribute = new Attribute('', '', '', '', 'STRING', '');
       attribute.name = scopes[i];
       this.missingAttributes[identity.pubkey].push(attribute);
     }
   }
 
-  getMissingReferences(identity) {
-    const refscopes = this.oidcService.getRefScope();
+  getMissingAttested(identity) {
+    const refscopes = this.oidcService.getAttestedScope();
     let i;
-    for (i = 0; i < this.requestedReferences[identity.pubkey].length; i++) {
+    for (i = 0; i < this.requestedAttested[identity.pubkey].length; i++) {
       for (var j = 0; j < refscopes.length; j++) {
-        if (this.requestedReferences[identity.pubkey][i].name === 
refscopes[j][0] ) {
+        if (this.requestedAttested[identity.pubkey][i].name === 
refscopes[j][0] ) {
           refscopes.splice(j,1);
         }
       }
     }
-    this.missingReferences[identity.pubkey] = [];
-    this.optionalReferences[identity.pubkey] = [];
+    this.missingAttestations[identity.pubkey] = [];
+    this.optionalAttested[identity.pubkey] = [];
     for (i = 0; i < refscopes.length; i++) {
-      const reference = new Reference('', '', '', '');
+      const attested = new Attribute('', '', '', '', 'STRING', '');
       if (refscopes[i][1] === true)
       {
-        reference.name = refscopes[i][0];
-        this.missingReferences[identity.pubkey].push(reference);
+        attested.name = refscopes[i][0];
+        this.missingAttestations[identity.pubkey].push(attested);
       }
       if (refscopes[i][1] === false)
       {
-        reference.name = refscopes[i][0];
-        this.optionalReferences[identity.pubkey].push(reference);
+        attested.name = refscopes[i][0];
+        this.optionalAttested[identity.pubkey].push(attested);
       }
     }
   }
 
-  private updateReferences(identity) {
-    this.reclaimService.getReferences(identity).subscribe(references => {
-      this.references[identity.pubkey] = [];
-      this.requestedReferences[identity.pubkey] = [];
-      if (references === null) {
-        this.getMissingReferences(identity);
-        return;
-      }
-     const scope = this.oidcService.getRefScope();
-      let i;
-      for (i = 0; i < references.length; i++) {
-        this.references[identity.pubkey].push(references[i]);
-        let j;
-        for (j = 0; j < scope.length; j++) {
-          if (references[i].name === scope[j][0] ) {
-            this.requestedReferences[identity.pubkey].push(references[i]);
-          }
-        }
+  private updateAttestations(identity) {
+    this.attestations[identity.pubkey] = [];
+    this.requestedAttested[identity.pubkey] = [];
+    this.reclaimService.getAttestations(identity).subscribe(attestations => {
+      if (attestations !== null) {
+        this.attestations[identity.pubkey] = attestations;
       }
-      this.getMissingReferences(identity);
     },
     err => {
       this.errorInfos.push("Error retrieving references for ``" + 
identity.name + "''");
@@ -166,11 +153,17 @@ export class IdentityListComponent implements OnInit {
       let i;
       for (i = 0; i < attributes.length; i++) {
         this.attributes[identity.pubkey].push(attributes[i]);
-        if (this.oidcService.getScope().includes(attributes[i].name)) {
+        if ((attributes[i].attestation === '') &&
+            this.oidcService.getScope().includes(attributes[i].name)) {
           this.requestedAttributes[identity.pubkey].push(attributes[i]);
         }
+        if ((attributes[i].attestation !== '') &&
+            this.oidcService.getAttestedScope().includes(attributes[i].name)) {
+          this.requestedAttested[identity.pubkey].push(attributes[i]);
+        }
       }
       this.getMissingAttributes(identity);
+      this.getMissingAttested(identity);
     },
     err => {
       this.errorInfos.push("Error retrieving attributes for ``" + 
identity.name + "''");
@@ -191,7 +184,7 @@ export class IdentityListComponent implements OnInit {
   }
 
   loginIdentity(identity) {
-    this.oidcService.setReferences(this.requestedReferences[identity.pubkey]);
+    this.oidcService.setAttestations(this.requestedAttested[identity.pubkey]);
     this.oidcService.login(identity).subscribe(() => {
       console.log('Successfully logged in');
       this.authorize();
@@ -269,7 +262,7 @@ export class IdentityListComponent implements OnInit {
 
       identities.forEach(identity => {
         this.updateAttributes(identity);
-        this.updateReferences(identity);
+        this.updateAttestations(identity);
       });
       if (!this.modalOpened) {
         this.closeModal('GnunetInfo');
@@ -291,22 +284,22 @@ export class IdentityListComponent implements OnInit {
     return this.isConnected() && 0 != this.identities.length;
   }
 
-  isReferenceMissing(identity) {
+  isAttestedMissing(identity) {
     if (!this.inOpenIdFlow()) {
       return false;
     }
-    if (undefined === this.requestedReferences) {
+    if (undefined === this.requestedAttested) {
       return false;
     }
-    for (var i = 0; i < this.oidcService.getRefScope().length; i++) {
-      if (this.oidcService.getRefScope()[i][1] === true) {
+    for (var i = 0; i < this.oidcService.getAttestedScope().length; i++) {
+      if (this.oidcService.getAttestedScope()[i][1] === true) {
         var j;
-        for (j = 0; j < this.requestedReferences.length; j++) {
-          if (this.oidcService.getRefScope()[i][0] === 
this.requestedReferences[j].name){
+        for (j = 0; j < this.requestedAttested.length; j++) {
+          if (this.oidcService.getAttestedScope()[i][0] === 
this.requestedAttested[j].name){
             break;
           }
         }
-        if (j === this.requestedReferences.length){
+        if (j === this.requestedAttested.length){
           return true;
         }
       }
@@ -314,12 +307,13 @@ export class IdentityListComponent implements OnInit {
     return false;
   }
 
-  isAttrRefRequested(identity: Identity, attribute: Attribute) {
-    if (undefined === this.requestedReferences[identity.pubkey]) {
+  isAttestedRequested(identity: Identity, attribute: Attribute) {
+    if (undefined === this.requestedAttested[identity.pubkey]) {
       return false;
     } else {
-      for (var j = 0; j < this.requestedReferences[identity.pubkey].length; 
j++) {
-        if (attribute.name === 
this.requestedReferences[identity.pubkey][j].name) {
+      for (var j = 0; j < this.requestedAttested[identity.pubkey].length; j++) 
{
+        if ((attribute.attestation !== '') &&
+            (attribute.name === 
this.requestedAttested[identity.pubkey][j].name)) {
           return true;
         }
       }
@@ -328,7 +322,7 @@ export class IdentityListComponent implements OnInit {
   }
 
   isAttestation(attribute: Attribute) {
-    if (attribute.flag ==='1') {
+    if (attribute.attestation !== '') {
       return true;
     }
     return false;
@@ -344,11 +338,11 @@ export class IdentityListComponent implements OnInit {
     if (!this.inOpenIdFlow()) {
       return [];
     }
-    if (undefined === this.optionalReferences[identity.pubkey]) {
+    if (undefined === this.optionalAttested[identity.pubkey]) {
       return [];
     }
-    for (i = 0; i < this.optionalReferences[identity.pubkey].length; i++) {
-        arr.push(this.optionalReferences[identity.pubkey][i].name);
+    for (i = 0; i < this.optionalAttested[identity.pubkey].length; i++) {
+        arr.push(this.optionalAttested[identity.pubkey][i].name);
     }
     return arr;
   }
diff --git a/src/app/open-id.service.ts b/src/app/open-id.service.ts
index 840f19d..12f2279 100644
--- a/src/app/open-id.service.ts
+++ b/src/app/open-id.service.ts
@@ -5,7 +5,7 @@ import { Identity } from './identity';
 import { ConfigService } from './config.service';
 import { Router } from '@angular/router';
 import { GnsService } from './gns.service';
-import { Reference } from './reference';
+import { Attribute } from './attribute';
 
 @Injectable()
 export class OpenIdService {
@@ -75,10 +75,10 @@ export class OpenIdService {
     '&nonce=' + this.params['nonce'];
   }
 
-  setReferences(references: Reference[]) {
+  setAttestations(attestations: Attribute[]) {
     this.referenceString = "";
-    for(var i = 0; i < references.length; i++) {
-      this.referenceString = this.referenceString + references[i].name + " ";
+    for(var i = 0; i < attestations.length; i++) {
+      this.referenceString = this.referenceString + attestations[i].name + " ";
     }
   }
 
@@ -112,7 +112,7 @@ export class OpenIdService {
     return scopes;
   }
 
-  getRefScope(): any {
+  getAttestedScope(): any {
     if (!this.inOpenIdFlow()) {
       return [];
     }
diff --git a/src/app/reclaim.service.ts b/src/app/reclaim.service.ts
index 20bdac5..029d07f 100644
--- a/src/app/reclaim.service.ts
+++ b/src/app/reclaim.service.ts
@@ -40,16 +40,6 @@ export class ReclaimService {
     return this.http.post<Ticket>(this.config.get().apiUrl + '/reclaim/revoke',
       ticket);
   }
-  getReferences(identity: Identity): Observable<Reference[]> {
-    return this.http.get<Reference[]>(this.config.get().apiUrl +
-      '/reclaim/attestation/reference/' + identity.name);
-  }
-
-  addReference(identity: Identity, reference: Reference) {
-    return this.http.post<Reference>(this.config.get().apiUrl +
-      '/reclaim/attestation/reference/' + identity.name,
-      reference);
-  }
 
   deleteReference(identity: Identity, reference: Reference) {
     const options = {headers: new HttpHeaders({'Content-Type': 
'application/json',}),
@@ -58,7 +48,7 @@ export class ReclaimService {
       identity.name + '/' + reference.ref_id, options);
   }
 
-  getAttestation(identity: Identity): Observable<Attestation[]> {
+  getAttestations(identity: Identity): Observable<Attestation[]> {
     return this.http.get<Attestation[]>(this.config.get().apiUrl +
       '/reclaim/attestation/' + identity.name);
   }
@@ -74,15 +64,6 @@ export class ReclaimService {
       identity.name + '/' + attestation.id);
   }
 
-  //FIXME this should be replaced by a data model that ties attributes
-  //and references to attestations together.
-  parseAttest(attestation: Attestation) {
-    var json = JSON.parse('{"value":"'+ attestation.value + '", "type":"'+ 
attestation.type + '"}')
-    return this.http.post(this.config.get().apiUrl +
-      '/reclaim/attestation/parse',json
-      );
-  }
-
   fixmeExchangeCode(code: String) {
     let json = JSON.parse("{}");
     return 
this.http.post("http://localhost:4567/token?grant_type=authorization_code&client_id=reclaimid&redirect_uri=http://localhost:4200/index.html&scope=openid&code="+code,
 json);

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]