1 2 #include <petscwebclient.h> 3 4 /* 5 These variables identify the code as a PETSc application to Box. 6 7 See - http://stackoverflow.com/questions/4616553/using-oauth-in-free-open-source-software 8 Users can get their own application IDs - goto https://developers.box.com 9 10 */ 11 #define PETSC_BOX_CLIENT_ID "sse42nygt4zqgrdwi0luv79q1u1f0xza" 12 #define PETSC_BOX_CLIENT_ST "A0Dy4KgOYLB2JIYZqpbze4EzjeIiX5k4" 13 14 #include <mongoose.h> 15 16 static volatile char *result = NULL; 17 18 /*this is the main handler call. It switched based on what uri is in the request*/ 19 static int PetscBoxWebServer_Private(struct mg_connection *conn) 20 { 21 const struct mg_request_info *request_info = mg_get_request_info(conn); 22 printf("Hi %s\n",request_info->uri); 23 printf("Hi %s\n",request_info->query_string); 24 result = (char*) request_info->query_string; 25 return 0; 26 } 27 28 29 static PetscErrorCode PetscBoxStartWebServer_Private(void) 30 { 31 PetscErrorCode ierr; 32 int optionsLen = 5; 33 const char *options[optionsLen]; 34 struct mg_callbacks callbacks; 35 struct mg_context *ctx; 36 37 PetscFunctionBegin; 38 options[0] = "listening_ports"; 39 options[1] = "8081s"; 40 options[2] = "ssl_certificate"; 41 options[3] = "/Users/barrysmith/Src/saws/saws.pem"; 42 options[4] = NULL; 43 44 45 /* Prepare callbacks structure. We have only one callback, the rest are NULL. */ 46 ierr = PetscMemzero(&callbacks, sizeof(callbacks));CHKERRQ(ierr); 47 callbacks.begin_request = PetscBoxWebServer_Private; 48 ctx = mg_start(&callbacks, NULL, options); 49 if (!ctx) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Unable to start up webserver"); 50 while (!result) {}; 51 PetscFunctionReturn(0); 52 } 53 54 #include <ctype.h> 55 56 char to_hex(char code) { 57 static char hex[] = "0123456789abcdef"; 58 return hex[code & 15]; 59 } 60 61 /* Returns a url-encoded version of str */ 62 char *url_encode(char *str) { 63 char *pstr = str, *buf = malloc(strlen(str) * 3 + 1), *pbuf = buf; 64 while (*pstr) { 65 if (isalnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == '~') 66 *pbuf++ = *pstr; 67 else if (*pstr == ' ') 68 *pbuf++ = '+'; 69 else 70 *pbuf++ = '%', *pbuf++ = to_hex(*pstr >> 4), *pbuf++ = to_hex(*pstr & 15); 71 pstr++; 72 } 73 *pbuf = '\0'; 74 return buf; 75 } 76 77 #undef __FUNCT__ 78 #define __FUNCT__ "PetscBoxAuthorize" 79 /*@C 80 PetscBoxAuthorize - Get authorization and refresh token for accessing Box drive from PETSc 81 82 Not collective, only the first process in MPI_Comm does anything 83 84 Input Parameters: 85 + comm - the MPI communicator 86 - tokensize - size of the token arrays 87 88 Output Parameters: 89 + access_token - can be used with PetscBoxUpload() for this one session 90 - refresh_token - can be used for ever to obtain new access_tokens with PetscBoxRefresh(), guard this like a password 91 it gives access to your Box Drive 92 93 Notes: This call requires stdout and stdin access from process 0 on the MPI communicator 94 95 You can run src/sys/webclient/examples/tutorials/obtainrefreshtoken to get a refresh token and then in the future pass it to 96 PETSc programs with -box_refresh_token XXX 97 98 Developer Notes: For some reason I cannot get this to work! Box always replies with Bad Request and no details. Using Curl works 99 if one is fast enough. Perhaps the problem is the need to urlencode the message? 100 101 .seealso: PetscBoxRefresh(), PetscBoxUpload(), PetscURLShorten() 102 103 @*/ 104 PetscErrorCode PetscBoxAuthorize(MPI_Comm comm,char access_token[],char refresh_token[],size_t tokensize) 105 { 106 SSL_CTX *ctx; 107 SSL *ssl; 108 int sock; 109 PetscErrorCode ierr; 110 char buff[8*1024],body[1024],*access,*refresh,*ctmp; 111 PetscMPIInt rank; 112 PetscBool flg; 113 114 PetscFunctionBegin; 115 ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr); 116 if (!rank) { 117 ierr = PetscPrintf(comm,"Cut and paste the following into your browser:\n\n" 118 "https://www.box.com/api/oauth2/authorize?" 119 "response_type=code&" 120 "client_id=" 121 PETSC_BOX_CLIENT_ID 122 "&state=PETScState" 123 "\n\n");CHKERRQ(ierr); 124 ierr = PetscBoxStartWebServer_Private();CHKERRQ(ierr); 125 ierr = PetscStrbeginswith((const char*)result,"state=PETScState&code=",&flg);CHKERRQ(ierr); 126 if (!flg) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Did not get expected string from Box got %s",result); 127 ierr = PetscStrncpy(buff,(const char*)result+22,sizeof(buff));CHKERRQ(ierr); 128 129 ierr = PetscSSLInitializeContext(&ctx);CHKERRQ(ierr); 130 ierr = PetscHTTPSConnect("www.box.com",443,ctx,&sock,&ssl);CHKERRQ(ierr); 131 ierr = PetscStrcpy(body,"code=");CHKERRQ(ierr); 132 ierr = PetscStrcat(body,buff);CHKERRQ(ierr); 133 ierr = PetscStrcat(body,"&client_id=");CHKERRQ(ierr); 134 ierr = PetscStrcat(body,PETSC_BOX_CLIENT_ID);CHKERRQ(ierr); 135 ierr = PetscStrcat(body,"&client_secret=");CHKERRQ(ierr); 136 ierr = PetscStrcat(body,PETSC_BOX_CLIENT_ST);CHKERRQ(ierr); 137 ierr = PetscStrcat(body,"&grant_type=authorization_code");CHKERRQ(ierr); 138 139 ierr = PetscHTTPSRequest("POST","https://www.box.com/api/oauth2/token",NULL,"application/x-www-form-urlencoded",body,ssl,buff,sizeof(buff));CHKERRQ(ierr); 140 ierr = PetscSSLDestroyContext(ctx);CHKERRQ(ierr); 141 close(sock); 142 143 ierr = PetscStrstr(buff,"\"access_token\" : \"",&access);CHKERRQ(ierr); 144 if (!access) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Did not receive access token from Box"); 145 access += 18; 146 ierr = PetscStrchr(access,'\"',&ctmp);CHKERRQ(ierr); 147 if (!ctmp) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Access token from Box is misformed"); 148 *ctmp = 0; 149 ierr = PetscStrncpy(access_token,access,tokensize);CHKERRQ(ierr); 150 *ctmp = '\"'; 151 152 ierr = PetscStrstr(buff,"\"refresh_token\" : \"",&refresh);CHKERRQ(ierr); 153 if (!refresh) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Did not receive refresh token from Box"); 154 refresh += 19; 155 ierr = PetscStrchr(refresh,'\"',&ctmp);CHKERRQ(ierr); 156 if (!ctmp) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Refresh token from Box is misformed"); 157 *ctmp = 0; 158 ierr = PetscStrncpy(refresh_token,refresh,tokensize);CHKERRQ(ierr); 159 160 ierr = PetscPrintf(comm,"Here is your Box refresh token, save it in a save place, in the future you can run PETSc\n");CHKERRQ(ierr); 161 ierr = PetscPrintf(comm,"programs with the option -box_refresh_token %d\n",refresh);CHKERRQ(ierr); 162 ierr = PetscPrintf(comm,"to access Box Drive automatically\n");CHKERRQ(ierr); 163 } 164 PetscFunctionReturn(0); 165 } 166 167 #undef __FUNCT__ 168 #define __FUNCT__ "PetscBoxRefresh" 169 /*@C 170 PetscBoxRefresh - Get a new authorization token for accessing Box drive from PETSc from a refresh token 171 172 Not collective, only the first process in the MPI_Comm does anything 173 174 Input Parameters: 175 + comm - MPI communicator 176 . refresh token - obtained with PetscBoxAuthorize(), if NULL PETSc will first look for one in the options data 177 if not found it will call PetscBoxAuthorize() 178 - tokensize - size of the output string access_token 179 180 Output Parameter: 181 + access_token - token that can be passed to PetscBoxUpload() 182 - new_refresh_token - the old refresh token is no longer valid, not this is different than Google where the same refresh_token is used forever 183 184 Note: This doesn't work I cannot figure out why. 185 186 .seealso: PetscURLShorten(), PetscBoxAuthorize(), PetscBoxUpload() 187 188 @*/ 189 PetscErrorCode PetscBoxRefresh(MPI_Comm comm,const char refresh_token[],char access_token[],char new_refresh_token[],size_t tokensize) 190 { 191 SSL_CTX *ctx; 192 SSL *ssl; 193 int sock; 194 PetscErrorCode ierr; 195 char buff[8*1024],body[1024],*access,*ctmp; 196 PetscMPIInt rank; 197 char *refreshtoken = (char*)refresh_token; 198 199 PetscFunctionBegin; 200 ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr); 201 if (!rank) { 202 if (!refresh_token) { 203 PetscBool set; 204 ierr = PetscMalloc1(512,&refreshtoken);CHKERRQ(ierr); 205 ierr = PetscOptionsGetString(NULL,"-box_refresh_token",refreshtoken,512,&set);CHKERRQ(ierr); 206 if (!set) { 207 ierr = PetscBoxAuthorize(comm,access_token,refreshtoken,512*sizeof(char));CHKERRQ(ierr); 208 ierr = PetscFree(refreshtoken);CHKERRQ(ierr); 209 PetscFunctionReturn(0); 210 } 211 } 212 ierr = PetscSSLInitializeContext(&ctx);CHKERRQ(ierr); 213 ierr = PetscHTTPSConnect("www.box.com",443,ctx,&sock,&ssl);CHKERRQ(ierr); 214 ierr = PetscStrcpy(body,"client_id=");CHKERRQ(ierr); 215 ierr = PetscStrcat(body,PETSC_BOX_CLIENT_ID);CHKERRQ(ierr); 216 ierr = PetscStrcat(body,"&client_secret=");CHKERRQ(ierr); 217 ierr = PetscStrcat(body,PETSC_BOX_CLIENT_ST);CHKERRQ(ierr); 218 ierr = PetscStrcat(body,"&refresh_token=");CHKERRQ(ierr); 219 ierr = PetscStrcat(body,refreshtoken);CHKERRQ(ierr); 220 if (!refresh_token) {ierr = PetscFree(refreshtoken);CHKERRQ(ierr);} 221 ierr = PetscStrcat(body,"&grant_type=refresh_token");CHKERRQ(ierr); 222 223 ierr = PetscHTTPSRequest("POST","https://www.box.com/api/oauth2/token",NULL,"application/x-www-form-urlencoded",body,ssl,buff,sizeof(buff));CHKERRQ(ierr); 224 ierr = PetscSSLDestroyContext(ctx);CHKERRQ(ierr); 225 close(sock); 226 227 ierr = PetscStrstr(buff,"\"access_token\" : \"",&access);CHKERRQ(ierr); 228 if (!access) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Did not receive access token from Box"); 229 access += 18; 230 ierr = PetscStrchr(access,'\"',&ctmp);CHKERRQ(ierr); 231 if (!ctmp) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Access token from Box is misformed"); 232 *ctmp = 0; 233 ierr = PetscStrncpy(access_token,access,tokensize);CHKERRQ(ierr); 234 *ctmp = '\"'; 235 } 236 PetscFunctionReturn(0); 237 } 238 239 #include <sys/stat.h> 240 241 #undef __FUNCT__ 242 #define __FUNCT__ "PetscBoxUpload" 243 /*@C 244 PetscBoxUpload - Loads a file to the Box Drive 245 246 Not collective, only the first process in the MPI_Comm uploads the file 247 248 Input Parameters: 249 + comm - MPI communicator 250 . access_token - obtained with PetscBoxRefresh(), pass NULL to have PETSc generate one 251 - filename - file to upload; if you upload multiple times it will have different names each time on Box Drive 252 253 Options Database: 254 . -box_refresh_token XXX 255 256 Usage Patterns: 257 With PETSc option -box_refresh_token XXX given 258 PetscBoxUpload(comm,NULL,filename); will upload file with no user interaction 259 260 Without PETSc option -box_refresh_token XXX given 261 PetscBoxUpload(comm,NULL,filename); for first use will prompt user to authorize access to Box Drive with their processor 262 263 With PETSc option -box_refresh_token XXX given 264 PetscBoxRefresh(comm,NULL,access_token,sizeof(access_token)); 265 PetscBoxUpload(comm,access_token,filename); 266 267 With refresh token entered in some way by the user 268 PetscBoxRefresh(comm,refresh_token,access_token,sizeof(access_token)); 269 PetscBoxUpload(comm,access_token,filename); 270 271 PetscBoxAuthorize(comm,access_token,refresh_token,sizeof(access_token)); 272 PetscBoxUpload(comm,access_token,filename); 273 274 .seealso: PetscURLShorten(), PetscBoxAuthorize(), PetscBoxRefresh() 275 276 @*/ 277 PetscErrorCode PetscBoxUpload(MPI_Comm comm,const char access_token[],const char filename[]) 278 { 279 SSL_CTX *ctx; 280 SSL *ssl; 281 int sock; 282 PetscErrorCode ierr; 283 char head[1024],buff[8*1024],*body,*title; 284 PetscMPIInt rank; 285 struct stat sb; 286 size_t len,blen,rd; 287 FILE *fd; 288 289 PetscFunctionBegin; 290 ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr); 291 if (!rank) { 292 ierr = PetscStrcpy(head,"Authorization: Bearer ");CHKERRQ(ierr); 293 ierr = PetscStrcat(head,access_token);CHKERRQ(ierr); 294 ierr = PetscStrcat(head,"\r\n");CHKERRQ(ierr); 295 ierr = PetscStrcat(head,"uploadType: multipart\r\n");CHKERRQ(ierr); 296 297 ierr = stat(filename,&sb); 298 if (ierr) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to stat file: %s",filename); 299 len = 1024 + sb.st_size; 300 ierr = PetscMalloc1(len,&body);CHKERRQ(ierr); 301 ierr = PetscStrcpy(body,"--foo_bar_baz\r\n" 302 "Content-Type: application/json\r\n\r\n" 303 "{" 304 "\"title\": \""); 305 ierr = PetscStrcat(body,filename); 306 ierr = PetscStrcat(body,"\"," 307 "\"mimeType\": \"text.html\"," 308 "\"description\": \" a file\"" 309 "}\r\n\r\n" 310 "--foo_bar_baz\r\n" 311 "Content-Type: text/html\r\n\r\n"); 312 ierr = PetscStrlen(body,&blen);CHKERRQ(ierr); 313 fd = fopen (filename, "r"); 314 if (!fd) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to open file: %s",filename); 315 rd = fread (body+blen, sizeof (unsigned char), sb.st_size, fd); 316 if (rd != sb.st_size) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to read entire file: %s %d %d",filename,(int)rd,sb.st_size); 317 fclose(fd); 318 body[blen + rd] = 0; 319 ierr = PetscStrcat(body,"\r\n\r\n" 320 "--foo_bar_baz\r\n"); 321 ierr = PetscSSLInitializeContext(&ctx);CHKERRQ(ierr); 322 ierr = PetscHTTPSConnect("www.boxapis.com",443,ctx,&sock,&ssl);CHKERRQ(ierr); 323 ierr = PetscHTTPSRequest("POST","https://www.boxapis.com/upload/drive/v2/files/",head,"multipart/related; boundary=\"foo_bar_baz\"",body,ssl,buff,sizeof(buff));CHKERRQ(ierr); 324 ierr = PetscFree(body);CHKERRQ(ierr); 325 ierr = PetscSSLDestroyContext(ctx);CHKERRQ(ierr); 326 close(sock); 327 ierr = PetscStrstr(buff,"\"title\"",&title);CHKERRQ(ierr); 328 if (!title) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Upload of file %s failed",filename); 329 } 330 PetscFunctionReturn(0); 331 } 332 333 334