@@ -4,7 +4,9 @@ import { computed, observable, action, autorun, flow, runInAction } from 'mobx';
4
4
import { observer , inject , disposeOnUnmount } from 'mobx-react' ;
5
5
6
6
import { delay } from '../../../util/promise' ;
7
+ import { UnreachableCheck } from '../../../util/error' ;
7
8
import { styled } from '../../../styles' ;
9
+ import { Icon } from '../../../icons' ;
8
10
9
11
import { Interceptor } from '../../../model/interception/interceptors' ;
10
12
import { ProxyStore } from '../../../model/proxy-store' ;
@@ -16,7 +18,6 @@ import { FridaActivationOptions, FridaHost, FridaTarget } from '../../../model/i
16
18
import { getDetailedInterceptorMetadata } from '../../../services/server-api' ;
17
19
18
20
import { TextInput } from '../../common/inputs' ;
19
- import { Icon } from '../../../icons' ;
20
21
import { InterceptionTargetList } from './intercept-target-list' ;
21
22
import { IconButton } from '../../common/icon-button' ;
22
23
@@ -116,6 +117,45 @@ const SearchBox = styled(TextInput)`
116
117
}
117
118
` ;
118
119
120
+ const HostName = styled . p `
121
+ font-weight: bold;
122
+ ` ;
123
+
124
+ const getStateDescriptionText = ( { type, state } : {
125
+ type : FridaHost [ 'type' ] ,
126
+ state : Exclude < FridaHost [ 'state' ] , 'available' >
127
+ } ) => {
128
+ if ( state === 'launch-required' ) return 'Frida launch required' ;
129
+ else if ( state === 'setup-required' ) return 'Frida installation required' ;
130
+ else if ( state === 'unavailable' ) {
131
+ if ( type === 'android' ) {
132
+ return 'Root access not available' ;
133
+ } else {
134
+ return 'Device must be jailbroken and running Frida server' ;
135
+ }
136
+ }
137
+
138
+ throw new UnreachableCheck ( state ) ;
139
+ } ;
140
+
141
+ const StateDescription = styled ( ( { type, state, className } : {
142
+ type : FridaHost [ 'type' ] ,
143
+ state : FridaHost [ 'state' ] ,
144
+ className ?: string
145
+ } ) => {
146
+ if ( state === 'available' ) return null ;
147
+
148
+ return < p className = { className } >
149
+ { getStateDescriptionText ( { type, state } ) }
150
+ </ p > ;
151
+ } ) `
152
+ margin-top: 5px;
153
+ font-style: italic;
154
+
155
+ white-space: normal;
156
+ text-wrap: balance;
157
+ ` ;
158
+
119
159
// We actively hide specific known non-interceptable apps:
120
160
const INCOMPATIBLE_APP_IDS : string [ ] = [
121
161
"com.apple.mobilesafari" ,
@@ -402,7 +442,7 @@ class FridaConfig extends React.Component<{
402
442
403
443
return {
404
444
id,
405
- title : `${ this . deviceClassName } device ${ name } (${ id } ) in state ${ state } ` ,
445
+ title : `${ this . deviceClassName } device ${ name } (${ id } ): ${ _ . startCase ( state ) } ` ,
406
446
icon : id . includes ( "emulator-" )
407
447
? < Icon icon = { [ 'far' , 'window-maximize' ] } />
408
448
: id . match ( / \d + \. \d + \. \d + \. \d + : \d + / )
@@ -415,7 +455,10 @@ class FridaConfig extends React.Component<{
415
455
// Available here means clickable - interceptable/setupable/launchable
416
456
: 'available' ,
417
457
progress : this . hostProgress [ id ] ,
418
- content : < p > { name } < br /> { state } </ p >
458
+ content : < div >
459
+ < HostName > { name } </ HostName >
460
+ < StateDescription type = { host . type } state = { host . state } />
461
+ </ div >
419
462
} ;
420
463
} ) }
421
464
interceptTarget = { this . selectHost }
0 commit comments