summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jordan Johnson-Doyle <jordan@doyle.la> 2019-03-17 19:48:53 +0000
committerGravatar Jordan Johnson-Doyle <jordan@doyle.la> 2019-03-17 19:48:53 +0000
commit9b363f635da02e352ef06cf011da50010455883d (patch)
tree7978b162b20f46766a52b79ce208bc0e6f7fedb3
parentcf4496169fbc92588a25d1598ef47c3ebd6ce52a (diff)
Add quick prototype of a profile ('proofs') page
-rw-r--r--package-lock.json6
-rw-r--r--package.json1
-rw-r--r--src/common/KeybaseUser.ts5
-rw-r--r--src/content/KeyRing.ts17
-rw-r--r--src/content/ScriptInterceptor.ts8
-rw-r--r--src/popup/js/App.tsx16
-rw-r--r--src/popup/js/pages/Index.tsx120
-rw-r--r--src/popup/js/pages/User.tsx96
-rw-r--r--src/popup/js/pages/Users.tsx9
9 files changed, 192 insertions, 86 deletions
diff --git a/package-lock.json b/package-lock.json
index d760e90..138c4ff 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -206,9 +206,9 @@
}
},
"@types/react-router": {
- "version": "4.0.31",
- "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-4.0.31.tgz",
- "integrity": "sha512-57Tqu1EDMgDzHhmIEjjQZHrc/N7/+GGv6CtH1wRTLmMIy3UMxX69vQoeEz0AmK0/zkf5ecfEW1ZX8DLVQ6Gl7Q==",
+ "version": "4.4.5",
+ "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-4.4.5.tgz",
+ "integrity": "sha512-12+VOu1+xiC8RPc9yrgHCyLI79VswjtuqeS2gPrMcywH6tkc8rGIUhs4LaL3AJPqo5d+RPnfRpNKiJ7MK2Qhcg==",
"dev": true,
"requires": {
"@types/history": "*",
diff --git a/package.json b/package.json
index 121c2e5..339cfdc 100644
--- a/package.json
+++ b/package.json
@@ -18,6 +18,7 @@
"@types/bluebird": "^3.5.26",
"@types/react": "^16.8.8",
"@types/react-dom": "^16.8.2",
+ "@types/react-router": "^4.4.5",
"@types/react-router-dom": "^4.3.1",
"copy-webpack-plugin": "^5.0.1",
"css-loader": "^1.0.1",
diff --git a/src/common/KeybaseUser.ts b/src/common/KeybaseUser.ts
index 5920ea6..90d47bf 100644
--- a/src/common/KeybaseUser.ts
+++ b/src/common/KeybaseUser.ts
@@ -3,10 +3,13 @@ export interface Proof {
name: string,
state: number, // TODO: make this enum
url: string,
+ tag: string,
}
export interface KeybaseUser {
name: string,
avatar: string,
- proofs: {[name: string]: Proof}
+ realName: string,
+ location: string,
+ proofs: {[name: string]: Proof[]}
} \ No newline at end of file
diff --git a/src/content/KeyRing.ts b/src/content/KeyRing.ts
index 5cebc4d..6484d1e 100644
--- a/src/content/KeyRing.ts
+++ b/src/content/KeyRing.ts
@@ -181,14 +181,17 @@ export default class KeyRing extends KeyFetcher {
keybaseUser: {
name: username,
avatar: (user.pictures.primary || Object.entries(user.basics.pictures)[0] || {})['url'],
+ realName: user.profile.full_name,
+ location: user.profile.location,
proofs: Object.entries(user.proofs_summary.by_presentation_group)
- .reduce((acc: {[name: string]: KeybaseUser}, [k, v]: [string, any]) => {
- acc[k] = {
- type: v.proof_type,
- name: v.nametag,
- state: v.state,
- url: v.human_url
- } as any;
+ .reduce((acc: {[name: string]: Proof[]}, [k, v]: [string, any[]]) => {
+ acc[k] = v.map(p => ({
+ type: p.proof_type,
+ name: p.nametag,
+ state: p.state,
+ url: p.human_url,
+ tag: p.presentation_tag
+ }));
return acc;
}, {})
}
diff --git a/src/content/ScriptInterceptor.ts b/src/content/ScriptInterceptor.ts
index 484fbc4..e607acb 100644
--- a/src/content/ScriptInterceptor.ts
+++ b/src/content/ScriptInterceptor.ts
@@ -62,7 +62,6 @@ export default new class ScriptInterceptor implements EventListenerObject {
try {
this.lock = true;
-
await this.checkPermissionMaybeExecute(script);
} catch (e) {
console.error(`Execution of script (${script.src || "inline"}) failed. ${e.name}: ${e.message}`, e.stack);
@@ -71,7 +70,7 @@ export default new class ScriptInterceptor implements EventListenerObject {
this.lock = false;
clearInterval(monitor);
}
- }, 10);
+ }, 0);
}
private async updateBadgeCount() {
@@ -167,6 +166,11 @@ export default new class ScriptInterceptor implements EventListenerObject {
}
}
}
+
+ window.document.dispatchEvent(new Event("DOMContentLoaded", {
+ bubbles: true,
+ cancelable: true
+ }));
}
/**
diff --git a/src/popup/js/App.tsx b/src/popup/js/App.tsx
index b7a1be5..f73c66c 100644
--- a/src/popup/js/App.tsx
+++ b/src/popup/js/App.tsx
@@ -3,28 +3,16 @@ import { HashRouter } from "react-router-dom";
import { Switch, Route } from "react-router-dom";
import Index from "./pages/Index";
-import { Users } from "./pages/Users";
-
-import AppBar from '@material-ui/core/AppBar';
-import Toolbar from '@material-ui/core/Toolbar';
-import Typography from '@material-ui/core/Typography';
+import User from "./pages/User";
export class App extends React.Component<any, any> {
render() {
return (
<HashRouter>
<div>
- <AppBar position="static">
- <Toolbar variant="dense">
- <Typography variant="h6" color="inherit">
- KPJS
- </Typography>
- </Toolbar>
- </AppBar>
-
<Switch>
<Route exact path="/" component={Index} />
- <Route path="/users" component={Users} />
+ <Route path="/user/:name" component={User} />
</Switch>
</div>
</HashRouter>
diff --git a/src/popup/js/pages/Index.tsx b/src/popup/js/pages/Index.tsx
index 0f1e808..53d51bb 100644
--- a/src/popup/js/pages/Index.tsx
+++ b/src/popup/js/pages/Index.tsx
@@ -16,6 +16,10 @@ import ErrorOutlinedIcon from '@material-ui/icons/ErrorOutlined';
import { KeybaseUser } from '../../../common/KeybaseUser';
import { Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions, Button, withMobileDialog } from '@material-ui/core';
import Slide from '@material-ui/core/Slide';
+import { Redirect } from 'react-router';
+
+import AppBar from '@material-ui/core/AppBar';
+import Toolbar from '@material-ui/core/Toolbar';
function Transition(props: any) {
return <Slide direction="up" {...props} />;
@@ -32,6 +36,7 @@ interface ToolbarState {
needsApproval: string[],
requiresApprovalDialogOpen: boolean,
requiresApprovalDialogUser: string,
+ redirectToProfile: string,
}
const pillTheme = createMuiTheme({
@@ -51,7 +56,8 @@ export default class Index extends React.Component<ToolbarProps, ToolbarState> {
barredUsers: [],
needsApproval: [],
requiresApprovalDialogOpen: false,
- requiresApprovalDialogUser: ''
+ requiresApprovalDialogUser: '',
+ redirectToProfile: '',
};
}
@@ -105,14 +111,14 @@ export default class Index extends React.Component<ToolbarProps, ToolbarState> {
getClickActionForUser = (name: string) => () => {
// TODO: open profile
+ this.setState({
+ redirectToProfile: name
+ });
};
getButtonActionForUser = (name: string) => () => {
if (this.state.trustedUsers.includes(name)) {
this.deny(name);
- } else if (this.state.barredUsers.includes(name)) {
- // TODO: show dialog to confirm action
- this.approve(name);
} else {
this.setState({
requiresApprovalDialogUser: name,
@@ -132,52 +138,66 @@ export default class Index extends React.Component<ToolbarProps, ToolbarState> {
};
render() {
- return <div className="container" style={{minHeight: '11rem'}}>
- <MuiThemeProvider theme={pillTheme}>
- { Object.entries(this.state.keybaseUsers).map(([name, u]) => (
- <Chip
- style={{margin: '1px'}}
- avatar={
- <Avatar src={u.avatar}>
- {!u.avatar ? <FaceIcon /> : ''}
- </Avatar>
- }
- color={
- this.state.barredUsers.includes(name)
- ? 'secondary'
- : (this.state.trustedUsers.includes(name)
- ? 'primary'
- : 'inherit')
- }
- label={name}
- onClick={this.getClickActionForUser(name)}
- onDelete={this.getButtonActionForUser(name)}
- deleteIcon={this.getButtonIconForUser(name)} />
- )) }
- </MuiThemeProvider>
-
- <Dialog
- fullScreen
- open={this.state.requiresApprovalDialogOpen}
- onClose={this.requiresApprovalDialogClose.bind(this, null, null)}
- TransitionComponent={Transition}
- aria-labelledby="alert-dialog-title"
- aria-describedby="alert-dialog-description">
- <DialogTitle id="alert-dialog-title">Allow scripts from {this.state.requiresApprovalDialogUser}?</DialogTitle>
- <DialogContent>
- <DialogContentText id="alert-dialog-description">
- This will allow all scripts signed by this user to run on this website now and in the future.
- </DialogContentText>
- </DialogContent>
- <DialogActions>
- <Button onClick={this.requiresApprovalDialogClose.bind(this, true, this.state.requiresApprovalDialogUser)} color="primary">
- Allow
- </Button>
- <Button onClick={this.requiresApprovalDialogClose.bind(this, false, this.state.requiresApprovalDialogUser)} color="secondary">
- Deny
- </Button>
- </DialogActions>
- </Dialog>
+ if (this.state.redirectToProfile) {
+ return <Redirect to={`/user/${this.state.redirectToProfile}`} />
+ }
+
+ return <div>
+ <AppBar position="static">
+ <Toolbar variant="dense">
+ <Typography variant="h6" color="inherit">
+ KPJS
+ </Typography>
+ </Toolbar>
+ </AppBar>
+
+ <div className="container" style={{minHeight: '11rem'}}>
+ <MuiThemeProvider theme={pillTheme}>
+ { Object.entries(this.state.keybaseUsers).map(([name, u]) => (
+ <Chip
+ style={{margin: '1px'}}
+ avatar={
+ <Avatar src={u.avatar}>
+ {!u.avatar ? <FaceIcon /> : ''}
+ </Avatar>
+ }
+ color={
+ this.state.barredUsers.includes(name)
+ ? 'secondary'
+ : (this.state.trustedUsers.includes(name)
+ ? 'primary'
+ : 'inherit')
+ }
+ label={name}
+ onClick={this.getClickActionForUser(name)}
+ onDelete={this.getButtonActionForUser(name)}
+ deleteIcon={this.getButtonIconForUser(name)} />
+ )) }
+ </MuiThemeProvider>
+
+ <Dialog
+ fullScreen
+ open={this.state.requiresApprovalDialogOpen}
+ onClose={this.requiresApprovalDialogClose.bind(this, null, null)}
+ TransitionComponent={Transition}
+ aria-labelledby="alert-dialog-title"
+ aria-describedby="alert-dialog-description">
+ <DialogTitle id="alert-dialog-title">Allow scripts from {this.state.requiresApprovalDialogUser}?</DialogTitle>
+ <DialogContent>
+ <DialogContentText id="alert-dialog-description">
+ This will allow all scripts signed by this user to run on this website now and in the future.
+ </DialogContentText>
+ </DialogContent>
+ <DialogActions>
+ <Button onClick={this.requiresApprovalDialogClose.bind(this, true, this.state.requiresApprovalDialogUser)} color="primary">
+ Allow
+ </Button>
+ <Button onClick={this.requiresApprovalDialogClose.bind(this, false, this.state.requiresApprovalDialogUser)} color="secondary">
+ Deny
+ </Button>
+ </DialogActions>
+ </Dialog>
+ </div>
</div>;
}
} \ No newline at end of file
diff --git a/src/popup/js/pages/User.tsx b/src/popup/js/pages/User.tsx
new file mode 100644
index 0000000..96b5879
--- /dev/null
+++ b/src/popup/js/pages/User.tsx
@@ -0,0 +1,96 @@
+import * as React from "react";
+import { GetKeybaseUserForDomainEvent, GetKeybaseUserForDomainResponse } from "../../../common/GetKeybaseUserForDomainEvent";
+import { KeybaseUser, Proof } from "../../../common/KeybaseUser";
+
+import Avatar from '@material-ui/core/Avatar';
+import Grid from '@material-ui/core/Grid';
+import { Typography, Link, IconButton } from "@material-ui/core";
+import CircularProgress from '@material-ui/core/CircularProgress';
+
+import AppBar from '@material-ui/core/AppBar';
+import Toolbar from '@material-ui/core/Toolbar';
+import Divider from '@material-ui/core/Divider';
+
+import ArrowBackIcon from '@material-ui/icons/ArrowBack';
+
+interface UserProps {
+ match: { params: { name: string }};
+};
+
+interface UserState {
+ user: KeybaseUser;
+}
+
+export default class User extends React.Component<UserProps, UserState> {
+ constructor(props: any) {
+ super(props);
+ this.state = {
+ user: null
+ };
+ }
+
+ async componentDidMount() {
+ const { match: { params }} = this.props;
+
+ const [ activeTab ] = await browser.tabs.query({ active: true });
+ const domain = new URL(activeTab.url).hostname;
+
+ await browser.tabs.sendMessage(activeTab.id, new GetKeybaseUserForDomainEvent(domain))
+ .then((res: GetKeybaseUserForDomainResponse) => {
+ this.setState({
+ user: res.keybaseUsers[params.name]
+ });
+ });
+ }
+
+ render() {
+ if (this.state.user) {
+ return <div>
+ <AppBar position="static">
+ <Toolbar variant="dense">
+ <IconButton color="inherit" aria-label="Back">
+ <ArrowBackIcon />
+ </IconButton>
+ <Grid container justify="center" alignItems="center">
+ <Typography variant="h6" color="inherit">{this.state.user.name}</Typography>
+ </Grid>
+ </Toolbar>
+ </AppBar>
+
+ <div className="container">
+ <Grid container justify="center" alignItems="center">
+ <Avatar src={this.state.user.avatar} style={{width: 60, height: 60}} />
+ <div style={{marginLeft: 3}}>
+ <Typography variant="subtitle1" style={{lineHeight: 1}}>{this.state.user.realName}</Typography>
+ <Typography variant="caption">{this.state.user.location}</Typography>
+ </div>
+ </Grid>
+
+ <Divider style={{margin: 8}} />
+
+ {Object.entries(this.state.user.proofs).map(([k, v]: [string, Proof[]]) => (
+ <Grid container alignItems="center" style={{margin: 3}}>
+ <img src={`https://keybase.io/images/paramproofs/services/${k.includes('.') ? 'web' : k}/logo_black_16@2x.png`} width="16px" height="16px" />
+ <Typography inline style={{marginLeft: 3}}>{v[0].name}</Typography>
+ {v.map(p => (<Typography inline style={{marginLeft: 3}}><Link href={p.url}>{p.tag}</Link></Typography>))}
+ </Grid>
+ ))}
+ </div>
+ </div>;
+ } else if (this.state.user === null) {
+ return <div>
+ <AppBar position="static">
+ <Toolbar variant="dense">
+ <Typography variant="h6" color="inherit">
+ KPJS
+ </Typography>
+ </Toolbar>
+ </AppBar>
+
+ <CircularProgress />
+ </div>;
+ } else {
+ return <div className="container">Not found!</div>
+ }
+ }
+} \ No newline at end of file
diff --git a/src/popup/js/pages/Users.tsx b/src/popup/js/pages/Users.tsx
deleted file mode 100644
index 08c7bab..0000000
--- a/src/popup/js/pages/Users.tsx
+++ /dev/null
@@ -1,9 +0,0 @@
-import * as React from "react";
-
-export class Users extends React.Component<any, any> {
- render() {
- return <div className="container">
- ayy
- </div>
- }
-}