Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NIP-76: Private Channels - Draft 2 - Includes Client Implementation and Tool kit library #116

Draft
wants to merge 42 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
e7f5e23
fixing of ExpressionChangedAfterItHasBeenCheckedError in profile. com…
d-krause Mar 6, 2023
42babae
adding Observable to NostrRelaySubscription type - makes it easier to…
d-krause Mar 6, 2023
d0d8c0d
NIP76 initial commit
d-krause Mar 6, 2023
434875d
basic key sharing , viewing other peoples private threads
d-krause Mar 8, 2023
a0cf4bd
adding follows, replies, and reactions, new nprivatethread nip19
d-krause Mar 11, 2023
08eca5d
expiring single use only cookie to encrypt the session
d-krause Mar 11, 2023
ddedb4b
Merge remote-tracking branch 'upstream/main' into main
d-krause Mar 11, 2023
57d1667
pre-refactor ContentDocument
d-krause Mar 11, 2023
5507832
some refactoring, more to come
d-krause Mar 12, 2023
0dcfdeb
nip76-tools update changes - Buffers are now Uint8Arrays, crypto is n…
d-krause Mar 13, 2023
08c7b30
more refactoring, storing content as array, signing all content, prev…
d-krause Mar 16, 2023
c559ca8
renaming Private Thread to Private Channel
d-krause Mar 16, 2023
97a9d81
more refactoring, removing the bastard rp key, isolating wallet stora…
d-krause Mar 19, 2023
bbd81c1
new created_at and keyset index reducer utilities. fully functioning …
d-krause Mar 20, 2023
0137320
new HDKIndex replaces IndexDocument - much more organized. removing u…
d-krause Mar 22, 2023
0313856
removing content sig, now verifying by pubkey owenership. pushing mor…
d-krause Mar 24, 2023
63f279e
condensing wallet indexes down to one documentsIndex. removing isTop…
d-krause Mar 27, 2023
880e430
renming add-thread to add-channel
d-krause Mar 27, 2023
bb4d950
renaming add-thread to add-channel
d-krause Mar 27, 2023
6ed051a
adding channel invitations is working, now need to work on reading an…
d-krause Mar 28, 2023
2456d6b
fully functioning invitations and rsvps
d-krause Mar 30, 2023
27bb01f
event deleting, copying invitation without saving, ability to delete …
d-krause Mar 30, 2023
475fcab
new rsvp class resembles a PrivateChannelPointer - channel owner can …
d-krause Mar 30, 2023
b3e8dce
new diagnostics component. handling invites and rsvps, suspension and…
d-krause Apr 1, 2023
ea6eb79
better ui flow
d-krause Apr 3, 2023
9de1dc5
rename component part 1
d-krause Apr 3, 2023
2820cd0
rename component part 2
d-krause Apr 3, 2023
ad1297c
rename component part 3
d-krause Apr 3, 2023
ad29b31
adding demo starter components
d-krause Apr 4, 2023
7a023f8
fully functionining demo code
d-krause Apr 4, 2023
d18fb91
Merge remote-tracking branch 'upstream/main' into nip76-draft-2
d-krause Apr 6, 2023
037c7d6
new dependency for event-buttons component
d-krause Apr 6, 2023
0183a96
updating package.json to use npmjs version of animiq-nip76-tools
d-krause Apr 6, 2023
a7bc303
cleanup demo and dev only changes
d-krause Apr 6, 2023
e8898c4
cleanup demo and dev only changes
d-krause Apr 6, 2023
d935900
cleanup demo and dev only changes
d-krause Apr 6, 2023
b142b67
cleanup demo and dev only changes removed
d-krause Apr 6, 2023
f07b0f2
cleanup demo and dev only changes removed
d-krause Apr 6, 2023
1889e9f
Merge remote-tracking branch 'upstream/main' into nip76-draft-2
d-krause Apr 18, 2023
9ee0818
WORK IN PROGRESS: refactors for supporting blockcore-wallet extensions
d-krause Apr 23, 2023
db973ae
blockcore-wallet no longer exposes any private channel private keys t…
d-krause Apr 25, 2023
88e8ab5
refactor moving key management from wallet to web storage. streamlini…
d-krause Apr 26, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"@twogate/ngx-photo-gallery": "^1.4.0",
"@types/sharedworker": "^0.0.91",
"angularx-qrcode": "^15.0.1",
"animiq-nip76-tools": "file:../../animiq-nip76-tools/dist",
d-krause marked this conversation as resolved.
Show resolved Hide resolved
"dexie": "^3.2.3",
"html5-qrcode": "^2.3.7",
"idb": "^7.1.1",
Expand Down
29 changes: 29 additions & 0 deletions src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ import { LoginComponent } from './connect/login/login';
import { CreateProfileComponent } from './connect/create/create';
import { EditorBadgesComponent } from './editor-badges/editor';
import { BadgeComponent } from './badge/badge';
import { Nip76MainComponent } from './nip76/nip76-main/nip76-main.component';
import { Nip76DemoService } from './nip76/demo-only/nip76-demo.service';
import { Nip76DemoStarterComponent } from './nip76/demo-only/nip76-demo-starter/nip76-demo-starter.component';

const routes: Routes = [
{
Expand Down Expand Up @@ -139,6 +142,32 @@ const routes: Routes = [
data: LoadingResolverService,
},
},
{
path: 'private-channels',
component: Nip76MainComponent,
canActivate: [AuthGuard],
resolve: {
data: LoadingResolverService,
},
},
{
path: 'private-channels/sent-rsvps',
component: Nip76MainComponent,
canActivate: [AuthGuard],
data: { tabIndex: 1 },
resolve: {
data: LoadingResolverService,
},
},
{
path: 'private-channels/:channelPubKey/notes',
component: Nip76MainComponent,
canActivate: [AuthGuard],
data: { tabIndex: 3 },
resolve: {
data: LoadingResolverService,
},
},
{
path: 'badges/:id',
component: BadgesComponent,
Expand Down
3 changes: 3 additions & 0 deletions src/app/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,9 @@ header {
overscroll-behavior-y: contain;
overflow-x: hidden;
overflow-y: overlay !important;

flex-direction: column;
display: flex;
}

.app-mediaplayer {
Expand Down
4 changes: 4 additions & 0 deletions src/app/app.html
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,10 @@ <h3><span *ngIf="profile?.name">@</span>{{ profile?.name }}</h3>
<mat-icon>badge</mat-icon>
<span>Badges</span>
</a>
<a [routerLink]="['/private-channels']" mat-menu-item (click)="toggleProfileMenu()" [routerLinkActiveOptions]="{ exact: true }" routerLinkActive="active">
<mat-icon>key</mat-icon>
<span>Private Channels</span>
</a>
<a [routerLink]="['/settings']" mat-menu-item (click)="toggleProfileMenu()" [routerLinkActiveOptions]="{ exact: true }" routerLinkActive="active">
<mat-icon>settings</mat-icon>
<span>Settings</span>
Expand Down
28 changes: 27 additions & 1 deletion src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,19 @@ import { BadgeComponent } from './badge/badge';
import { MAT_FORM_FIELD_DEFAULT_OPTIONS } from '@angular/material/form-field';
import { DragScrollModule } from 'ngx-drag-scroll';
import { ZappersListDialogComponent } from './shared/zappers-list-dialog/zappers-list-dialog.component';
import { Nip76MainComponent } from './nip76/nip76-main/nip76-main.component';
import { AddChannelDialog } from './nip76/nip76-add-channel-dialog/add-channel-dialog.component';
import { Nip76EventButtonsComponent } from './nip76/nip76-event-buttons/nip76-event-buttons.component';
import { Nip76EventThreadComponent } from './nip76/nip76-event-thread/nip76-event-thread.component';
import { Nip76ContentComponent } from './nip76/nip76-content/nip76-event-content.component';
import { Nip76AddInvitationComponent } from './nip76/nip76-add-invitation/nip76-add-invitation.component';
import { Nip76DiagnosticsComponent } from './nip76/nip76-diagnostics/nip76-diagnostics.component';
import { Nip76ChannelHeaderComponent } from './nip76/nip76-channel/nip76-channel.component';
import { Nip76ChannelNotesComponent } from './nip76/nip76-channel-notes/nip76-channel-notes.component';
import { Nip76RsvpsSentComponent } from './nip76/nip76-rsvps-sent/nip76-rsvps-sent.component';
import { Nip76DemoService } from './nip76/demo-only/nip76-demo.service';
import { Nip76DemoStarterComponent, Nip76DemoCreateComponent, Nip76DemoKeyComponent } from './nip76/demo-only/nip76-demo-starter/nip76-demo-starter.component';

@NgModule({
declarations: [
AppComponent,
Expand Down Expand Up @@ -244,6 +257,19 @@ import { ZappersListDialogComponent } from './shared/zappers-list-dialog/zappers
TagsComponent,
BadgeComponent,
ZappersListDialogComponent,
Nip76MainComponent,
AddChannelDialog,
Nip76EventButtonsComponent,
Nip76EventThreadComponent,
Nip76ContentComponent,
Nip76AddInvitationComponent,
Nip76DiagnosticsComponent,
Nip76ChannelHeaderComponent,
Nip76ChannelNotesComponent,
Nip76RsvpsSentComponent,
Nip76DemoKeyComponent,
Nip76DemoCreateComponent,
Nip76DemoStarterComponent
],
imports: [
HttpClientModule,
Expand Down Expand Up @@ -322,7 +348,7 @@ import { ZappersListDialogComponent } from './shared/zappers-list-dialog/zappers
}),
],
exports: [],
providers: [{ provide: MAT_FORM_FIELD_DEFAULT_OPTIONS, useValue: { appearance: 'outline' } }, AuthGuardService, AppUpdateService, CheckForUpdateService, ChatService, UserService],
providers: [{ provide: MAT_FORM_FIELD_DEFAULT_OPTIONS, useValue: { appearance: 'outline' } }, AuthGuardService, AppUpdateService, CheckForUpdateService, ChatService, UserService, Nip76DemoService],
bootstrap: [AppComponent],
})
export class AppModule {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<mat-card class="intro">
<b>Thanks for coming to checkout the Nip76 Private Channels Demo.</b>
<p>
You may use your own private nostr key, but we understand why many users would be hesitant
to do this. If so, please feel free to use a demo profile like
<a class="action-link" (click)="copyKey('Alice')">Alice</a>
or <a class="action-link" (click)="copyKey('Bob')">Bob</a>,
or create an entirely new user.
</p>
<div class="menubar">
<button class="menubar-button" mat-flat-button (click)="demoUserType = 'existing'"
[color]="demoUserType === 'existing' ? 'primary' : 'secondary'"> Use Existing User </button>
<button class="menubar-button" mat-flat-button (click)="demoUserType = 'new'"
[color]="demoUserType === 'new' ? 'primary' : 'secondary'"> Create New User </button>
</div>
</mat-card>
<nip76-demo-key *ngIf="demoUserType === 'existing'"></nip76-demo-key>
<nip76-demo-create *ngIf="demoUserType === 'new'"></nip76-demo-create>
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
.intro {
position: absolute;
top: 86px;
padding: 8px;
left: 198px;
z-index: 1000;
width: 66%;
background-color: floralwhite;
border-radius: 20px;
}

.menubar {
display: flex;
flex-direction: row;
justify-content: center;
}

.menubar-button {
display: flex;
}

.action-link {
cursor: pointer;
}

p {
margin: 4px 0px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { Nip76DemoStarterComponent } from './nip76-demo-starter.component';

describe('LoginOrCreateNewComponent', () => {
let component: Nip76DemoStarterComponent;
let fixture: ComponentFixture<Nip76DemoStarterComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ Nip76DemoStarterComponent ]
})
.compileComponents();

fixture = TestBed.createComponent(Nip76DemoStarterComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { Component } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { MatSnackBar } from '@angular/material/snack-bar';
import { Router } from '@angular/router';
import { filter } from 'rxjs';
import { CreateProfileComponent } from 'src/app/connect/create/create';
import { ConnectKeyComponent } from 'src/app/connect/key/key';
import { AuthenticationService } from 'src/app/services/authentication';
import { DataService } from 'src/app/services/data';
import { ProfileService } from 'src/app/services/profile';
import { SecurityService } from 'src/app/services/security';
import { ThemeService } from 'src/app/services/theme';
import { Utilities } from 'src/app/services/utilities';
import { defaultSnackBarOpts } from '../../nip76.service';
import { Nip76DemoService } from '../nip76-demo.service';



@Component({
selector: 'app-nip76-demo-starter',
templateUrl: './nip76-demo-starter.component.html',
styleUrls: ['./nip76-demo-starter.component.scss']
})
export class Nip76DemoStarterComponent {
demoUserType: 'existing' | 'new' = 'existing';
constructor(
private snackBar: MatSnackBar,
private profileService: ProfileService,
private router: Router
) { }

ngOnInit() {
this.profileService.profile$.pipe(filter(x => !!x)).subscribe(x => {
this.router.navigateByUrl('/private-channels');
});
}

copyKey(name: 'Alice' | 'Bob') {
const key = {
'Alice': 'nsec1y72ekupwshrl6zca2kx439uz23x4fqppc6gg9y9e5up5es06qqxqlcw698',
'Bob': 'nsec12l6c5g8e7gt9twyctk0t073trlrf2zzs88240k3d2dmqlyh2hwhq9s2wl3'
}[name];
navigator.clipboard.writeText(key);
this.snackBar.open(`${name}'s key is now in your clipboard.`, 'Hide', defaultSnackBarOpts);
}
}

@Component({
selector: 'nip76-demo-key',
templateUrl: '../../../connect/key/key.html',
styleUrls: ['../../../connect/key/key.css', '../../../connect/connect.css']
})
export class Nip76DemoKeyComponent extends ConnectKeyComponent {

constructor(
dialog: MatDialog,
theme: ThemeService,
private router1: Router,
security: SecurityService,
nip76DemoService: Nip76DemoService

) {
super(dialog, theme, router1, security);
this.step = 3;
}

override async persistKey() {
super.persistKey();
setTimeout(() => {
this.router1.navigateByUrl('/private-channels');
}, 200)
}

}

@Component({
selector: 'nip76-demo-create',
templateUrl: '../../../connect/create/create.html',
styleUrls: ['../../../connect/create/create.css', '../../../connect/connect.css']
})
export class Nip76DemoCreateComponent extends CreateProfileComponent {

constructor(
utilities: Utilities,
dataService: DataService,
profileService: ProfileService,
authService: AuthenticationService,
theme: ThemeService,
private router1: Router,
security: SecurityService,
nip76DemoService: Nip76DemoService
) {
super(utilities, dataService, profileService, authService, theme, router1, security)
}

override async persistKey() {
super.persistKey();
setTimeout(() => {
this.router1.navigateByUrl('/private-channels');
}, 200)
}
}

Loading