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