7272import java .util .Map ;
7373import java .util .Properties ;
7474import java .util .Queue ;
75+ import java .util .concurrent .ConcurrentHashMap ;
7576import java .util .concurrent .ConcurrentLinkedQueue ;
7677import java .util .concurrent .ExecutorService ;
7778import java .util .concurrent .Executors ;
@@ -103,6 +104,7 @@ public class MainActivity extends NativeActivity {
103104 private final ExecutorService _audioExecutor = Executors .newSingleThreadExecutor ();
104105 private final Queue <Sound > _sounds = new ConcurrentLinkedQueue <>();
105106 private final Handler _keypadHandler = new Handler (Looper .getMainLooper ());
107+ private final Map <String , Boolean > permittedHost = new ConcurrentHashMap <>();
106108 private String [] _options = null ;
107109 private MediaPlayer _mediaPlayer = null ;
108110 private LocationAdapter _locationAdapter = null ;
@@ -149,13 +151,13 @@ public int ask(final byte[] titleBytes, final byte[] promptBytes, final boolean
149151 public void run () {
150152 AlertDialog .Builder builder = new AlertDialog .Builder (activity );
151153 builder .setTitle (title ).setMessage (prompt );
152- builder .setPositiveButton ("Yes" , new DialogInterface .OnClickListener () {
154+ builder .setPositiveButton (R . string . YES , new DialogInterface .OnClickListener () {
153155 public void onClick (DialogInterface dialog , int which ) {
154156 result .setYes ();
155157 mutex .release ();
156158 }
157159 });
158- builder .setNegativeButton ("No" , new DialogInterface .OnClickListener () {
160+ builder .setNegativeButton (R . string . NO , new DialogInterface .OnClickListener () {
159161 public void onClick (DialogInterface dialog , int which ) {
160162 result .setNo ();
161163 mutex .release ();
@@ -169,7 +171,7 @@ public void onCancel(DialogInterface dialog) {
169171 }
170172 });
171173 if (cancel ) {
172- builder .setNeutralButton ("Cancel" , new DialogInterface .OnClickListener () {
174+ builder .setNeutralButton (R . string . CANCEL , new DialogInterface .OnClickListener () {
173175 public void onClick (DialogInterface dialog , int which ) {
174176 result .setCancel ();
175177 mutex .release ();
@@ -501,8 +503,7 @@ public void setClipboardText(final byte[] textBytes) {
501503 final String text = new String (textBytes , CP1252 );
502504 runOnUiThread (new Runnable () {
503505 public void run () {
504- ClipboardManager clipboard =
505- (ClipboardManager ) getSystemService (Context .CLIPBOARD_SERVICE );
506+ ClipboardManager clipboard = (ClipboardManager ) getSystemService (Context .CLIPBOARD_SERVICE );
506507 if (clipboard != null ) {
507508 ClipData clip = ClipData .newPlainText ("text" , text );
508509 clipboard .setPrimaryClip (clip );
@@ -577,8 +578,9 @@ public void showAlert(final byte[] titleBytes, final byte[] messageBytes) {
577578 runOnUiThread (new Runnable () {
578579 public void run () {
579580 new AlertDialog .Builder (activity )
580- .setTitle (title ).setMessage (message )
581- .setPositiveButton ("OK" , new DialogInterface .OnClickListener () {
581+ .setTitle (title )
582+ .setMessage (message )
583+ .setPositiveButton (R .string .OK , new DialogInterface .OnClickListener () {
582584 public void onClick (DialogInterface dialog , int which ) {}
583585 }).show ();
584586 }
@@ -771,6 +773,14 @@ private void installSamples() {
771773 }
772774 }
773775
776+ private boolean isHostDenied (String remoteHost ) {
777+ return (remoteHost != null && permittedHost .get (remoteHost ) != null && Boolean .FALSE .equals (permittedHost .get (remoteHost )));
778+ }
779+
780+ private boolean isHostNotPermitted (String remoteHost ) {
781+ return (remoteHost == null || permittedHost .get (remoteHost ) == null || !Boolean .TRUE .equals (permittedHost .get (remoteHost )));
782+ }
783+
774784 private boolean locationPermitted () {
775785 String permission = Manifest .permission .ACCESS_FINE_LOCATION ;
776786 return (ContextCompat .checkSelfPermission (this , permission ) == PackageManager .PERMISSION_GRANTED );
@@ -797,11 +807,11 @@ private void processSettings() {
797807 is = getApplication ().openFileInput ("settings.txt" );
798808 Properties p = new Properties ();
799809 p .load (is );
800- int socket = Integer .parseInt (p .getProperty ("serverSocket" , "-1" ));
810+ int port = Integer .parseInt (p .getProperty ("serverSocket" , "-1" ));
801811 String token = p .getProperty ("serverToken" , new Date ().toString ());
802- if (socket > 1023 && socket < 65536 ) {
812+ if (port > 1023 && port < 65536 ) {
803813 WebServer webServer = new WebServerImpl ();
804- webServer .run (socket , token );
814+ webServer .run (port , token );
805815 } else {
806816 Log .i (TAG , "Web service disabled" );
807817 }
@@ -848,6 +858,27 @@ private String readLine(InputStream inputReader) throws IOException {
848858 return b == -1 ? null : out .size () == 0 ? "" : out .toString ();
849859 }
850860
861+ private void requestHostPermission (String remoteHost ) {
862+ final Activity activity = this ;
863+ runOnUiThread (new Runnable () {
864+ public void run () {
865+ new AlertDialog .Builder (activity )
866+ .setTitle (R .string .PORTAL_PROMPT )
867+ .setMessage (getString (R .string .PORTAL_QUESTION , remoteHost ))
868+ .setPositiveButton (R .string .OK , new DialogInterface .OnClickListener () {
869+ public void onClick (DialogInterface dialog , int which ) {
870+ permittedHost .put (remoteHost , Boolean .TRUE );
871+ }
872+ })
873+ .setNegativeButton (R .string .CANCEL , new DialogInterface .OnClickListener () {
874+ public void onClick (DialogInterface dialog , int which ) {
875+ permittedHost .put (remoteHost , Boolean .FALSE );
876+ }
877+ }).show ();
878+ }
879+ });
880+ }
881+
851882 private String saveSchemeData (final String buffer ) throws IOException {
852883 File outputFile = new File (_storage .getInternal (), SCHEME_BAS );
853884 BufferedWriter output = new BufferedWriter (new FileWriter (outputFile ));
@@ -863,6 +894,12 @@ private void setupStorageEnvironment() {
863894 setenv ("LEGACY_DIR" , _storage .getMedia ());
864895 }
865896
897+ private void validateAccess (String remoteHost ) throws IOException {
898+ if (isHostNotPermitted (remoteHost )) {
899+ throw new IOException (getString (R .string .PORTAL_DENIED ));
900+ }
901+ }
902+
866903 private static class BasFileFilter implements FilenameFilter {
867904 @ Override
868905 public boolean accept (File dir , String name ) {
@@ -944,7 +981,8 @@ protected byte[] decodeBase64(String data) {
944981 }
945982
946983 @ Override
947- protected void deleteFile (String fileName ) throws IOException {
984+ protected void deleteFile (String remoteHost , String fileName ) throws IOException {
985+ validateAccess (remoteHost );
948986 if (fileName == null ) {
949987 throw new IOException ("Empty file name" );
950988 }
@@ -958,19 +996,30 @@ protected void deleteFile(String fileName) throws IOException {
958996 }
959997
960998 @ Override
961- protected void execStream (InputStream inputStream ) throws IOException {
962- MainActivity .this .execStream (inputStream );
999+ protected void execStream (String remoteHost , InputStream inputStream ) throws IOException {
1000+ if (isHostDenied (remoteHost )) {
1001+ throw new IOException (getString (R .string .PORTAL_DENIED ));
1002+ }
1003+ if (isHostNotPermitted (remoteHost )) {
1004+ requestHostPermission (remoteHost );
1005+ } else {
1006+ MainActivity .this .execStream (inputStream );
1007+ }
9631008 }
9641009
9651010 @ Override
966- protected Response getFile (String path , boolean asset ) throws IOException {
1011+ protected Response getFile (String remoteHost , String path , boolean asset ) throws IOException {
9671012 Response result ;
9681013 if (asset ) {
9691014 String name = "webui/" + path ;
9701015 long length = getFileLength (name );
9711016 log ("Opened " + name + " " + length + " bytes" );
9721017 result = new Response (getAssets ().open (name ), length );
1018+ if ("index.html" .equals (path ) && isHostNotPermitted (remoteHost )) {
1019+ requestHostPermission (remoteHost );
1020+ }
9731021 } else {
1022+ validateAccess (remoteHost );
9741023 File file = getFile (path );
9751024 if (file != null ) {
9761025 result = new Response (new FileInputStream (file ), file .length ());
@@ -982,7 +1031,8 @@ protected Response getFile(String path, boolean asset) throws IOException {
9821031 }
9831032
9841033 @ Override
985- protected Collection <FileData > getFileData () throws IOException {
1034+ protected Collection <FileData > getFileData (String remoteHost ) throws IOException {
1035+ validateAccess (remoteHost );
9861036 Collection <FileData > result = new ArrayList <>();
9871037 result .addAll (getFiles (new File (_storage .getExternal ())));
9881038 result .addAll (getFiles (new File (_storage .getMedia ())));
@@ -1001,7 +1051,8 @@ protected void log(String message) {
10011051 }
10021052
10031053 @ Override
1004- protected void renameFile (String from , String to ) throws IOException {
1054+ protected void renameFile (String remoteHost , String from , String to ) throws IOException {
1055+ validateAccess (remoteHost );
10051056 if (to == null ) {
10061057 throw new IOException ("Empty file name" );
10071058 }
@@ -1019,7 +1070,8 @@ protected void renameFile(String from, String to) throws IOException {
10191070 }
10201071
10211072 @ Override
1022- protected void saveFile (String fileName , byte [] content ) throws IOException {
1073+ protected void saveFile (String remoteHost , String fileName , byte [] content ) throws IOException {
1074+ validateAccess (remoteHost );
10231075 File file = new File (_storage .getExternal (), fileName );
10241076 if (file .exists ()) {
10251077 throw new IOException ("File already exists: " + fileName );
0 commit comments