summaryrefslogtreecommitdiff
path: root/VKPC/HostsHack.m
blob: 89f07524827e8079d6ab50e7be51b38cde1029bb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
//
//  HostsHack.m
//  VKPC
//
//  Created by Eugene on 10/30/14.
//  Copyright (c) 2014 Eugene Z. All rights reserved.
//

#import "HostsHack.h"
#import "HostsHackWindowController.h"
#import "AppDelegate.h"

#include <stdio.h>

#ifdef DEBUG
#include <time.h>
#endif

NSString * const VKPCHostsHackTaskFinished = @"VKPCHostsHackTaskFinished";

static BOOL hackFound = NO;
static HostsHackWindowController *windowController = nil;
#ifdef DEBUG
static char *testPath = "/tmp/vkpc_test";
#endif

@implementation HostsHack

static NSString *readLineASNSString(FILE *file) {
    char *line = NULL;
    size_t len = 0;
    getline(&line, &len, file);
    return [NSString stringWithUTF8String:line];
}

+ (void)check {
    hackFound = NO;
    
#ifdef DEBUG
    clock_t begin = clock();
#endif
    
    FILE *file = fopen(VKPCHostsFile, "r");
    if (file == NULL) {
        NSLog(@"[HostsHack check] !file, returning");
        return;
    }
    
    while (!feof(file)) {
        NSString *line = readLineASNSString(file);
//        NSLog(@"[hostshack] line: %@", line);
        NSRange rng = [line rangeOfString:[NSString stringWithUTF8String:VKPCWSClientHost]];
        if (rng.location != NSNotFound) {
//        if ([line containsString:[NSString stringWithUTF8String:VKPCWSClientHost]]) {
            line = [line stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
            if ([line hasPrefix:@"127.0.0.1"]) {
                hackFound = YES;
                break;
            }
        }
    }
    fclose(file);
    
#ifdef DEBUG
    NSLog(@"[HostsHack check] file reading time: %lf", (double)(clock() - begin) / CLOCKS_PER_SEC);
    NSLog(@"[HostsHack check] found: %s", hackFound ? "YES" : "NO");
#endif
}

static void showAlert(NSString *text, NSString *informativeText) {
    NSAlert *alert = [[NSAlert alloc] init];
    [alert setMessageText:text];
    [alert setInformativeText:informativeText];
    [alert setAlertStyle:NSWarningAlertStyle];
    [alert runModal];
}

+ (void)hack {
//    return;
    
    AuthorizationRef auth = NULL;
    OSStatus err;
    
    err = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagInteractionAllowed, &auth);
    if (err != errAuthorizationSuccess) {
        showAlert(@"VKPC Error", [NSString stringWithFormat:@"Failed to obtain authorization. Code = %d", err]);
        [windowController setButtonRetry];
        return;
    }
    
    const char *path = [[NSProcessInfo processInfo].arguments[0] UTF8String];
    char * const args[] = {"--hostshack", NULL};
    
    [windowController setButtonWait];
    
    err = AuthorizationExecuteWithPrivileges(auth, path, kAuthorizationFlagDefaults, args, NULL);
    if (err != errAuthorizationSuccess) {
        showAlert(@"VKPC Error", [NSString stringWithFormat:@"Failed to run command with adminstrative privileges. Code = %d", err]);
        [windowController setButtonRetry];
        return;
    }
    
    [[NSDistributedNotificationCenter defaultCenter] addObserver:(id)[self class]
                                                        selector:@selector(hackTaskFinished:)
                                                            name:VKPCHostsHackTaskFinished
                                                          object:nil];
}

+ (void)hackTaskFinished:(id)notification {
    [[NSDistributedNotificationCenter defaultCenter] removeObserver:(id)[self class]];
    
    [self check];
    
    if (hackFound) {
        [windowController close];
        [[AppDelegate shared] continueRunning];
    } else {
        [self showUnableAlert];
    }
}

+ (void)showUnableAlert {
    showAlert(@"VKPC Error", [NSString stringWithFormat:
                                         @"Unfortunately, VKPC failed to automatically edit the file %@. Now you have to make it manually.\n\n"
                                         "Please open the file %@ with root privileges and add following line at the end:\n\n"
                                         "127.0.0.1\t%@\n\n"
                                         "Then save the file and relaunch the app.",
                                         [NSString stringWithUTF8String:VKPCHostsFile],
                                         [NSString stringWithUTF8String:VKPCHostsFile],
                                         [NSString stringWithUTF8String:VKPCWSClientHost]]);
}

+ (int)doHack {
//    sleep(2);
    
    char *path = VKPCHostsFile;
    FILE *file = fopen(path, "a");
    if (!file) {
        NSLog(@"[HostsHack doHack] error opening file %s, returning error", path);
        return -1;
    }
    
    fputs("\n#VK Player Controller", file);
    fputs([[NSString stringWithFormat:@"\n127.0.0.1\t%@", [NSString stringWithUTF8String:VKPCWSClientHost]] UTF8String], file);
    
    fclose(file);
    return 0;
}

+ (BOOL)found {
    return hackFound;
}

+ (void)showWindow {
    if (!windowController) {
        windowController = [[HostsHackWindowController alloc] initWithWindowNibName:@"HostsHackWindow"];
    }
    [windowController showWindow:nil];
    [windowController.window makeKeyAndOrderFront:nil];
    [windowController.window setLevel:kCGFloatingWindowLevel];
}

@end