mirror of
https://github.com/yzernik/squeaknode.git
synced 2026-08-16 13:01:04 +02:00
Add rpc method to get private key (#664)
* Add rpc method to get private key * Add export private key to frontend
This commit is contained in:
parent
c624ca2460
commit
4b0f3bc637
11 changed files with 284 additions and 0 deletions
|
|
@ -0,0 +1,124 @@
|
|||
import React, {useState, useEffect} from 'react';
|
||||
import {
|
||||
Paper,
|
||||
IconButton,
|
||||
Menu,
|
||||
MenuItem,
|
||||
Typography,
|
||||
Grid,
|
||||
Box,
|
||||
Link,
|
||||
Dialog,
|
||||
DialogTitle,
|
||||
DialogContent,
|
||||
DialogContentText,
|
||||
TextField,
|
||||
DialogActions,
|
||||
Button,
|
||||
FormControl,
|
||||
InputLabel,
|
||||
Select,
|
||||
} from "@material-ui/core";
|
||||
import { MoreVert as MoreIcon } from "@material-ui/icons";
|
||||
import {useHistory} from "react-router-dom";
|
||||
import classnames from "classnames";
|
||||
|
||||
// styles
|
||||
import useStyles from "./styles";
|
||||
|
||||
import Widget from "../../components/Widget";
|
||||
import SqueakThreadItem from "../../components/SqueakThreadItem";
|
||||
|
||||
import {
|
||||
getSqueakProfilePrivateKey,
|
||||
} from "../../squeakclient/requests"
|
||||
|
||||
|
||||
|
||||
export default function ExportPrivateKeyDialog({
|
||||
open,
|
||||
handleClose,
|
||||
profile,
|
||||
...props
|
||||
}) {
|
||||
var classes = useStyles();
|
||||
const history = useHistory();
|
||||
|
||||
var [privateKey, setPrivateKey] = useState('');
|
||||
|
||||
const resetFields = () => {
|
||||
setPrivateKey('');
|
||||
};
|
||||
|
||||
const handleChangePrivateKey = (event) => {
|
||||
setPrivateKey(event.target.value);
|
||||
};
|
||||
|
||||
const getPrivateKey = () => {
|
||||
var profileId = profile.getProfileId();
|
||||
getSqueakProfilePrivateKey(profileId, (response) => {
|
||||
setPrivateKey(response.getPrivateKey());
|
||||
});
|
||||
};
|
||||
|
||||
function handleSubmit(event) {
|
||||
event.preventDefault();
|
||||
getPrivateKey();
|
||||
}
|
||||
|
||||
function DisplayPrivateKey() {
|
||||
return (
|
||||
<TextField
|
||||
id="standard-textarea"
|
||||
label="private-key"
|
||||
required
|
||||
autoFocus
|
||||
value={privateKey}
|
||||
fullWidth
|
||||
inputProps={{
|
||||
readOnly: true,
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function CancelButton() {
|
||||
return (
|
||||
<Button
|
||||
onClick={handleClose}
|
||||
variant="contained"
|
||||
color="secondary"
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
function ShowPrivateKeyButton() {
|
||||
return (
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
className={classes.button}
|
||||
>
|
||||
Show private key
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog open={open} onEnter={resetFields} onClose={handleClose} aria-labelledby="form-dialog-title">
|
||||
<DialogTitle id="form-dialog-title">Export Private Key</DialogTitle>
|
||||
<form className={classes.root} onSubmit={handleSubmit} noValidate autoComplete="off">
|
||||
<DialogContent>
|
||||
{DisplayPrivateKey()}
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
{CancelButton()}
|
||||
{ShowPrivateKeyButton()}
|
||||
</DialogActions>
|
||||
</form>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"name": "ExportPrivateKeyDialog",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"main": "ExportPrivateKeyDialog.js"
|
||||
}
|
||||
43
frontend/src/components/ExportPrivateKeyDialog/styles.js
Normal file
43
frontend/src/components/ExportPrivateKeyDialog/styles.js
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
import { makeStyles } from "@material-ui/styles";
|
||||
|
||||
export default makeStyles(theme => ({
|
||||
widgetWrapper: {
|
||||
display: "flex",
|
||||
minHeight: "100%",
|
||||
},
|
||||
widgetHeader: {
|
||||
padding: theme.spacing(3),
|
||||
paddingBottom: theme.spacing(1),
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
},
|
||||
widgetRoot: {
|
||||
boxShadow: theme.customShadows.widget,
|
||||
},
|
||||
widgetBody: {
|
||||
paddingBottom: theme.spacing(3),
|
||||
paddingRight: theme.spacing(3),
|
||||
paddingLeft: theme.spacing(3),
|
||||
},
|
||||
noPadding: {
|
||||
padding: 0,
|
||||
},
|
||||
paper: {
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
flexGrow: 1,
|
||||
overflow: "hidden",
|
||||
},
|
||||
moreButton: {
|
||||
margin: -theme.spacing(1),
|
||||
padding: 0,
|
||||
width: 40,
|
||||
height: 40,
|
||||
color: theme.palette.text.hint,
|
||||
"&:hover": {
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
color: "rgba(255, 255, 255, 0.35)",
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
|
@ -19,6 +19,7 @@ import useStyles from "./styles";
|
|||
import PageTitle from "../../components/PageTitle";
|
||||
import Widget from "../../components/Widget";
|
||||
import DeleteProfileDialog from "../../components/DeleteProfileDialog";
|
||||
import ExportPrivateKeyDialog from "../../components/ExportPrivateKeyDialog";
|
||||
|
||||
import {
|
||||
getSqueakProfileRequest,
|
||||
|
|
@ -32,6 +33,7 @@ export default function ProfilePage() {
|
|||
const { id } = useParams();
|
||||
const [squeakProfile, setSqueakProfile] = useState(null);
|
||||
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
||||
const [exportPrivateKeyDialogOpen, setExportPrivateKeyDialogOpen] = useState(false);
|
||||
const history = useHistory();
|
||||
|
||||
const getSqueakProfile = (id) => {
|
||||
|
|
@ -61,10 +63,18 @@ export default function ProfilePage() {
|
|||
setDeleteDialogOpen(true);
|
||||
};
|
||||
|
||||
const handleClickOpenExportPrivateKeyDialog = () => {
|
||||
setExportPrivateKeyDialogOpen(true);
|
||||
};
|
||||
|
||||
const handleCloseDeleteDialog = () => {
|
||||
setDeleteDialogOpen(false);
|
||||
};
|
||||
|
||||
const handleCloseExportPrivateKeyDialog = () => {
|
||||
setExportPrivateKeyDialogOpen(false);
|
||||
};
|
||||
|
||||
const handleSettingsFollowingChange = (event) => {
|
||||
console.log("Following changed for profile id: " + id);
|
||||
console.log("Following changed to: " + event.target.checked);
|
||||
|
|
@ -94,6 +104,9 @@ export default function ProfilePage() {
|
|||
{ProfileSettingsForm()}
|
||||
{ViewSqueaksButton()}
|
||||
{DeleteProfileButton()}
|
||||
{squeakProfile.getHasPrivateKey() &&
|
||||
ExportPrivateKeyButton()
|
||||
}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
@ -133,6 +146,23 @@ export default function ProfilePage() {
|
|||
)
|
||||
}
|
||||
|
||||
function ExportPrivateKeyButton() {
|
||||
return (
|
||||
<>
|
||||
<Grid item xs={12}>
|
||||
<div className={classes.root}>
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
handleClickOpenExportPrivateKeyDialog();
|
||||
}}>Export Private Key
|
||||
</Button>
|
||||
</div>
|
||||
</Grid>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function ViewSqueaksButton() {
|
||||
return (
|
||||
<>
|
||||
|
|
@ -162,6 +192,18 @@ export default function ProfilePage() {
|
|||
)
|
||||
}
|
||||
|
||||
function ExportPrivateKeyDialogContent() {
|
||||
return (
|
||||
<>
|
||||
<ExportPrivateKeyDialog
|
||||
open={exportPrivateKeyDialogOpen}
|
||||
handleClose={handleCloseExportPrivateKeyDialog}
|
||||
profile={squeakProfile}
|
||||
></ExportPrivateKeyDialog>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<PageTitle title={'Squeak Profile: ' + (squeakProfile ? squeakProfile.getProfileName() : null)} />
|
||||
|
|
@ -172,6 +214,7 @@ export default function ProfilePage() {
|
|||
}
|
||||
</div>
|
||||
{DeleteProfileDialogContent()}
|
||||
{ExportPrivateKeyDialogContent()}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,6 +86,8 @@ import {
|
|||
GetReceivedPaymentsReply,
|
||||
GetNetworkRequest,
|
||||
GetNetworkReply,
|
||||
GetSqueakProfilePrivateKeyRequest,
|
||||
GetSqueakProfilePrivateKeyReply,
|
||||
} from "../proto/squeak_admin_pb"
|
||||
|
||||
console.log('The value of REACT_APP_SERVER_PORT is:', process.env.REACT_APP_SERVER_PORT);
|
||||
|
|
@ -1007,3 +1009,14 @@ export function getNetworkRequest(handleResponse) {
|
|||
}
|
||||
);
|
||||
};
|
||||
|
||||
export function getSqueakProfilePrivateKey(id, handleResponse) {
|
||||
var request = new GetSqueakProfilePrivateKeyRequest();
|
||||
request.setProfileId(id);
|
||||
makeRequest(
|
||||
'getsqueakprofileprivatekey',
|
||||
request,
|
||||
GetSqueakProfilePrivateKeyReply.deserializeBinary,
|
||||
handleResponse,
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -500,6 +500,18 @@ def test_delete_profile(server_stub, admin_stub, contact_profile_id):
|
|||
assert "Profile not found." in str(excinfo.value)
|
||||
|
||||
|
||||
def test_get_profile_private_key(server_stub, admin_stub, signing_profile_id):
|
||||
# Get the private key
|
||||
private_key_response = admin_stub.GetSqueakProfilePrivateKey(
|
||||
squeak_admin_pb2.GetSqueakProfilePrivateKeyRequest(
|
||||
profile_id=signing_profile_id,
|
||||
)
|
||||
)
|
||||
|
||||
print(private_key_response.private_key)
|
||||
assert len(private_key_response.private_key) > 0
|
||||
|
||||
|
||||
def test_get_following_squeaks(
|
||||
server_stub, admin_stub, saved_squeak_hash, signing_profile_id
|
||||
):
|
||||
|
|
|
|||
|
|
@ -100,6 +100,10 @@ service SqueakAdmin {
|
|||
*/
|
||||
rpc SetSqueakProfileSharing (SetSqueakProfileSharingRequest) returns (SetSqueakProfileSharingReply) {}
|
||||
|
||||
/** sqkadmin: `getsqueakprofileprivatekey`
|
||||
*/
|
||||
rpc GetSqueakProfilePrivateKey (GetSqueakProfilePrivateKeyRequest) returns (GetSqueakProfilePrivateKeyReply) {}
|
||||
|
||||
/** sqkadmin: `deletesqueakprofile`
|
||||
*/
|
||||
rpc DeleteSqueakProfile (DeleteSqueakProfileRequest) returns (DeleteSqueakProfileReply) {}
|
||||
|
|
@ -293,6 +297,16 @@ message SetSqueakProfileSharingRequest {
|
|||
message SetSqueakProfileSharingReply {
|
||||
}
|
||||
|
||||
message GetSqueakProfilePrivateKeyRequest {
|
||||
/// The profile id
|
||||
int32 profile_id = 1;
|
||||
}
|
||||
|
||||
message GetSqueakProfilePrivateKeyReply {
|
||||
/// The private key
|
||||
string private_key = 1;
|
||||
}
|
||||
|
||||
message DeleteSqueakProfileRequest {
|
||||
/// The profile id
|
||||
int32 profile_id = 1;
|
||||
|
|
|
|||
|
|
@ -190,6 +190,16 @@ class SqueakAdminServerHandler(object):
|
|||
self.squeak_controller.delete_squeak_profile(profile_id)
|
||||
return squeak_admin_pb2.DeleteSqueakProfileReply()
|
||||
|
||||
def handle_get_squeak_profile_private_key(self, request):
|
||||
profile_id = request.profile_id
|
||||
logger.info(
|
||||
"Handle get squeak profile private key for id: {}".format(profile_id))
|
||||
private_key = self.squeak_controller.get_squeak_profile_private_key(
|
||||
profile_id)
|
||||
return squeak_admin_pb2.GetSqueakProfilePrivateKeyReply(
|
||||
private_key=private_key
|
||||
)
|
||||
|
||||
def handle_make_squeak(self, request):
|
||||
profile_id = request.profile_id
|
||||
content_str = request.content
|
||||
|
|
|
|||
|
|
@ -91,6 +91,9 @@ class SqueakAdminServerServicer(squeak_admin_pb2_grpc.SqueakAdminServicer):
|
|||
def DeleteSqueakProfile(self, request, context):
|
||||
return self.handler.handle_delete_squeak_profile(request)
|
||||
|
||||
def GetSqueakProfilePrivateKey(self, request, context):
|
||||
return self.handler.handle_get_squeak_profile_private_key(request)
|
||||
|
||||
def MakeSqueak(self, request, context):
|
||||
return self.handler.handle_make_squeak(request)
|
||||
|
||||
|
|
|
|||
|
|
@ -433,6 +433,14 @@ def create_app(handler, username, password):
|
|||
handler.handle_get_network,
|
||||
)
|
||||
|
||||
@app.route("/getsqueakprofileprivatekey", methods=["POST"])
|
||||
@login_required
|
||||
def getsqueakprofileprivatekey():
|
||||
return handle_request(
|
||||
squeak_admin_pb2.GetSqueakProfilePrivateKeyRequest(),
|
||||
handler.handle_get_squeak_profile_private_key,
|
||||
)
|
||||
|
||||
return app
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -154,6 +154,14 @@ class SqueakController:
|
|||
def delete_squeak_profile(self, profile_id: int):
|
||||
self.squeak_db.delete_profile(profile_id)
|
||||
|
||||
def get_squeak_profile_private_key(self, profile_id: int):
|
||||
profile = self.get_squeak_profile(profile_id)
|
||||
if profile.private_key is None:
|
||||
raise Exception("Profile with id: {} does not have a private key.".format(
|
||||
profile_id
|
||||
))
|
||||
return profile.private_key
|
||||
|
||||
def make_squeak(self, profile_id: int, content_str: str, replyto_hash: bytes):
|
||||
squeak_profile = self.squeak_db.get_profile(profile_id)
|
||||
squeak_entry = self.squeak_core.make_squeak(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue