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