Skip to content

Commit c0f0b30

Browse files
authored
Merge pull request #345 from lightninglabs/read-only-session
Add support for read-only macaroons
2 parents 46e9424 + 5cb7ded commit c0f0b30

File tree

8 files changed

+109
-12
lines changed

8 files changed

+109
-12
lines changed

app/src/components/common/FormSelect.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ interface Props {
5858
extra?: ReactNode;
5959
placeholder?: string;
6060
onChange?: (value: string) => void;
61+
className?: string;
6162
}
6263

6364
const FormSelect: React.FC<Props> = ({
@@ -66,17 +67,17 @@ const FormSelect: React.FC<Props> = ({
6667
value,
6768
placeholder,
6869
onChange,
70+
className,
6971
}) => {
7072
const { Wrapper, Select } = Styled;
7173
return (
72-
<Wrapper>
74+
<Wrapper className={className}>
7375
<Select
7476
value={value}
7577
onChange={v => onChange && onChange(v as string)}
7678
placeholder={placeholder}
7779
aria-label={label}
7880
options={options}
79-
dropdownClassName="asdf"
8081
/>
8182
</Wrapper>
8283
);

app/src/components/connect/AddSession.tsx

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@ import React, { useCallback, useState } from 'react';
22
import { observer } from 'mobx-react-lite';
33
import styled from '@emotion/styled';
44
import { usePrefixedTranslation } from 'hooks';
5+
import * as LIT from 'types/generated/lit-sessions_pb';
56
import { MAX_DATE } from 'util/constants';
67
import { useStore } from 'store';
78
import { Button, Column, HeaderFour, Row } from 'components/base';
89
import FormField from 'components/common/FormField';
910
import FormInput from 'components/common/FormInput';
11+
import FormSelect from 'components/common/FormSelect';
1012
import PurpleButton from './PurpleButton';
1113

1214
const Styled = {
@@ -21,6 +23,17 @@ const Styled = {
2123
padding: 12px 16px;
2224
}
2325
`,
26+
FormSelect: styled(FormSelect)`
27+
.rc-select {
28+
font-family: ${props => props.theme.fonts.open.regular};
29+
font-size: ${props => props.theme.sizes.m};
30+
padding: 12px 40px 8px 0px;
31+
}
32+
33+
.rc-select-selection-item {
34+
padding-left: 14px;
35+
}
36+
`,
2437
};
2538

2639
interface Props {
@@ -32,18 +45,25 @@ const AddSession: React.FC<Props> = ({ primary }) => {
3245
const { sessionStore } = useStore();
3346

3447
const [label, setLabel] = useState('');
48+
const [permissions, setPermissions] = useState('admin');
3549
const [editing, setEditing] = useState(false);
3650

3751
const toggleEditing = useCallback(() => setEditing(e => !e), []);
3852
const handleSubmit = useCallback(async () => {
39-
const session = await sessionStore.addSession(label, MAX_DATE);
53+
const sessionType =
54+
permissions === 'admin'
55+
? LIT.SessionType.TYPE_MACAROON_ADMIN
56+
: LIT.SessionType.TYPE_MACAROON_READONLY;
57+
58+
const session = await sessionStore.addSession(label, sessionType, MAX_DATE);
59+
4060
if (session) {
4161
setLabel('');
4262
setEditing(false);
4363
}
44-
}, [label]);
64+
}, [label, permissions]);
4565

46-
const { Wrapper, FormHeader, FormInput } = Styled;
66+
const { Wrapper, FormHeader, FormInput, FormSelect } = Styled;
4767
if (!editing) {
4868
return (
4969
<PurpleButton tertiary={!primary} onClick={toggleEditing}>
@@ -54,13 +74,32 @@ const AddSession: React.FC<Props> = ({ primary }) => {
5474

5575
return (
5676
<Wrapper>
57-
<FormHeader>{l('label')}</FormHeader>
77+
<Row>
78+
<Column>
79+
<FormHeader>{l('label')}</FormHeader>
80+
</Column>
81+
<Column>
82+
<FormHeader>{l('permissions')}</FormHeader>
83+
</Column>
84+
</Row>
5885
<Row>
5986
<Column cols={6}>
6087
<FormField>
6188
<FormInput value={label} onChange={setLabel} placeholder={l('labelHint')} />
6289
</FormField>
6390
</Column>
91+
<Column>
92+
<FormField>
93+
<FormSelect
94+
value={permissions}
95+
onChange={setPermissions}
96+
options={[
97+
{ label: 'Admin', value: 'admin' },
98+
{ label: 'Read Only', value: 'read-only' },
99+
]}
100+
/>
101+
</FormField>
102+
</Column>
64103
<Column>
65104
<PurpleButton onClick={handleSubmit}>{l('common.submit')}</PurpleButton>
66105
<Button ghost borderless onClick={toggleEditing}>

app/src/components/layout/Layout.tsx

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React from 'react';
22
import { observer } from 'mobx-react-lite';
3+
import { Global, Theme } from '@emotion/react';
34
import styled from '@emotion/styled';
45
import { useStore } from 'store';
56
import { Background, Menu } from 'components/base';
@@ -10,6 +11,47 @@ interface CollapsedProps {
1011
fullWidth?: boolean;
1112
}
1213

14+
const GlobalStyles = (theme: Theme) => `
15+
.rc-select-dropdown {
16+
padding-top: 10px;
17+
background-color: transparent;
18+
19+
& > div {
20+
color: ${theme.colors.offWhite};
21+
background-color: ${theme.colors.lightBlue};
22+
border-width: 0;
23+
border-radius: 8px;
24+
box-shadow: 0px 16px 16px rgba(0, 0, 0, 0.15);
25+
overflow: hidden;
26+
}
27+
}
28+
29+
.rc-select-item {
30+
color: ${theme.colors.white};
31+
font-family: ${theme.fonts.open.regular};
32+
font-weight: 600;
33+
font-size: ${theme.sizes.s};
34+
line-height: 24px;
35+
padding: 16px;
36+
border-bottom: 1px solid ${theme.colors.paleBlue};
37+
38+
&:last-of-type {
39+
border-bottom: none;
40+
}
41+
42+
&:hover {
43+
color: ${theme.colors.white};
44+
background-color: ${theme.colors.blue};
45+
cursor: pointer;
46+
}
47+
48+
& > .rc-select-item-option-state {
49+
top: 16px;
50+
right: 12px;
51+
}
52+
}
53+
`;
54+
1355
const Styled = {
1456
Container: styled.div<{ fullWidth: boolean }>`
1557
position: relative;
@@ -86,6 +128,7 @@ export const Layout: React.FC = ({ children }) => {
86128
<Fluid className="container-fluid">{children}</Fluid>
87129
</Content>
88130
</Container>
131+
<Global styles={GlobalStyles} />
89132
</Background>
90133
);
91134
};

app/src/components/theme.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ const theme: Theme = {
4242
purple: '#57038d',
4343
overlay: 'rgba(245,245,245,0.04)',
4444
gradient: 'linear-gradient(325.53deg, #252F4A 0%, #46547B 100%);',
45+
lightBlue: '#384770',
46+
paleBlue: '#2E3A5C',
4547
},
4648
};
4749

app/src/emotion-theme.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ declare module '@emotion/react' {
3838
purple: string;
3939
overlay: string;
4040
gradient: string;
41+
lightBlue: string;
42+
paleBlue: string;
4143
};
4244
}
4345
}

app/src/i18n/locales/en-US.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
"cmps.common.Wizard.backTip": "Back to Previous",
3434
"cmps.connect.AddSession.create": "Create a new session",
3535
"cmps.connect.AddSession.label": "Label",
36+
"cmps.connect.AddSession.permissions": "Permissions",
3637
"cmps.connect.AddSession.labelHint": "My First Session",
3738
"cmps.connect.AddSession.expiration": "Expiration",
3839
"cmps.connect.AddSession.expirationSuffix": "",

app/src/store/models/session.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,11 @@ export default class Session {
5151
get typeLabel() {
5252
switch (this.type) {
5353
case LIT.SessionType.TYPE_MACAROON_READONLY:
54-
return 'Readonly Macaroon';
54+
return 'Read-Only';
5555
case LIT.SessionType.TYPE_MACAROON_ADMIN:
56-
return 'Admin Macaroon';
56+
return 'Admin';
5757
case LIT.SessionType.TYPE_MACAROON_CUSTOM:
58-
return 'Custom Macaroon';
58+
return 'Custom';
5959
case LIT.SessionType.TYPE_UI_PASSWORD:
6060
return 'LiT UI Password';
6161
}

app/src/store/stores/sessionStore.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,11 @@ export default class SessionStore {
8383
s.label.startsWith('Default Session'),
8484
).length;
8585
const countText = count === 0 ? '' : `(${count})`;
86-
await this.addSession(`Default Session ${countText}`, MAX_DATE);
86+
await this.addSession(
87+
`Default Session ${countText}`,
88+
LIT.SessionType.TYPE_MACAROON_ADMIN,
89+
MAX_DATE,
90+
);
8791
}
8892
} catch (error: any) {
8993
this._store.appView.handleError(error, 'Unable to fetch sessions');
@@ -93,11 +97,16 @@ export default class SessionStore {
9397
/**
9498
* Adds a new session
9599
* @param label the user defined label for this session
100+
* @param type the type of session being created (admin, read-only, etc)
96101
* @param expiry how long the session should be valid for
97102
* @param mailboxServerAddr the address where the mailbox server is reachable
98103
* @param devServer whether the mailbox server is a dev server that has no valid TLS cert
99104
*/
100-
async addSession(label: string, expiry: Date) {
105+
async addSession(
106+
label: string,
107+
type: LIT.SessionTypeMap[keyof LIT.SessionTypeMap],
108+
expiry: Date,
109+
) {
101110
try {
102111
this._store.log.info(`submitting session with label ${label}`, {
103112
expiry,
@@ -107,7 +116,7 @@ export default class SessionStore {
107116

108117
const { session } = await this._store.api.lit.addSession(
109118
label,
110-
LIT.SessionType.TYPE_UI_PASSWORD,
119+
type,
111120
expiry,
112121
this.proxyServer,
113122
!IS_PROD,

0 commit comments

Comments
 (0)