add-user-scripts.v5.patch 356 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824
  1. From: uazo <uazo@users.noreply.github.com>
  2. Date: Mon, 28 Dec 2020 12:29:56 +0000
  3. Subject: Experimental user scripts support preview
  4. ---
  5. chrome/android/BUILD.gn | 2 +
  6. .../browser/download/DownloadUtils.java | 6 +
  7. .../chrome/browser/settings/MainSettings.java | 7 +
  8. .../browser/settings/SettingsActivity.java | 10 +-
  9. chrome/android/java_sources.gni | 3 +
  10. chrome/android/proguard/main.flags | 7 +
  11. chrome/browser/BUILD.gn | 5 +
  12. chrome/browser/about_flags.cc | 9 +
  13. chrome/browser/flag_descriptions.cc | 10 +
  14. chrome/browser/flag_descriptions.h | 5 +
  15. chrome/browser/prefs/browser_prefs.cc | 2 +
  16. ...hrome_browser_main_extra_parts_profiles.cc | 4 +
  17. chrome/browser/profiles/profile_manager.cc | 9 +
  18. chrome/renderer/BUILD.gn | 1 +
  19. .../chrome_content_renderer_client.cc | 32 +
  20. .../browser_ui/settings/SettingsUtils.java | 44 +
  21. components/components_strings.grd | 1 +
  22. components/user_scripts/android/BUILD.gn | 83 ++
  23. .../java/res/drawable-hdpi/userscript_off.png | Bin 0 -> 161 bytes
  24. .../java/res/drawable-hdpi/userscript_on.png | Bin 0 -> 168 bytes
  25. .../java/res/layout/accept_script_item.xml | 65 ++
  26. .../java/res/layout/accept_script_list.xml | 10 +
  27. .../java/res/layout/scripts_preference.xml | 40 +
  28. .../android/java/res/values/dimens.xml | 11 +
  29. .../main_preferences_addon_userscripts.xml | 29 +
  30. .../java/res/xml/userscripts_preferences.xml | 40 +
  31. .../user_scripts/UserScriptsUtils.java | 49 ++
  32. .../user_scripts/FragmentWindowAndroid.java | 68 ++
  33. .../components/user_scripts/ScriptInfo.java | 31 +
  34. .../user_scripts/ScriptListBaseAdapter.java | 186 ++++
  35. .../user_scripts/ScriptListPreference.java | 151 ++++
  36. .../user_scripts/UserScriptsBridge.java | 145 ++++
  37. .../user_scripts/UserScriptsPreferences.java | 141 +++
  38. .../user_scripts/android/java_sources.gni | 18 +
  39. .../android/user_scripts_bridge.cc | 178 ++++
  40. .../android/user_scripts_bridge.h | 31 +
  41. components/user_scripts/browser/BUILD.gn | 68 ++
  42. .../user_scripts/browser/file_task_runner.cc | 40 +
  43. .../user_scripts/browser/file_task_runner.h | 34 +
  44. .../browser/user_script_loader.cc | 650 ++++++++++++++
  45. .../user_scripts/browser/user_script_loader.h | 173 ++++
  46. .../browser/user_script_pref_info.cc | 34 +
  47. .../browser/user_script_pref_info.h | 58 ++
  48. .../user_scripts/browser/user_script_prefs.cc | 241 ++++++
  49. .../user_scripts/browser/user_script_prefs.h | 55 ++
  50. .../browser/userscripts_browser_client.cc | 79 ++
  51. .../browser/userscripts_browser_client.h | 62 ++
  52. components/user_scripts/common/BUILD.gn | 52 ++
  53. components/user_scripts/common/constants.h | 21 +
  54. components/user_scripts/common/error_utils.cc | 54 ++
  55. components/user_scripts/common/error_utils.h | 25 +
  56. .../common/extension_message_generator.cc | 29 +
  57. .../common/extension_message_generator.h | 11 +
  58. .../user_scripts/common/extension_messages.cc | 40 +
  59. .../user_scripts/common/extension_messages.h | 70 ++
  60. components/user_scripts/common/host_id.cc | 31 +
  61. components/user_scripts/common/host_id.h | 35 +
  62. .../user_scripts/common/script_constants.h | 33 +
  63. components/user_scripts/common/url_pattern.cc | 807 ++++++++++++++++++
  64. components/user_scripts/common/url_pattern.h | 301 +++++++
  65. .../user_scripts/common/url_pattern_set.cc | 330 +++++++
  66. .../user_scripts/common/url_pattern_set.h | 161 ++++
  67. components/user_scripts/common/user_script.cc | 351 ++++++++
  68. components/user_scripts/common/user_script.h | 371 ++++++++
  69. .../common/user_scripts_features.cc | 34 +
  70. .../common/user_scripts_features.h | 35 +
  71. components/user_scripts/common/view_type.cc | 39 +
  72. components/user_scripts/common/view_type.h | 48 ++
  73. components/user_scripts/renderer/BUILD.gn | 67 ++
  74. .../renderer/extension_frame_helper.cc | 96 +++
  75. .../renderer/extension_frame_helper.h | 92 ++
  76. .../user_scripts/renderer/injection_host.cc | 12 +
  77. .../user_scripts/renderer/injection_host.h | 42 +
  78. .../renderer/resources/greasemonkey_api.js | 82 ++
  79. .../user_scripts_renderer_resources.grd | 14 +
  80. .../user_scripts/renderer/script_context.cc | 213 +++++
  81. .../user_scripts/renderer/script_context.h | 70 ++
  82. .../user_scripts/renderer/script_injection.cc | 350 ++++++++
  83. .../user_scripts/renderer/script_injection.h | 160 ++++
  84. .../renderer/script_injection_callback.cc | 26 +
  85. .../renderer/script_injection_callback.h | 38 +
  86. .../renderer/script_injection_manager.cc | 407 +++++++++
  87. .../renderer/script_injection_manager.h | 102 +++
  88. .../user_scripts/renderer/script_injector.h | 96 +++
  89. .../user_scripts/renderer/scripts_run_info.cc | 31 +
  90. .../user_scripts/renderer/scripts_run_info.h | 70 ++
  91. .../renderer/user_script_injector.cc | 229 +++++
  92. .../renderer/user_script_injector.h | 86 ++
  93. .../user_scripts/renderer/user_script_set.cc | 260 ++++++
  94. .../user_scripts/renderer/user_script_set.h | 102 +++
  95. .../renderer/user_script_set_manager.cc | 77 ++
  96. .../renderer/user_script_set_manager.h | 62 ++
  97. .../renderer/user_scripts_dispatcher.cc | 36 +
  98. .../renderer/user_scripts_dispatcher.h | 48 ++
  99. .../renderer/user_scripts_renderer_client.cc | 76 ++
  100. .../renderer/user_scripts_renderer_client.h | 33 +
  101. .../renderer/web_ui_injection_host.cc | 40 +
  102. .../renderer/web_ui_injection_host.h | 28 +
  103. .../strings/userscripts_strings.grdp | 50 ++
  104. tools/gritsettings/resource_ids.spec | 3 +
  105. .../chromium/ui/base/SelectFileDialog.java | 3 +-
  106. 101 files changed, 8902 insertions(+), 4 deletions(-)
  107. create mode 100755 components/user_scripts/android/BUILD.gn
  108. create mode 100755 components/user_scripts/android/java/res/drawable-hdpi/userscript_off.png
  109. create mode 100755 components/user_scripts/android/java/res/drawable-hdpi/userscript_on.png
  110. create mode 100644 components/user_scripts/android/java/res/layout/accept_script_item.xml
  111. create mode 100644 components/user_scripts/android/java/res/layout/accept_script_list.xml
  112. create mode 100644 components/user_scripts/android/java/res/layout/scripts_preference.xml
  113. create mode 100755 components/user_scripts/android/java/res/values/dimens.xml
  114. create mode 100755 components/user_scripts/android/java/res/xml/main_preferences_addon_userscripts.xml
  115. create mode 100644 components/user_scripts/android/java/res/xml/userscripts_preferences.xml
  116. create mode 100755 components/user_scripts/android/java/src/org/chromium/chrome/browser/user_scripts/UserScriptsUtils.java
  117. create mode 100644 components/user_scripts/android/java/src/org/chromium/components/user_scripts/FragmentWindowAndroid.java
  118. create mode 100644 components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptInfo.java
  119. create mode 100644 components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptListBaseAdapter.java
  120. create mode 100644 components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptListPreference.java
  121. create mode 100644 components/user_scripts/android/java/src/org/chromium/components/user_scripts/UserScriptsBridge.java
  122. create mode 100755 components/user_scripts/android/java/src/org/chromium/components/user_scripts/UserScriptsPreferences.java
  123. create mode 100644 components/user_scripts/android/java_sources.gni
  124. create mode 100644 components/user_scripts/android/user_scripts_bridge.cc
  125. create mode 100644 components/user_scripts/android/user_scripts_bridge.h
  126. create mode 100755 components/user_scripts/browser/BUILD.gn
  127. create mode 100755 components/user_scripts/browser/file_task_runner.cc
  128. create mode 100755 components/user_scripts/browser/file_task_runner.h
  129. create mode 100755 components/user_scripts/browser/user_script_loader.cc
  130. create mode 100755 components/user_scripts/browser/user_script_loader.h
  131. create mode 100644 components/user_scripts/browser/user_script_pref_info.cc
  132. create mode 100644 components/user_scripts/browser/user_script_pref_info.h
  133. create mode 100644 components/user_scripts/browser/user_script_prefs.cc
  134. create mode 100644 components/user_scripts/browser/user_script_prefs.h
  135. create mode 100755 components/user_scripts/browser/userscripts_browser_client.cc
  136. create mode 100755 components/user_scripts/browser/userscripts_browser_client.h
  137. create mode 100755 components/user_scripts/common/BUILD.gn
  138. create mode 100755 components/user_scripts/common/constants.h
  139. create mode 100755 components/user_scripts/common/error_utils.cc
  140. create mode 100755 components/user_scripts/common/error_utils.h
  141. create mode 100755 components/user_scripts/common/extension_message_generator.cc
  142. create mode 100755 components/user_scripts/common/extension_message_generator.h
  143. create mode 100755 components/user_scripts/common/extension_messages.cc
  144. create mode 100755 components/user_scripts/common/extension_messages.h
  145. create mode 100755 components/user_scripts/common/host_id.cc
  146. create mode 100755 components/user_scripts/common/host_id.h
  147. create mode 100755 components/user_scripts/common/script_constants.h
  148. create mode 100755 components/user_scripts/common/url_pattern.cc
  149. create mode 100755 components/user_scripts/common/url_pattern.h
  150. create mode 100755 components/user_scripts/common/url_pattern_set.cc
  151. create mode 100755 components/user_scripts/common/url_pattern_set.h
  152. create mode 100755 components/user_scripts/common/user_script.cc
  153. create mode 100755 components/user_scripts/common/user_script.h
  154. create mode 100644 components/user_scripts/common/user_scripts_features.cc
  155. create mode 100644 components/user_scripts/common/user_scripts_features.h
  156. create mode 100755 components/user_scripts/common/view_type.cc
  157. create mode 100755 components/user_scripts/common/view_type.h
  158. create mode 100755 components/user_scripts/renderer/BUILD.gn
  159. create mode 100755 components/user_scripts/renderer/extension_frame_helper.cc
  160. create mode 100755 components/user_scripts/renderer/extension_frame_helper.h
  161. create mode 100755 components/user_scripts/renderer/injection_host.cc
  162. create mode 100755 components/user_scripts/renderer/injection_host.h
  163. create mode 100755 components/user_scripts/renderer/resources/greasemonkey_api.js
  164. create mode 100755 components/user_scripts/renderer/resources/user_scripts_renderer_resources.grd
  165. create mode 100755 components/user_scripts/renderer/script_context.cc
  166. create mode 100755 components/user_scripts/renderer/script_context.h
  167. create mode 100755 components/user_scripts/renderer/script_injection.cc
  168. create mode 100755 components/user_scripts/renderer/script_injection.h
  169. create mode 100755 components/user_scripts/renderer/script_injection_callback.cc
  170. create mode 100755 components/user_scripts/renderer/script_injection_callback.h
  171. create mode 100755 components/user_scripts/renderer/script_injection_manager.cc
  172. create mode 100755 components/user_scripts/renderer/script_injection_manager.h
  173. create mode 100755 components/user_scripts/renderer/script_injector.h
  174. create mode 100755 components/user_scripts/renderer/scripts_run_info.cc
  175. create mode 100755 components/user_scripts/renderer/scripts_run_info.h
  176. create mode 100755 components/user_scripts/renderer/user_script_injector.cc
  177. create mode 100755 components/user_scripts/renderer/user_script_injector.h
  178. create mode 100755 components/user_scripts/renderer/user_script_set.cc
  179. create mode 100755 components/user_scripts/renderer/user_script_set.h
  180. create mode 100755 components/user_scripts/renderer/user_script_set_manager.cc
  181. create mode 100755 components/user_scripts/renderer/user_script_set_manager.h
  182. create mode 100755 components/user_scripts/renderer/user_scripts_dispatcher.cc
  183. create mode 100755 components/user_scripts/renderer/user_scripts_dispatcher.h
  184. create mode 100755 components/user_scripts/renderer/user_scripts_renderer_client.cc
  185. create mode 100755 components/user_scripts/renderer/user_scripts_renderer_client.h
  186. create mode 100755 components/user_scripts/renderer/web_ui_injection_host.cc
  187. create mode 100755 components/user_scripts/renderer/web_ui_injection_host.h
  188. create mode 100755 components/user_scripts/strings/userscripts_strings.grdp
  189. diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
  190. --- a/chrome/android/BUILD.gn
  191. +++ b/chrome/android/BUILD.gn
  192. @@ -226,6 +226,7 @@ android_resources("chrome_app_java_resources") {
  193. "//components/strings:components_locale_settings_grd",
  194. "//components/strings:components_strings_grd",
  195. "//components/translate/content/android:java_resources",
  196. + "//components/user_scripts/android:java_resources",
  197. "//content/public/android:content_java_resources",
  198. "//third_party/android_data_chart:android_data_chart_java_resources",
  199. "//third_party/android_deps:android_support_v7_appcompat_java",
  200. @@ -443,6 +444,7 @@ android_library("chrome_java") {
  201. "//components/translate/content/android:translate_android_enums_java",
  202. "//components/url_formatter/android:url_formatter_java",
  203. "//components/user_prefs/android:java",
  204. + "//components/user_scripts/android:java",
  205. "//components/variations/android:variations_java",
  206. "//components/version_info/android:version_constants_java",
  207. "//components/viz/common:common_java",
  208. diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
  209. --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
  210. +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
  211. @@ -61,6 +61,7 @@ import org.chromium.content_public.browser.BrowserStartupController;
  212. import org.chromium.content_public.browser.LoadUrlParams;
  213. import org.chromium.ui.base.DeviceFormFactor;
  214. import org.chromium.ui.widget.Toast;
  215. +import org.chromium.chrome.browser.user_scripts.UserScriptsUtils;
  216. import java.io.File;
  217. @@ -364,6 +365,11 @@ public class DownloadUtils {
  218. Context context = ContextUtils.getApplicationContext();
  219. DownloadManagerService service = DownloadManagerService.getDownloadManagerService();
  220. + if (UserScriptsUtils.openFile(filePath, mimeType, downloadGuid,
  221. + isOffTheRecord, originalUrl, referrer)) {
  222. + return true;
  223. + }
  224. +
  225. // Check if Chrome should open the file itself.
  226. if (service.isDownloadOpenableInBrowser(isOffTheRecord, mimeType)) {
  227. // Share URIs use the content:// scheme when able, which looks bad when displayed
  228. diff --git a/chrome/android/java/src/org/chromium/chrome/browser/settings/MainSettings.java b/chrome/android/java/src/org/chromium/chrome/browser/settings/MainSettings.java
  229. --- a/chrome/android/java/src/org/chromium/chrome/browser/settings/MainSettings.java
  230. +++ b/chrome/android/java/src/org/chromium/chrome/browser/settings/MainSettings.java
  231. @@ -143,6 +143,8 @@ public class MainSettings extends PreferenceFragmentCompat
  232. findPreference(PREF_PRIVACY).setTitle(R.string.prefs_privacy_security);
  233. }
  234. + createBromitePreferences();
  235. +
  236. cachePreferences();
  237. updatePasswordsPreference();
  238. @@ -303,4 +305,9 @@ public class MainSettings extends PreferenceFragmentCompat
  239. }
  240. };
  241. }
  242. +
  243. + private void createBromitePreferences() {
  244. + SettingsUtils.inflatePrefsAddon(this, "main_preferences_addon_",
  245. + R.xml.class.getFields());
  246. + }
  247. }
  248. diff --git a/chrome/android/java/src/org/chromium/chrome/browser/settings/SettingsActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/settings/SettingsActivity.java
  249. --- a/chrome/android/java/src/org/chromium/chrome/browser/settings/SettingsActivity.java
  250. +++ b/chrome/android/java/src/org/chromium/chrome/browser/settings/SettingsActivity.java
  251. @@ -256,9 +256,13 @@ public class SettingsActivity extends ChromeBaseAppCompatActivity
  252. finish();
  253. return true;
  254. } else if (item.getItemId() == R.id.menu_id_general_help) {
  255. - HelpAndFeedbackLauncherImpl.getInstance().show(this,
  256. - getString(R.string.help_context_settings), Profile.getLastUsedRegularProfile(),
  257. - null);
  258. + if (mainFragment instanceof SettingsUtils.ISupportHelpAndFeedback) {
  259. + ((SettingsUtils.ISupportHelpAndFeedback)mainFragment).onHelpAndFeebackPressed();
  260. + } else {
  261. + HelpAndFeedbackLauncherImpl.getInstance().show(this,
  262. + getString(R.string.help_context_settings), Profile.getLastUsedRegularProfile(),
  263. + null);
  264. + }
  265. return true;
  266. }
  267. return super.onOptionsItemSelected(item);
  268. diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
  269. --- a/chrome/android/java_sources.gni
  270. +++ b/chrome/android/java_sources.gni
  271. @@ -18,6 +18,7 @@ import("//chrome/common/features.gni")
  272. import("//components/feed/features.gni")
  273. import("//components/offline_pages/buildflags/features.gni")
  274. import("//device/vr/buildflags/buildflags.gni")
  275. +import("//components/user_scripts/android/java_sources.gni")
  276. chrome_java_sources += public_autofill_assistant_java_sources
  277. @@ -49,3 +50,5 @@ if (enable_arcore) {
  278. "java/src/org/chromium/chrome/browser/vr/ArImmersiveOverlay.java",
  279. ]
  280. }
  281. +
  282. +chrome_java_sources += userscripts_java_sources
  283. diff --git a/chrome/android/proguard/main.flags b/chrome/android/proguard/main.flags
  284. --- a/chrome/android/proguard/main.flags
  285. +++ b/chrome/android/proguard/main.flags
  286. @@ -57,3 +57,10 @@
  287. public <clinit>();
  288. *** build() return null;
  289. }
  290. +
  291. +# Keep fields name for all R.xml
  292. +# used in SettingsUtils.java
  293. +# components/browser_ui/settings/android/java/src/org/chromium/components/browser_ui/settings
  294. +-keepclassmembers class **.R$xml* {
  295. + public static <fields>;
  296. +}
  297. diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
  298. --- a/chrome/browser/BUILD.gn
  299. +++ b/chrome/browser/BUILD.gn
  300. @@ -3238,6 +3238,11 @@ static_library("browser") {
  301. ]
  302. deps += [ "//chrome/android/modules/dev_ui/provider:native" ]
  303. }
  304. + deps += [
  305. + "//components/user_scripts/common",
  306. + "//components/user_scripts/browser",
  307. + "//components/user_scripts/android",
  308. + ]
  309. } else { #!is_android
  310. sources += [
  311. "accessibility/caption_controller.cc",
  312. diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
  313. --- a/chrome/browser/about_flags.cc
  314. +++ b/chrome/browser/about_flags.cc
  315. @@ -131,6 +131,7 @@
  316. #include "components/translate/core/browser/translate_ranker_impl.h"
  317. #include "components/translate/core/common/translate_util.h"
  318. #include "components/ui_devtools/switches.h"
  319. +#include "components/user_scripts/common/user_scripts_features.h"
  320. #include "components/version_info/version_info.h"
  321. #include "components/viz/common/features.h"
  322. #include "components/viz/common/switches.h"
  323. @@ -6257,6 +6258,14 @@ const FeatureEntry kFeatureEntries[] = {
  324. FEATURE_VALUE_TYPE(features::kUserDataSnapshot)},
  325. #endif
  326. + {"enable-user-scripts", flag_descriptions::kEnableUserScriptsName,
  327. + flag_descriptions::kEnableUserScriptsDescription, kOsDesktop | kOsAndroid,
  328. + FEATURE_VALUE_TYPE(user_scripts::features::kEnableUserScripts)},
  329. +
  330. + {"enable-user-scripts-log", flag_descriptions::kEnableLoggingUserScriptsName,
  331. + flag_descriptions::kEnableLoggingUserScriptsDescription, kOsDesktop | kOsAndroid,
  332. + FEATURE_VALUE_TYPE(user_scripts::features::kEnableLoggingUserScripts)},
  333. +
  334. #if defined(OS_WIN)
  335. {"run-video-capture-service-in-browser",
  336. flag_descriptions::kRunVideoCaptureServiceInBrowserProcessName,
  337. diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
  338. --- a/chrome/browser/flag_descriptions.cc
  339. +++ b/chrome/browser/flag_descriptions.cc
  340. @@ -4687,6 +4687,16 @@ const char kUserDataSnapshotDescription[] =
  341. "update and restoring them after a version rollback.";
  342. #endif // !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
  343. +const char kEnableUserScriptsName[] = "Enable user scripts";
  344. +const char kEnableUserScriptsDescription[] =
  345. + "Enables experimental support on user scripts. "
  346. + "Please report back any bug.";
  347. +
  348. +const char kEnableLoggingUserScriptsName[] = "Enable logging user scripts component";
  349. +const char kEnableLoggingUserScriptsDescription[] =
  350. + "Enables logging for troubleshooting feature. "
  351. + "Please report back any bug.";
  352. +
  353. #if defined(OS_WIN) || defined(OS_CHROMEOS)
  354. const char kWebShareName[] = "Web Share";
  355. const char kWebShareDescription[] =
  356. diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
  357. --- a/chrome/browser/flag_descriptions.h
  358. +++ b/chrome/browser/flag_descriptions.h
  359. @@ -2735,6 +2735,11 @@ extern const char kUserDataSnapshotName[];
  360. extern const char kUserDataSnapshotDescription[];
  361. #endif // !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
  362. +extern const char kEnableUserScriptsName[];
  363. +extern const char kEnableUserScriptsDescription[];
  364. +extern const char kEnableLoggingUserScriptsName[];
  365. +extern const char kEnableLoggingUserScriptsDescription[];
  366. +
  367. #if defined(OS_WIN) || defined(OS_CHROMEOS)
  368. extern const char kWebShareName[];
  369. extern const char kWebShareDescription[];
  370. diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
  371. --- a/chrome/browser/prefs/browser_prefs.cc
  372. +++ b/chrome/browser/prefs/browser_prefs.cc
  373. @@ -228,6 +228,7 @@
  374. #include "components/permissions/contexts/geolocation_permission_context_android.h"
  375. #include "components/query_tiles/tile_service_prefs.h"
  376. #include "components/feed/core/common/pref_names.h"
  377. +#include "components/user_scripts/browser/user_script_prefs.h"
  378. #else // defined(OS_ANDROID)
  379. #include "chrome/browser/accessibility/caption_controller.h"
  380. #include "chrome/browser/enterprise/reporting/prefs.h"
  381. @@ -810,6 +811,7 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry,
  382. translate::TranslatePrefs::RegisterProfilePrefs(registry);
  383. omnibox::RegisterProfilePrefs(registry);
  384. ZeroSuggestProvider::RegisterProfilePrefs(registry);
  385. + user_scripts::UserScriptsPrefs::RegisterProfilePrefs(registry);
  386. #if BUILDFLAG(ENABLE_EXTENSIONS)
  387. ExtensionWebUI::RegisterProfilePrefs(registry);
  388. diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
  389. --- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
  390. +++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
  391. @@ -179,6 +179,8 @@
  392. #include "chrome/browser/nearby_sharing/nearby_sharing_service_factory.h"
  393. #endif
  394. +#include "components/user_scripts/browser/userscripts_browser_client.h"
  395. +
  396. namespace chrome {
  397. void AddProfilesExtraParts(ChromeBrowserMainParts* main_parts) {
  398. @@ -403,6 +405,8 @@ void ChromeBrowserMainExtraPartsProfiles::
  399. #endif
  400. WebDataServiceFactory::GetInstance();
  401. webrtc_event_logging::WebRtcEventLogManagerKeyedServiceFactory::GetInstance();
  402. +
  403. + user_scripts::UserScriptsBrowserClient::GetInstance();
  404. }
  405. void ChromeBrowserMainExtraPartsProfiles::PreProfileInit() {
  406. diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc
  407. --- a/chrome/browser/profiles/profile_manager.cc
  408. +++ b/chrome/browser/profiles/profile_manager.cc
  409. @@ -109,6 +109,8 @@
  410. #include "extensions/common/manifest.h"
  411. #endif
  412. +#include "components/user_scripts/browser/userscripts_browser_client.h"
  413. +
  414. #if BUILDFLAG(ENABLE_SESSION_SERVICE)
  415. #include "chrome/browser/sessions/session_service_factory.h"
  416. #endif
  417. @@ -1287,6 +1289,13 @@ void ProfileManager::DoFinalInitForServices(Profile* profile,
  418. }
  419. #endif
  420. +
  421. + user_scripts::UserScriptsBrowserClient* userscript_client =
  422. + user_scripts::UserScriptsBrowserClient::GetInstance();
  423. + if(userscript_client) {
  424. + userscript_client->SetProfile(profile);
  425. + }
  426. +
  427. #if BUILDFLAG(ENABLE_SUPERVISED_USERS)
  428. // Initialization needs to happen after extension system initialization (for
  429. // extension::ManagementPolicy) and InitProfileUserPrefs (for setting the
  430. diff --git a/chrome/renderer/BUILD.gn b/chrome/renderer/BUILD.gn
  431. --- a/chrome/renderer/BUILD.gn
  432. +++ b/chrome/renderer/BUILD.gn
  433. @@ -154,6 +154,7 @@ static_library("renderer") {
  434. "//components/contextual_search/content:renderer",
  435. "//components/data_reduction_proxy/core/common",
  436. "//components/dom_distiller/content/renderer",
  437. + "//components/user_scripts/renderer",
  438. "//components/network_hints/renderer",
  439. "//components/omnibox/common",
  440. "//components/page_image_annotation/content/renderer",
  441. diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc
  442. --- a/chrome/renderer/chrome_content_renderer_client.cc
  443. +++ b/chrome/renderer/chrome_content_renderer_client.cc
  444. @@ -166,6 +166,7 @@
  445. #if defined(OS_ANDROID)
  446. #include "chrome/renderer/sandbox_status_extension_android.h"
  447. +#include "components/user_scripts/renderer/user_scripts_renderer_client.h"
  448. #else
  449. #include "chrome/renderer/media/chrome_speech_recognition_client.h"
  450. #include "chrome/renderer/searchbox/search_bouncer.h"
  451. @@ -363,6 +364,12 @@ void ChromeContentRendererClient::RenderThreadStarted() {
  452. ChromeExtensionsRendererClient::GetInstance()->RenderThreadStarted();
  453. #endif
  454. + user_scripts::UserScriptsRendererClient* userscript_client =
  455. + user_scripts::UserScriptsRendererClient::GetInstance();
  456. + if(userscript_client) {
  457. + userscript_client->RenderThreadStarted();
  458. + }
  459. +
  460. #if BUILDFLAG(ENABLE_SPELLCHECK)
  461. if (!spellcheck_)
  462. InitSpellCheck();
  463. @@ -502,6 +509,13 @@ void ChromeContentRendererClient::RenderFrameCreated(
  464. render_frame, registry);
  465. #endif
  466. + user_scripts::UserScriptsRendererClient* userscript_client =
  467. + user_scripts::UserScriptsRendererClient::GetInstance();
  468. + if(userscript_client) {
  469. + userscript_client->RenderFrameCreated(
  470. + render_frame, registry);
  471. + }
  472. +
  473. #if BUILDFLAG(ENABLE_PLUGINS)
  474. new PepperHelper(render_frame);
  475. #endif
  476. @@ -1455,6 +1469,12 @@ void ChromeContentRendererClient::RunScriptsAtDocumentStart(
  477. render_frame);
  478. // |render_frame| might be dead by now.
  479. #endif
  480. + user_scripts::UserScriptsRendererClient* userscript_client =
  481. + user_scripts::UserScriptsRendererClient::GetInstance();
  482. + if(userscript_client) {
  483. + userscript_client->RunScriptsAtDocumentStart(
  484. + render_frame);
  485. + }
  486. }
  487. void ChromeContentRendererClient::RunScriptsAtDocumentEnd(
  488. @@ -1464,6 +1484,12 @@ void ChromeContentRendererClient::RunScriptsAtDocumentEnd(
  489. render_frame);
  490. // |render_frame| might be dead by now.
  491. #endif
  492. + user_scripts::UserScriptsRendererClient* userscript_client =
  493. + user_scripts::UserScriptsRendererClient::GetInstance();
  494. + if(userscript_client) {
  495. + userscript_client->RunScriptsAtDocumentEnd(
  496. + render_frame);
  497. + }
  498. }
  499. void ChromeContentRendererClient::RunScriptsAtDocumentIdle(
  500. @@ -1473,6 +1499,12 @@ void ChromeContentRendererClient::RunScriptsAtDocumentIdle(
  501. render_frame);
  502. // |render_frame| might be dead by now.
  503. #endif
  504. + user_scripts::UserScriptsRendererClient* userscript_client =
  505. + user_scripts::UserScriptsRendererClient::GetInstance();
  506. + if(userscript_client) {
  507. + userscript_client->RunScriptsAtDocumentIdle(
  508. + render_frame);
  509. + }
  510. }
  511. void ChromeContentRendererClient::
  512. diff --git a/components/browser_ui/settings/android/java/src/org/chromium/components/browser_ui/settings/SettingsUtils.java b/components/browser_ui/settings/android/java/src/org/chromium/components/browser_ui/settings/SettingsUtils.java
  513. --- a/components/browser_ui/settings/android/java/src/org/chromium/components/browser_ui/settings/SettingsUtils.java
  514. +++ b/components/browser_ui/settings/android/java/src/org/chromium/components/browser_ui/settings/SettingsUtils.java
  515. @@ -23,6 +23,12 @@ import androidx.preference.PreferenceFragmentCompat;
  516. import org.chromium.base.ApiCompatibilityUtils;
  517. +import org.chromium.base.Log;
  518. +import androidx.preference.PreferenceScreen;
  519. +import androidx.preference.PreferenceManager;
  520. +import android.content.res.Resources;
  521. +import java.lang.reflect.Field;
  522. +
  523. /**
  524. * A helper class for Settings.
  525. */
  526. @@ -118,4 +124,42 @@ public class SettingsUtils {
  527. ImageView imageButton = (ImageView) button;
  528. return imageButton.getDrawable() == parentMenu.getOverflowIcon();
  529. }
  530. +
  531. + public static PreferenceScreen inflatePrefsAddon(PreferenceFragmentCompat preferenceFragment,
  532. + String name,
  533. + Field[] fields) {
  534. + Resources resources = preferenceFragment.getResources();
  535. +
  536. + for(int count=0; count < fields.length; count++) {
  537. + String assetName = fields[count].getName();
  538. + //Log.i("found ", assetName);
  539. + if (assetName.startsWith(name)) {
  540. + //int resId = resources.getIdentifier(assetName, "xml", packageName);
  541. + try {
  542. + int resId = fields[count].getInt(null);
  543. + //Log.i("inflating ", Integer.toString(resId));
  544. + return SettingsUtils.inflatePreferencesFromResource(preferenceFragment, resId);
  545. + } catch (IllegalAccessException e) {}
  546. + }
  547. + }
  548. + return null;
  549. + }
  550. +
  551. + public static PreferenceScreen inflatePreferencesFromResource(
  552. + PreferenceFragmentCompat preferenceFragment, @XmlRes int preferencesResId) {
  553. + StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
  554. + try {
  555. + PreferenceManager preferenceManager = preferenceFragment.getPreferenceManager();
  556. + final PreferenceScreen xmlRoot = preferenceManager.inflateFromResource(
  557. + preferenceFragment.getContext(),
  558. + preferencesResId, preferenceFragment.getPreferenceScreen());
  559. + return xmlRoot;
  560. + } finally {
  561. + StrictMode.setThreadPolicy(oldPolicy);
  562. + }
  563. + }
  564. +
  565. + public interface ISupportHelpAndFeedback {
  566. + void onHelpAndFeebackPressed();
  567. + }
  568. }
  569. diff --git a/components/components_strings.grd b/components/components_strings.grd
  570. --- a/components/components_strings.grd
  571. +++ b/components/components_strings.grd
  572. @@ -319,6 +319,7 @@
  573. <part file="tab_groups_strings.grdp" />
  574. <part file="undo_strings.grdp" />
  575. <part file="version_ui_strings.grdp" />
  576. + <part file="user_scripts/strings/userscripts_strings.grdp" />
  577. <if expr="not is_android and not is_ios">
  578. <part file="management_strings.grdp" />
  579. diff --git a/components/user_scripts/android/BUILD.gn b/components/user_scripts/android/BUILD.gn
  580. new file mode 100755
  581. --- /dev/null
  582. +++ b/components/user_scripts/android/BUILD.gn
  583. @@ -0,0 +1,83 @@
  584. +# This file is part of Bromite.
  585. +
  586. +# Bromite is free software: you can redistribute it and/or modify
  587. +# it under the terms of the GNU General Public License as published by
  588. +# the Free Software Foundation, either version 3 of the License, or
  589. +# (at your option) any later version.
  590. +
  591. +# Bromite is distributed in the hope that it will be useful,
  592. +# but WITHOUT ANY WARRANTY; without even the implied warranty of
  593. +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  594. +# GNU General Public License for more details.
  595. +
  596. +# You should have received a copy of the GNU General Public License
  597. +# along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  598. +
  599. +import("//build/config/android/rules.gni")
  600. +
  601. +generate_jni("user_scripts_jni_headers") {
  602. + sources = [ "java/src/org/chromium/components/user_scripts/UserScriptsBridge.java" ]
  603. +}
  604. +
  605. +android_resources("java_resources") {
  606. + sources = [
  607. + "java/res/xml/main_preferences_addon_userscripts.xml",
  608. + "java/res/xml/userscripts_preferences.xml",
  609. + "java/res/layout/accept_script_item.xml",
  610. + "java/res/layout/accept_script_list.xml",
  611. + "java/res/layout/scripts_preference.xml",
  612. + "java/res/drawable-hdpi/userscript_off.png",
  613. + "java/res/drawable-hdpi/userscript_on.png",
  614. + "java/res/values/dimens.xml"
  615. + ]
  616. +
  617. + deps = [
  618. + "//components/browser_ui/strings/android:browser_ui_strings_grd",
  619. + "//components/browser_ui/styles/android:java_resources",
  620. + "//components/strings:components_strings_grd",
  621. + "//ui/android:ui_java_resources",
  622. + ]
  623. +}
  624. +
  625. +android_library("java") {
  626. + sources = [
  627. + "java/src/org/chromium/components/user_scripts/FragmentWindowAndroid.java",
  628. + "java/src/org/chromium/components/user_scripts/UserScriptsPreferences.java",
  629. + "java/src/org/chromium/components/user_scripts/UserScriptsBridge.java",
  630. + "java/src/org/chromium/components/user_scripts/ScriptListBaseAdapter.java",
  631. + "java/src/org/chromium/components/user_scripts/ScriptListPreference.java",
  632. + "java/src/org/chromium/components/user_scripts/ScriptInfo.java",
  633. + ]
  634. + deps = [
  635. + ":java_resources",
  636. + "//base:base_java",
  637. + "//base:jni_java",
  638. + "//components/embedder_support/android:browser_context_java",
  639. + "//components/browser_ui/settings/android:java",
  640. + "//components/browser_ui/widget/android:java",
  641. + "//content/public/android:content_java",
  642. + "//components/prefs/android:java",
  643. + "//third_party/android_deps:android_support_v7_appcompat_java",
  644. + "//third_party/android_deps:androidx_annotation_annotation_java",
  645. + "//third_party/android_deps:androidx_appcompat_appcompat_resources_java",
  646. + "//third_party/android_deps:androidx_preference_preference_java",
  647. + "//ui/android:ui_java",
  648. + ]
  649. + resources_package = "org.chromium.components.user_scripts"
  650. + annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
  651. +}
  652. +
  653. +source_set("android") {
  654. + sources = [
  655. + "user_scripts_bridge.cc",
  656. + "user_scripts_bridge.h",
  657. + ]
  658. + deps = [
  659. + ":user_scripts_jni_headers",
  660. + "//base",
  661. + "//components/user_scripts/browser",
  662. + "//components/embedder_support/android:browser_context",
  663. + "//components/permissions",
  664. + "//content/public/browser",
  665. + ]
  666. +}
  667. diff --git a/components/user_scripts/android/java/res/drawable-hdpi/userscript_off.png b/components/user_scripts/android/java/res/drawable-hdpi/userscript_off.png
  668. new file mode 100755
  669. index 0000000000000000000000000000000000000000..e73aedd2c7f76bb0167de23023fe961253c97b70
  670. GIT binary patch
  671. literal 161
  672. zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8K8hNp{TNCjiE0&`DOpaB=tQKj2V
  673. zM>)EL*(T-&&Q^YYXsbfcOm2~U<+HBEf^Laj6Ej8B=KCzZ(5rZRMS*NrkD~-@i$Jml
  674. z<3lTf=0l|lHNSRu6i8gOzs9j#xoUaNp~~K>o%Kf=fCe*sI~Tv`K#x%^&`t(VS3j3^
  675. HP6<r_-MTc>
  676. literal 0
  677. HcmV?d00001
  678. diff --git a/components/user_scripts/android/java/res/drawable-hdpi/userscript_on.png b/components/user_scripts/android/java/res/drawable-hdpi/userscript_on.png
  679. new file mode 100755
  680. index 0000000000000000000000000000000000000000..bcbe8e7416996e7e739b8986f8880feacb57b6a3
  681. GIT binary patch
  682. literal 168
  683. zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8K8zNd?0NJZS+D;s$aDDb#kEGe1U
  684. zc};pkvZTN3wo_a#SFSH$?mYHy?bj!#!hK4NyjN7uXyc1dn<riy^68hUvi*6M=B!Ni
  685. z$1gIbiOrmJTq*E~4@-KNWM`7wq8WiJXG=`{)p1cH$)rnSu992suivhQ_D0@wvOWiW
  686. RumoDo;OXk;vd$@?2>?`wKEeP1
  687. literal 0
  688. HcmV?d00001
  689. diff --git a/components/user_scripts/android/java/res/layout/accept_script_item.xml b/components/user_scripts/android/java/res/layout/accept_script_item.xml
  690. new file mode 100644
  691. --- /dev/null
  692. +++ b/components/user_scripts/android/java/res/layout/accept_script_item.xml
  693. @@ -0,0 +1,65 @@
  694. +<?xml version="1.0" encoding="utf-8"?>
  695. +<!-- Copyright 2017 The Chromium Authors. All rights reserved.
  696. + Use of this source code is governed by a BSD-style license that can be
  697. + found in the LICENSE file. -->
  698. +
  699. +<LinearLayout
  700. + xmlns:android="http://schemas.android.com/apk/res/android"
  701. + xmlns:app="http://schemas.android.com/apk/res-auto"
  702. + xmlns:tools="http://schemas.android.com/tools"
  703. + android:id="@+id/language_item"
  704. + android:layout_marginStart="0dp"
  705. + android:paddingStart="@dimen/draggable_list_item_padding"
  706. + android:paddingEnd="@dimen/draggable_list_item_padding"
  707. + style="@style/ListItemContainer">
  708. +
  709. + <org.chromium.ui.widget.ChromeImageView
  710. + android:id="@+id/icon_view"
  711. + style="@style/ListItemStartIcon"
  712. + app:tint="@color/default_icon_color_tint_list" />
  713. +
  714. + <LinearLayout
  715. + android:layout_width="0dp"
  716. + android:layout_height="wrap_content"
  717. + android:layout_weight="1"
  718. + android:orientation="vertical"
  719. + android:layout_gravity="center_vertical" >
  720. +
  721. + <TextView
  722. + android:id="@+id/title"
  723. + android:layout_width="match_parent"
  724. + android:layout_height="wrap_content"
  725. + style="@style/PreferenceTitle" />
  726. +
  727. + <TextView
  728. + android:id="@+id/description"
  729. + android:layout_width="match_parent"
  730. + android:layout_height="wrap_content"
  731. + style="@style/PreferenceSummary" />
  732. +
  733. + <TextView
  734. + android:id="@+id/version"
  735. + android:layout_width="match_parent"
  736. + android:layout_height="wrap_content"
  737. + style="@style/PreferenceSummary" />
  738. +
  739. + <TextView
  740. + android:id="@+id/file"
  741. + android:layout_width="match_parent"
  742. + android:layout_height="wrap_content"
  743. + style="@style/PreferenceSummary" />
  744. +
  745. + </LinearLayout>
  746. +
  747. + <org.chromium.components.browser_ui.widget.listmenu.ListMenuButton
  748. + android:id="@+id/more"
  749. + android:layout_width="wrap_content"
  750. + android:layout_height="match_parent"
  751. + android:paddingStart="@dimen/default_list_row_padding"
  752. + android:paddingEnd="@dimen/default_list_row_padding"
  753. + android:background="@null"
  754. + android:src="@drawable/ic_more_vert_24dp"
  755. + app:menuMaxWidth="@dimen/pref_scripts_item_popup_width"
  756. + app:tint="@color/default_icon_color_tint_list"
  757. + tools:ignore="ContentDescription" />
  758. +</LinearLayout>
  759. \ No newline at end of file
  760. diff --git a/components/user_scripts/android/java/res/layout/accept_script_list.xml b/components/user_scripts/android/java/res/layout/accept_script_list.xml
  761. new file mode 100644
  762. --- /dev/null
  763. +++ b/components/user_scripts/android/java/res/layout/accept_script_list.xml
  764. @@ -0,0 +1,10 @@
  765. +<?xml version="1.0" encoding="utf-8"?>
  766. +<!-- Copyright 2017 The Chromium Authors. All rights reserved.
  767. + Use of this source code is governed by a BSD-style license that can be
  768. + found in the LICENSE file. -->
  769. +
  770. +<androidx.recyclerview.widget.RecyclerView
  771. + xmlns:android="http://schemas.android.com/apk/res/android"
  772. + android:id="@+id/script_list"
  773. + android:layout_width="match_parent"
  774. + android:layout_height="wrap_content" />
  775. \ No newline at end of file
  776. diff --git a/components/user_scripts/android/java/res/layout/scripts_preference.xml b/components/user_scripts/android/java/res/layout/scripts_preference.xml
  777. new file mode 100644
  778. --- /dev/null
  779. +++ b/components/user_scripts/android/java/res/layout/scripts_preference.xml
  780. @@ -0,0 +1,40 @@
  781. +<?xml version="1.0" encoding="utf-8"?>
  782. +<!-- Copyright 2017 The Chromium Authors. All rights reserved.
  783. + Use of this source code is governed by a BSD-style license that can be
  784. + found in the LICENSE file. -->
  785. +
  786. +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  787. + android:id="@+id/accept_scripts_list_container"
  788. + style="@style/PreferenceLayout"
  789. + android:layout_width="match_parent"
  790. + android:layout_height="wrap_content"
  791. + android:paddingStart="0dp"
  792. + android:paddingEnd="0dp"
  793. + android:padding="0dp"
  794. + android:orientation="vertical" >
  795. +
  796. + <TextView
  797. + android:layout_width="match_parent"
  798. + android:layout_height="wrap_content"
  799. + android:padding="@dimen/draggable_list_item_padding"
  800. + android:text="@string/scripts_list_description" />
  801. +
  802. + <FrameLayout
  803. + android:id="@android:id/widget_frame"
  804. + android:layout_width="match_parent"
  805. + android:layout_height="wrap_content" />
  806. +
  807. + <TextView
  808. + android:id="@+id/add_script"
  809. + android:layout_width="match_parent"
  810. + android:layout_height="wrap_content"
  811. + android:background="?attr/selectableItemBackground"
  812. + android:clickable="true"
  813. + android:gravity="center_vertical"
  814. + android:padding="@dimen/draggable_list_item_padding"
  815. + android:paddingStart="@dimen/pref_scripts_add_button_padding"
  816. + android:drawablePadding="@dimen/pref_scripts_add_button_padding"
  817. + android:text="@string/add_script"
  818. + style="@style/PreferenceTitle" />
  819. +
  820. +</LinearLayout>
  821. \ No newline at end of file
  822. diff --git a/components/user_scripts/android/java/res/values/dimens.xml b/components/user_scripts/android/java/res/values/dimens.xml
  823. new file mode 100755
  824. --- /dev/null
  825. +++ b/components/user_scripts/android/java/res/values/dimens.xml
  826. @@ -0,0 +1,11 @@
  827. +<?xml version="1.0" encoding="utf-8"?>
  828. +<!-- Copyright 2014 The Chromium Authors. All rights reserved.
  829. + Use of this source code is governed by a BSD-style license that can be
  830. + found in the LICENSE file. -->
  831. +
  832. +<resources xmlns:tools="http://schemas.android.com/tools">
  833. +
  834. + <dimen name="pref_scripts_add_button_padding">24dp</dimen>
  835. + <dimen name="pref_scripts_item_popup_width">260dp</dimen>
  836. +
  837. +</resources>
  838. diff --git a/components/user_scripts/android/java/res/xml/main_preferences_addon_userscripts.xml b/components/user_scripts/android/java/res/xml/main_preferences_addon_userscripts.xml
  839. new file mode 100755
  840. --- /dev/null
  841. +++ b/components/user_scripts/android/java/res/xml/main_preferences_addon_userscripts.xml
  842. @@ -0,0 +1,29 @@
  843. +<?xml version="1.0" encoding="utf-8"?>
  844. +<!--
  845. + This file is part of Bromite.
  846. +
  847. + Bromite is free software: you can redistribute it and/or modify
  848. + it under the terms of the GNU General Public License as published by
  849. + the Free Software Foundation, either version 3 of the License, or
  850. + (at your option) any later version.
  851. +
  852. + Bromite is distributed in the hope that it will be useful,
  853. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  854. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  855. + GNU General Public License for more details.
  856. +
  857. + You should have received a copy of the GNU General Public License
  858. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  859. +-->
  860. +
  861. +<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
  862. + xmlns:app="http://schemas.android.com/apk/res-auto"
  863. + android:orderingFromXml="false">
  864. +
  865. + <Preference
  866. + android:fragment="org.chromium.components.user_scripts.UserScriptsPreferences"
  867. + android:key="userscripts_settings"
  868. + android:order="20"
  869. + android:title="@string/prefs_userscripts_settings"/>
  870. +
  871. +</PreferenceScreen>
  872. diff --git a/components/user_scripts/android/java/res/xml/userscripts_preferences.xml b/components/user_scripts/android/java/res/xml/userscripts_preferences.xml
  873. new file mode 100644
  874. --- /dev/null
  875. +++ b/components/user_scripts/android/java/res/xml/userscripts_preferences.xml
  876. @@ -0,0 +1,40 @@
  877. +<?xml version="1.0" encoding="utf-8"?>
  878. +<!--
  879. + This file is part of Bromite.
  880. +
  881. + Bromite is free software: you can redistribute it and/or modify
  882. + it under the terms of the GNU General Public License as published by
  883. + the Free Software Foundation, either version 3 of the License, or
  884. + (at your option) any later version.
  885. +
  886. + Bromite is distributed in the hope that it will be useful,
  887. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  888. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  889. + GNU General Public License for more details.
  890. +
  891. + You should have received a copy of the GNU General Public License
  892. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  893. +-->
  894. +
  895. +<PreferenceScreen
  896. + xmlns:android="http://schemas.android.com/apk/res/android"
  897. + xmlns:app="http://schemas.android.com/apk/res-auto">
  898. +
  899. + <org.chromium.components.browser_ui.settings.TextMessagePreference
  900. + android:key="scripts_disabled_description"
  901. + android:title="@string/scripts_disabled_description"
  902. + app:allowDividerBelow="false"
  903. + app:isPreferenceVisible="false"/>
  904. +
  905. + <org.chromium.components.browser_ui.settings.ChromeSwitchPreference
  906. + android:key="enabled_switch"
  907. + android:title="@string/option_userscript_flag"
  908. + android:summaryOn="@string/option_userscript_flag_on"
  909. + android:summaryOff="@string/option_userscript_flag_off" />
  910. +
  911. + <org.chromium.components.user_scripts.ScriptListPreference
  912. + android:key="script_list"
  913. + android:layout="@layout/scripts_preference"
  914. + android:widgetLayout="@layout/accept_script_list" />
  915. +
  916. +</PreferenceScreen>
  917. diff --git a/components/user_scripts/android/java/src/org/chromium/chrome/browser/user_scripts/UserScriptsUtils.java b/components/user_scripts/android/java/src/org/chromium/chrome/browser/user_scripts/UserScriptsUtils.java
  918. new file mode 100755
  919. --- /dev/null
  920. +++ b/components/user_scripts/android/java/src/org/chromium/chrome/browser/user_scripts/UserScriptsUtils.java
  921. @@ -0,0 +1,49 @@
  922. +/*
  923. + This file is part of Bromite.
  924. +
  925. + Bromite is free software: you can redistribute it and/or modify
  926. + it under the terms of the GNU General Public License as published by
  927. + the Free Software Foundation, either version 3 of the License, or
  928. + (at your option) any later version.
  929. +
  930. + Bromite is distributed in the hope that it will be useful,
  931. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  932. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  933. + GNU General Public License for more details.
  934. +
  935. + You should have received a copy of the GNU General Public License
  936. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  937. +*/
  938. +
  939. +package org.chromium.chrome.browser.user_scripts;
  940. +
  941. +import android.content.Context;
  942. +import android.content.Intent;
  943. +
  944. +import org.chromium.base.ContextUtils;
  945. +import org.chromium.base.IntentUtils;
  946. +
  947. +import org.chromium.chrome.browser.settings.SettingsLauncherImpl;
  948. +import org.chromium.chrome.browser.settings.SettingsLauncher;
  949. +
  950. +import org.chromium.components.user_scripts.UserScriptsPreferences;
  951. +import org.chromium.components.user_scripts.UserScriptsBridge;
  952. +
  953. +public class UserScriptsUtils {
  954. + public static boolean openFile(String filePath, String mimeType, String downloadGuid,
  955. + boolean isOffTheRecord, String originalUrl, String referrer) {
  956. + if (UserScriptsBridge.isUserEnabled() == false) return false;
  957. +
  958. + if (filePath.toUpperCase().endsWith(".USER.JS") == false) return false;
  959. +
  960. + Context context = ContextUtils.getApplicationContext();
  961. +
  962. + SettingsLauncher settingsLauncher = new SettingsLauncherImpl();
  963. + Intent intent = settingsLauncher.createSettingsActivityIntent(
  964. + context, UserScriptsPreferences.class.getName(),
  965. + UserScriptsPreferences.createFragmentArgsForInstall(filePath));
  966. + IntentUtils.safeStartActivity(context, intent);
  967. +
  968. + return true;
  969. + }
  970. +}
  971. \ No newline at end of file
  972. diff --git a/components/user_scripts/android/java/src/org/chromium/components/user_scripts/FragmentWindowAndroid.java b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/FragmentWindowAndroid.java
  973. new file mode 100644
  974. --- /dev/null
  975. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/FragmentWindowAndroid.java
  976. @@ -0,0 +1,68 @@
  977. +// Copyright 2019 The Chromium Authors. All rights reserved.
  978. +// Use of this source code is governed by a BSD-style license that can be
  979. +// found in the LICENSE file.
  980. +
  981. +package org.chromium.components.user_scripts;
  982. +
  983. +import android.annotation.TargetApi;
  984. +import android.app.Activity;
  985. +import android.content.Context;
  986. +import android.content.Intent;
  987. +import android.content.IntentSender;
  988. +import android.os.Build;
  989. +import android.view.View;
  990. +
  991. +import androidx.fragment.app.Fragment;
  992. +
  993. +import org.chromium.ui.base.ActivityKeyboardVisibilityDelegate;
  994. +import org.chromium.ui.base.ActivityAndroidPermissionDelegate;
  995. +import org.chromium.ui.base.ImmutableWeakReference;
  996. +import org.chromium.ui.base.IntentWindowAndroid;
  997. +
  998. +import java.lang.ref.WeakReference;
  999. +
  1000. +/**
  1001. + * Implements intent sending for a fragment based window. This should be created when
  1002. + * onAttach() is called on the fragment, and destroyed when onDetach() is called.
  1003. + */
  1004. +public class FragmentWindowAndroid extends IntentWindowAndroid {
  1005. + private Fragment mFragment;
  1006. +
  1007. + // This WeakReference is purely to avoid gc churn of creating a new WeakReference in
  1008. + // every getActivity call. It is not needed for correctness.
  1009. + private ImmutableWeakReference<Activity> mActivityWeakRefHolder;
  1010. +
  1011. + FragmentWindowAndroid(Context context, Fragment fragment) {
  1012. + super(context);
  1013. + mFragment = fragment;
  1014. +
  1015. + setKeyboardDelegate(new ActivityKeyboardVisibilityDelegate(getActivity()));
  1016. + setAndroidPermissionDelegate(new ActivityAndroidPermissionDelegate(getActivity()));
  1017. + }
  1018. +
  1019. + @Override
  1020. + protected final boolean startIntentSenderForResult(IntentSender intentSender, int requestCode) {
  1021. + try {
  1022. + mFragment.startIntentSenderForResult(
  1023. + intentSender, requestCode, new Intent(), 0, 0, 0, null);
  1024. + } catch (IntentSender.SendIntentException e) {
  1025. + return false;
  1026. + }
  1027. + return true;
  1028. + }
  1029. +
  1030. + @Override
  1031. + protected final boolean startActivityForResult(Intent intent, int requestCode) {
  1032. + mFragment.startActivityForResult(intent, requestCode, null);
  1033. + return true;
  1034. + }
  1035. +
  1036. + @Override
  1037. + public final WeakReference<Activity> getActivity() {
  1038. + if (mActivityWeakRefHolder == null
  1039. + || mActivityWeakRefHolder.get() != mFragment.getActivity()) {
  1040. + mActivityWeakRefHolder = new ImmutableWeakReference<>(mFragment.getActivity());
  1041. + }
  1042. + return mActivityWeakRefHolder;
  1043. + }
  1044. +}
  1045. \ No newline at end of file
  1046. diff --git a/components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptInfo.java b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptInfo.java
  1047. new file mode 100644
  1048. --- /dev/null
  1049. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptInfo.java
  1050. @@ -0,0 +1,31 @@
  1051. +/*
  1052. + This file is part of Bromite.
  1053. +
  1054. + Bromite is free software: you can redistribute it and/or modify
  1055. + it under the terms of the GNU General Public License as published by
  1056. + the Free Software Foundation, either version 3 of the License, or
  1057. + (at your option) any later version.
  1058. +
  1059. + Bromite is distributed in the hope that it will be useful,
  1060. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1061. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1062. + GNU General Public License for more details.
  1063. +
  1064. + You should have received a copy of the GNU General Public License
  1065. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1066. +*/
  1067. +
  1068. +package org.chromium.components.user_scripts;
  1069. +
  1070. +import java.time.LocalDateTime;
  1071. +
  1072. +public class ScriptInfo {
  1073. + public String Key;
  1074. + public String Name;
  1075. + public String Description;
  1076. + public String Version;
  1077. + public boolean Enabled;
  1078. + public LocalDateTime InstallTime;
  1079. +
  1080. + public ScriptInfo() {}
  1081. +}
  1082. diff --git a/components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptListBaseAdapter.java b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptListBaseAdapter.java
  1083. new file mode 100644
  1084. --- /dev/null
  1085. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptListBaseAdapter.java
  1086. @@ -0,0 +1,186 @@
  1087. +/*
  1088. + This file is part of Bromite.
  1089. +
  1090. + Bromite is free software: you can redistribute it and/or modify
  1091. + it under the terms of the GNU General Public License as published by
  1092. + the Free Software Foundation, either version 3 of the License, or
  1093. + (at your option) any later version.
  1094. +
  1095. + Bromite is distributed in the hope that it will be useful,
  1096. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1097. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1098. + GNU General Public License for more details.
  1099. +
  1100. + You should have received a copy of the GNU General Public License
  1101. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1102. +*/
  1103. +
  1104. +package org.chromium.components.user_scripts;
  1105. +
  1106. +import android.content.Context;
  1107. +import android.view.LayoutInflater;
  1108. +import android.view.MotionEvent;
  1109. +import android.view.View;
  1110. +import android.view.ViewGroup;
  1111. +import android.view.accessibility.AccessibilityManager;
  1112. +import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
  1113. +import android.widget.ImageView;
  1114. +import android.widget.TextView;
  1115. +
  1116. +import androidx.annotation.DrawableRes;
  1117. +import androidx.annotation.NonNull;
  1118. +import androidx.core.view.ViewCompat;
  1119. +import androidx.recyclerview.widget.RecyclerView.ViewHolder;
  1120. +
  1121. +import org.chromium.components.browser_ui.widget.dragreorder.DragReorderableListAdapter;
  1122. +import org.chromium.components.browser_ui.widget.dragreorder.DragStateDelegate;
  1123. +import org.chromium.components.browser_ui.widget.listmenu.ListMenuButton;
  1124. +import org.chromium.components.browser_ui.widget.listmenu.ListMenuButtonDelegate;
  1125. +
  1126. +import java.util.ArrayList;
  1127. +import java.util.List;
  1128. +
  1129. +public class ScriptListBaseAdapter extends DragReorderableListAdapter<ScriptInfo> {
  1130. +
  1131. + interface ItemClickListener {
  1132. + void onScriptClicked(ScriptInfo item);
  1133. + }
  1134. +
  1135. + static class ScriptInfoRowViewHolder extends ViewHolder {
  1136. + private TextView mTitle;
  1137. + private TextView mDescription;
  1138. + private TextView mVersion;
  1139. + private TextView mFile;
  1140. +
  1141. + private ImageView mStartIcon;
  1142. + private ListMenuButton mMoreButton;
  1143. +
  1144. + ScriptInfoRowViewHolder(View view) {
  1145. + super(view);
  1146. +
  1147. + mTitle = view.findViewById(R.id.title);
  1148. + mDescription = view.findViewById(R.id.description);
  1149. + mVersion = view.findViewById(R.id.version);
  1150. + mFile = view.findViewById(R.id.file);
  1151. +
  1152. + mStartIcon = view.findViewById(R.id.icon_view);
  1153. + mMoreButton = view.findViewById(R.id.more);
  1154. + }
  1155. +
  1156. + protected void updateScriptInfo(ScriptInfo item) {
  1157. + mTitle.setText(item.Name);
  1158. + mDescription.setText(item.Description);
  1159. + mVersion.setText(item.Version);
  1160. + mFile.setText(item.Key);
  1161. +
  1162. + if (item.Enabled)
  1163. + setStartIcon(R.drawable.userscript_on);
  1164. + else
  1165. + setStartIcon(R.drawable.userscript_off);
  1166. + }
  1167. +
  1168. + void setStartIcon(@DrawableRes int iconResId) {
  1169. + mStartIcon.setVisibility(View.VISIBLE);
  1170. + mStartIcon.setImageResource(iconResId);
  1171. + }
  1172. +
  1173. + void setMenuButtonDelegate(@NonNull ListMenuButtonDelegate delegate) {
  1174. + mMoreButton.setVisibility(View.VISIBLE);
  1175. + mMoreButton.setDelegate(delegate);
  1176. + // Set item row end padding 0 when MenuButton is visible.
  1177. + ViewCompat.setPaddingRelative(itemView, ViewCompat.getPaddingStart(itemView),
  1178. + itemView.getPaddingTop(), 0, itemView.getPaddingBottom());
  1179. + }
  1180. +
  1181. + void setItemClickListener(ScriptInfo item, @NonNull ItemClickListener listener) {
  1182. + itemView.setOnClickListener(view -> listener.onScriptClicked(item));
  1183. + }
  1184. + }
  1185. +
  1186. + private class ScriptDragStateDelegate implements DragStateDelegate {
  1187. + private AccessibilityManager mA11yManager;
  1188. + private AccessibilityStateChangeListener mA11yListener;
  1189. + private boolean mA11yEnabled;
  1190. +
  1191. + public ScriptDragStateDelegate() {
  1192. + mA11yManager =
  1193. + (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
  1194. + mA11yEnabled = mA11yManager.isEnabled();
  1195. + mA11yListener = enabled -> {
  1196. + mA11yEnabled = enabled;
  1197. + notifyDataSetChanged();
  1198. + };
  1199. + mA11yManager.addAccessibilityStateChangeListener(mA11yListener);
  1200. + }
  1201. +
  1202. + @Override
  1203. + public boolean getDragEnabled() {
  1204. + return !mA11yEnabled;
  1205. + }
  1206. +
  1207. + @Override
  1208. + public boolean getDragActive() {
  1209. + return getDragEnabled();
  1210. + }
  1211. +
  1212. + @Override
  1213. + public void setA11yStateForTesting(boolean a11yEnabled) {
  1214. + }
  1215. + }
  1216. +
  1217. + ScriptListBaseAdapter(Context context) {
  1218. + super(context);
  1219. + setDragStateDelegate(new ScriptDragStateDelegate());
  1220. + }
  1221. +
  1222. + void showDragIndicatorInRow(ScriptInfoRowViewHolder holder) {
  1223. + // Quit if it's not applicable.
  1224. + if (getItemCount() <= 1 || !mDragStateDelegate.getDragEnabled()) return;
  1225. +
  1226. + assert mItemTouchHelper != null;
  1227. + //holder.setStartIcon(R.drawable.ic_drag_handle_grey600_24dp);
  1228. + holder.mStartIcon.setOnTouchListener((v, event) -> {
  1229. + if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
  1230. + mItemTouchHelper.startDrag(holder);
  1231. + }
  1232. + return false;
  1233. + });
  1234. + }
  1235. +
  1236. + @Override
  1237. + public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
  1238. + View row = LayoutInflater.from(viewGroup.getContext())
  1239. + .inflate(R.layout.accept_script_item, viewGroup, false);
  1240. + return new ScriptInfoRowViewHolder(row);
  1241. + }
  1242. +
  1243. + @Override
  1244. + public void onBindViewHolder(ViewHolder viewHolder, int i) {
  1245. + ((ScriptInfoRowViewHolder) viewHolder).updateScriptInfo(mElements.get(i));
  1246. + }
  1247. +
  1248. + @Override
  1249. + protected void setOrder(List<ScriptInfo> order) {
  1250. + // String[] codes = new String[order.size()];
  1251. + // for (int i = 0; i < order.size(); i++) {
  1252. + // codes[i] = order.get(i).getCode();
  1253. + // }
  1254. + //LanguagesManager.getInstance().setOrder(codes, false);
  1255. + //notifyDataSetChanged();
  1256. + }
  1257. +
  1258. + void setDisplayedScriptInfo(List<ScriptInfo> values) {
  1259. + mElements = new ArrayList<>(values);
  1260. + notifyDataSetChanged();
  1261. + }
  1262. +
  1263. + @Override
  1264. + protected boolean isActivelyDraggable(ViewHolder viewHolder) {
  1265. + return isPassivelyDraggable(viewHolder);
  1266. + }
  1267. +
  1268. + @Override
  1269. + protected boolean isPassivelyDraggable(ViewHolder viewHolder) {
  1270. + return viewHolder instanceof ScriptInfoRowViewHolder;
  1271. + }
  1272. +}
  1273. diff --git a/components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptListPreference.java b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptListPreference.java
  1274. new file mode 100644
  1275. --- /dev/null
  1276. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptListPreference.java
  1277. @@ -0,0 +1,151 @@
  1278. +/*
  1279. + This file is part of Bromite.
  1280. +
  1281. + Bromite is free software: you can redistribute it and/or modify
  1282. + it under the terms of the GNU General Public License as published by
  1283. + the Free Software Foundation, either version 3 of the License, or
  1284. + (at your option) any later version.
  1285. +
  1286. + Bromite is distributed in the hope that it will be useful,
  1287. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1288. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1289. + GNU General Public License for more details.
  1290. +
  1291. + You should have received a copy of the GNU General Public License
  1292. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1293. +*/
  1294. +
  1295. +package org.chromium.components.user_scripts;
  1296. +
  1297. +import static org.chromium.components.browser_ui.widget.listmenu.BasicListMenu.buildMenuListItem;
  1298. +import static org.chromium.components.browser_ui.widget.listmenu.BasicListMenu.buildMenuListItemWithEndIcon;
  1299. +
  1300. +import android.content.Intent;
  1301. +import android.content.Context;
  1302. +import android.util.AttributeSet;
  1303. +import android.widget.TextView;
  1304. +import android.widget.Toast;
  1305. +
  1306. +import androidx.preference.Preference;
  1307. +import androidx.preference.PreferenceViewHolder;
  1308. +import androidx.recyclerview.widget.DividerItemDecoration;
  1309. +import androidx.recyclerview.widget.LinearLayoutManager;
  1310. +import androidx.recyclerview.widget.RecyclerView;
  1311. +import androidx.recyclerview.widget.RecyclerView.ViewHolder;
  1312. +
  1313. +import org.chromium.ui.base.WindowAndroid;
  1314. +import org.chromium.ui.base.ActivityWindowAndroid;
  1315. +
  1316. +import org.chromium.base.ApplicationStatus;
  1317. +import org.chromium.components.browser_ui.widget.TintedDrawable;
  1318. +import org.chromium.components.browser_ui.widget.listmenu.BasicListMenu;
  1319. +import org.chromium.components.browser_ui.widget.listmenu.ListMenu;
  1320. +import org.chromium.components.browser_ui.widget.listmenu.ListMenuItemProperties;
  1321. +import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
  1322. +
  1323. +import org.chromium.components.user_scripts.ScriptListBaseAdapter;
  1324. +import org.chromium.components.user_scripts.FragmentWindowAndroid;
  1325. +
  1326. +public class ScriptListPreference extends Preference {
  1327. + private static class ScriptListAdapter
  1328. + extends ScriptListBaseAdapter {
  1329. + private final Context mContext;
  1330. +
  1331. + ScriptListAdapter(Context context) {
  1332. + super(context);
  1333. + mContext = context;
  1334. + }
  1335. +
  1336. + @Override
  1337. + public void onBindViewHolder(ViewHolder holder, int position) {
  1338. + super.onBindViewHolder(holder, position);
  1339. +
  1340. + final ScriptInfo info = getItemByPosition(position);
  1341. +
  1342. + showDragIndicatorInRow((ScriptInfoRowViewHolder) holder);
  1343. + ModelList menuItems = new ModelList();
  1344. +
  1345. + menuItems.add(buildMenuListItem(R.string.remove, 0, 0, true));
  1346. + menuItems.add(buildMenuListItem(R.string.scripts_menu_enable, 0, 0, info.Enabled == false));
  1347. + menuItems.add(buildMenuListItem(R.string.scripts_menu_disable, 0, 0, info.Enabled == true));
  1348. +
  1349. + ListMenu.Delegate delegate = (model) -> {
  1350. + int textId = model.get(ListMenuItemProperties.TITLE_ID);
  1351. + if (textId == R.string.remove) {
  1352. + UserScriptsBridge.RemoveScript(info.Key);
  1353. + } else if (textId == R.string.scripts_menu_enable) {
  1354. + UserScriptsBridge.SetScriptEnabled(info.Key, true);
  1355. + } else if (textId == R.string.scripts_menu_disable) {
  1356. + UserScriptsBridge.SetScriptEnabled(info.Key, false);
  1357. + }
  1358. + };
  1359. + ((ScriptInfoRowViewHolder) holder)
  1360. + .setMenuButtonDelegate(() -> new BasicListMenu(mContext, menuItems, delegate));
  1361. + }
  1362. +
  1363. + // @Override
  1364. + public void onDataUpdated() {
  1365. + if (mDragStateDelegate.getDragActive()) {
  1366. + enableDrag();
  1367. + } else {
  1368. + disableDrag();
  1369. + }
  1370. + setDisplayedScriptInfo(UserScriptsBridge.getUserScriptItems());
  1371. + }
  1372. + }
  1373. +
  1374. + private TextView mAddButton;
  1375. + private RecyclerView mRecyclerView;
  1376. + private ScriptListAdapter mAdapter;
  1377. + private FragmentWindowAndroid mwindowAndroid;
  1378. +
  1379. + public ScriptListPreference(Context context, AttributeSet attrs) {
  1380. + super(context, attrs);
  1381. + mAdapter = new ScriptListAdapter(context);
  1382. + }
  1383. +
  1384. + public void setWindowAndroid(FragmentWindowAndroid windowAndroid) {
  1385. + mwindowAndroid = windowAndroid;
  1386. + }
  1387. +
  1388. + @Override
  1389. + public void onBindViewHolder(PreferenceViewHolder holder) {
  1390. + super.onBindViewHolder(holder);
  1391. +
  1392. + mAddButton = (TextView) holder.findViewById(R.id.add_script);
  1393. + mAddButton.setCompoundDrawablesRelativeWithIntrinsicBounds(
  1394. + TintedDrawable.constructTintedDrawable(
  1395. + getContext(), R.drawable.plus, R.color.default_control_color_active),
  1396. + null, null, null);
  1397. + mAddButton.setOnClickListener(view -> {
  1398. + UserScriptsBridge.SelectAndAddScriptFromFile(mwindowAndroid);
  1399. + });
  1400. +
  1401. + mRecyclerView = (RecyclerView) holder.findViewById(R.id.script_list);
  1402. + LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());
  1403. + mRecyclerView.setLayoutManager(layoutManager);
  1404. + mRecyclerView.addItemDecoration(
  1405. + new DividerItemDecoration(getContext(), layoutManager.getOrientation()));
  1406. +
  1407. + UserScriptsBridge.RegisterLoadCallback(this);
  1408. +
  1409. + // We do not want the RecyclerView to be announced by screen readers every time
  1410. + // the view is bound.
  1411. + if (mRecyclerView.getAdapter() != mAdapter) {
  1412. + mRecyclerView.setAdapter(mAdapter);
  1413. + // Initialize script list.
  1414. + mAdapter.onDataUpdated();
  1415. + }
  1416. + }
  1417. +
  1418. + public void NotifyScriptsChanged() {
  1419. + mAdapter.onDataUpdated();
  1420. + }
  1421. +
  1422. + public void OnUserScriptLoaded(boolean result, String error) {
  1423. + if (result == false) {
  1424. + Toast toast = Toast.makeText(getContext(), error, Toast.LENGTH_LONG);
  1425. + toast.show();
  1426. + }
  1427. + }
  1428. +}
  1429. \ No newline at end of file
  1430. diff --git a/components/user_scripts/android/java/src/org/chromium/components/user_scripts/UserScriptsBridge.java b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/UserScriptsBridge.java
  1431. new file mode 100644
  1432. --- /dev/null
  1433. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/UserScriptsBridge.java
  1434. @@ -0,0 +1,145 @@
  1435. +/*
  1436. + This file is part of Bromite.
  1437. +
  1438. + Bromite is free software: you can redistribute it and/or modify
  1439. + it under the terms of the GNU General Public License as published by
  1440. + the Free Software Foundation, either version 3 of the License, or
  1441. + (at your option) any later version.
  1442. +
  1443. + Bromite is distributed in the hope that it will be useful,
  1444. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1445. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1446. + GNU General Public License for more details.
  1447. +
  1448. + You should have received a copy of the GNU General Public License
  1449. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1450. +*/
  1451. +
  1452. +package org.chromium.components.user_scripts;
  1453. +
  1454. +import java.util.ArrayList;
  1455. +import java.util.List;
  1456. +import java.lang.ref.WeakReference;
  1457. +
  1458. +import org.json.JSONArray;
  1459. +import org.json.JSONException;
  1460. +import org.json.JSONObject;
  1461. +
  1462. +import androidx.annotation.Nullable;
  1463. +
  1464. +import org.chromium.base.annotations.CalledByNative;
  1465. +import org.chromium.base.annotations.JNINamespace;
  1466. +import org.chromium.base.annotations.NativeMethods;
  1467. +import org.chromium.base.Log;
  1468. +import org.chromium.ui.base.WindowAndroid;
  1469. +
  1470. +import org.chromium.components.user_scripts.ScriptListPreference;
  1471. +
  1472. +@JNINamespace("user_scripts")
  1473. +public class UserScriptsBridge {
  1474. + static WeakReference<ScriptListPreference> observer;
  1475. +
  1476. + public static boolean isFeatureEnabled() {
  1477. + return UserScriptsBridgeJni.get().isFeatureEnabled();
  1478. + }
  1479. +
  1480. + public static boolean isUserEnabled() {
  1481. + return UserScriptsBridgeJni.get().isUserEnabled();
  1482. + }
  1483. +
  1484. + public static void setUserEnabled(boolean enabled) {
  1485. + UserScriptsBridgeJni.get().setUserEnabled(enabled);
  1486. + }
  1487. +
  1488. + public static void RemoveScript(String key) {
  1489. + UserScriptsBridgeJni.get().removeScript(key);
  1490. + }
  1491. +
  1492. + public static void SetScriptEnabled(String key,
  1493. + boolean enabled) {
  1494. + UserScriptsBridgeJni.get().setScriptEnabled(key, enabled);
  1495. + }
  1496. +
  1497. + public static void Reload() {
  1498. + UserScriptsBridgeJni.get().reload();
  1499. + }
  1500. +
  1501. + public static void SelectAndAddScriptFromFile(WindowAndroid window) {
  1502. + UserScriptsBridgeJni.get().selectAndAddScriptFromFile(window);
  1503. + }
  1504. +
  1505. + public static void TryToInstall(String ScriptFullPath) {
  1506. + UserScriptsBridgeJni.get().tryToInstall(ScriptFullPath);
  1507. + }
  1508. +
  1509. + public static List<ScriptInfo> getUserScriptItems() {
  1510. + List<ScriptInfo> list = new ArrayList<>();
  1511. + try {
  1512. + String json = UserScriptsBridgeJni.get().getScriptsInfo();
  1513. + Log.i("User Scripts Loaded", json);
  1514. +
  1515. + JSONObject jsonObject = new JSONObject(json);
  1516. +
  1517. + JSONArray scripts = jsonObject.names();
  1518. + if (scripts != null) {
  1519. + for (int i = 0; i < scripts.length(); i++) {
  1520. + String key = (String) scripts.get(i);
  1521. + JSONObject script = jsonObject.getJSONObject(key);
  1522. +
  1523. + ScriptInfo si = new ScriptInfo();
  1524. + si.Key = key;
  1525. + list.add(si);
  1526. +
  1527. + if(script.has("name")) si.Name = script.getString("name");
  1528. + if(script.has("description")) si.Description = script.getString("description");
  1529. + if(script.has("version")) si.Version = script.getString("version");
  1530. + si.Enabled = script.getBoolean("enabled");
  1531. + }
  1532. + }
  1533. + } catch (Exception e) {
  1534. + Log.i("User Scripts Load Error", e.toString());
  1535. + }
  1536. + return list;
  1537. + }
  1538. +
  1539. + public static void RegisterLoadCallback(ScriptListPreference caller) {
  1540. + UserScriptsBridgeJni.get().registerLoadCallback();
  1541. + observer = new WeakReference<ScriptListPreference>(caller);
  1542. + }
  1543. +
  1544. + @CalledByNative
  1545. + private static void shouldRefreshUserScriptList() {
  1546. + ScriptListPreference reference = observer.get();
  1547. + if (reference != null) {
  1548. + reference.NotifyScriptsChanged();
  1549. + }
  1550. + }
  1551. +
  1552. + @CalledByNative
  1553. + private static void onUserScriptLoaded(boolean result, String error) {
  1554. + ScriptListPreference reference = observer.get();
  1555. + if (reference != null) {
  1556. + reference.OnUserScriptLoaded(result, error);
  1557. + }
  1558. + }
  1559. +
  1560. + @NativeMethods
  1561. + interface Natives {
  1562. + boolean isFeatureEnabled();
  1563. +
  1564. + boolean isUserEnabled();
  1565. + void setUserEnabled(boolean enabled);
  1566. +
  1567. + String getScriptsInfo();
  1568. +
  1569. + void removeScript(String scriptKey);
  1570. + void setScriptEnabled(String scriptKey, boolean enabled);
  1571. +
  1572. + void reload();
  1573. + void selectAndAddScriptFromFile(WindowAndroid window);
  1574. + void tryToInstall(String scriptFullPath);
  1575. +
  1576. + void registerLoadCallback();
  1577. + }
  1578. +
  1579. +}
  1580. \ No newline at end of file
  1581. diff --git a/components/user_scripts/android/java/src/org/chromium/components/user_scripts/UserScriptsPreferences.java b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/UserScriptsPreferences.java
  1582. new file mode 100755
  1583. --- /dev/null
  1584. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/UserScriptsPreferences.java
  1585. @@ -0,0 +1,141 @@
  1586. +/*
  1587. + This file is part of Bromite.
  1588. +
  1589. + Bromite is free software: you can redistribute it and/or modify
  1590. + it under the terms of the GNU General Public License as published by
  1591. + the Free Software Foundation, either version 3 of the License, or
  1592. + (at your option) any later version.
  1593. +
  1594. + Bromite is distributed in the hope that it will be useful,
  1595. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1596. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1597. + GNU General Public License for more details.
  1598. +
  1599. + You should have received a copy of the GNU General Public License
  1600. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1601. +*/
  1602. +
  1603. +package org.chromium.components.user_scripts;
  1604. +
  1605. +import android.app.Activity;
  1606. +import android.app.AlertDialog;
  1607. +import android.content.Context;
  1608. +import android.content.Intent;
  1609. +import android.content.DialogInterface;
  1610. +import android.os.Bundle;
  1611. +import android.provider.Browser;
  1612. +import android.net.Uri;
  1613. +import android.view.MenuItem;
  1614. +import android.view.View;
  1615. +
  1616. +import androidx.preference.Preference;
  1617. +import androidx.preference.PreferenceFragmentCompat;
  1618. +
  1619. +import org.chromium.base.Log;
  1620. +import org.chromium.ui.base.WindowAndroid;
  1621. +import org.chromium.ui.base.ActivityWindowAndroid;
  1622. +
  1623. +import org.chromium.components.browser_ui.settings.ChromeSwitchPreference;
  1624. +import org.chromium.components.browser_ui.settings.SettingsUtils;
  1625. +import org.chromium.components.browser_ui.settings.TextMessagePreference;
  1626. +
  1627. +import org.chromium.components.user_scripts.UserScriptsBridge;
  1628. +import org.chromium.components.user_scripts.FragmentWindowAndroid;
  1629. +
  1630. +public class UserScriptsPreferences
  1631. + extends PreferenceFragmentCompat
  1632. + implements SettingsUtils.ISupportHelpAndFeedback {
  1633. +
  1634. + private static final String PREF_ENABLED_SWITCH = "enabled_switch";
  1635. + private static final String PREF_SCRIPTLISTPREFERENCE = "script_list";
  1636. + private static final String PREF_SCRIPTS_DISABLED_DESCRIPTION = "scripts_disabled_description";
  1637. +
  1638. + public static final String EXTRA_SCRIPT_FILE = "org.chromium.chrome.preferences.script_file";
  1639. +
  1640. + private FragmentWindowAndroid mwindowAndroid;
  1641. +
  1642. + @Override
  1643. + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
  1644. + getActivity().setTitle(R.string.prefs_userscripts_settings);
  1645. + SettingsUtils.addPreferencesFromResource(this, R.xml.userscripts_preferences);
  1646. +
  1647. + ChromeSwitchPreference enabledSwitch =
  1648. + (ChromeSwitchPreference) findPreference(PREF_ENABLED_SWITCH);
  1649. + boolean enabled = UserScriptsBridge.isUserEnabled();
  1650. + enabledSwitch.setChecked(enabled);
  1651. + enabledSwitch.setOnPreferenceChangeListener((preference, newValue) -> {
  1652. + UserScriptsBridge.setUserEnabled((boolean) newValue);
  1653. + return true;
  1654. + });
  1655. +
  1656. + mwindowAndroid = new FragmentWindowAndroid(getContext(), this);
  1657. + ScriptListPreference listPreference =
  1658. + (ScriptListPreference) findPreference(PREF_SCRIPTLISTPREFERENCE);
  1659. + listPreference.setWindowAndroid(mwindowAndroid);
  1660. +
  1661. + if (UserScriptsBridge.isFeatureEnabled() == false) {
  1662. + enabledSwitch.setEnabled(false);
  1663. + listPreference.setEnabled(false);
  1664. +
  1665. + TextMessagePreference scripts_disabled_description =
  1666. + (TextMessagePreference) findPreference(PREF_SCRIPTS_DISABLED_DESCRIPTION);
  1667. + scripts_disabled_description.setVisible(true);
  1668. + }
  1669. + }
  1670. +
  1671. + @Override
  1672. + public void onActivityResult(int requestCode, int resultCode, Intent data) {
  1673. + // handle picker callback from SelectFileDialog
  1674. + mwindowAndroid.onActivityResult(requestCode, resultCode, data);
  1675. + }
  1676. +
  1677. + public void onHelpAndFeebackPressed() {
  1678. + Context context = getContext();
  1679. +
  1680. + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/bromite/bromite/wiki/UserScripts"));
  1681. + // Let Chromium know that this intent is from Chromium, so that it does not close the app when
  1682. + // the user presses 'back' button.
  1683. + intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
  1684. + intent.putExtra(Browser.EXTRA_CREATE_NEW_TAB, true);
  1685. + intent.setPackage(context.getPackageName());
  1686. + context.startActivity(intent);
  1687. + }
  1688. +
  1689. + public static Bundle createFragmentArgsForInstall(String filePath) {
  1690. + Bundle fragmentArgs = new Bundle();
  1691. + fragmentArgs.putSerializable(EXTRA_SCRIPT_FILE, filePath);
  1692. + return fragmentArgs;
  1693. + }
  1694. +
  1695. + @Override
  1696. + public void onActivityCreated(Bundle savedInstanceState) {
  1697. + super.onActivityCreated(savedInstanceState);
  1698. +
  1699. + String scriptToInstall = (String)getArguments().getSerializable(EXTRA_SCRIPT_FILE);
  1700. + if (scriptToInstall != null) {
  1701. + DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
  1702. + @Override
  1703. + public void onClick(DialogInterface dialog, int which) {
  1704. + switch (which){
  1705. + case DialogInterface.BUTTON_POSITIVE:
  1706. + UserScriptsBridge.TryToInstall(scriptToInstall);
  1707. + break;
  1708. +
  1709. + case DialogInterface.BUTTON_NEGATIVE:
  1710. + break;
  1711. + }
  1712. + }
  1713. + };
  1714. +
  1715. + Context context = getContext();
  1716. + String message = context.getString(R.string.ask_to_install) + " " +
  1717. + scriptToInstall;
  1718. +
  1719. + AlertDialog.Builder builder = new AlertDialog.Builder(context);
  1720. + builder.setMessage(message)
  1721. + .setPositiveButton(context.getString(R.string.yes), dialogClickListener)
  1722. + .setNegativeButton(context.getString(R.string.no), dialogClickListener)
  1723. + .show();
  1724. + }
  1725. + }
  1726. +}
  1727. diff --git a/components/user_scripts/android/java_sources.gni b/components/user_scripts/android/java_sources.gni
  1728. new file mode 100644
  1729. --- /dev/null
  1730. +++ b/components/user_scripts/android/java_sources.gni
  1731. @@ -0,0 +1,18 @@
  1732. +# This file is part of Bromite.
  1733. +
  1734. +# Bromite is free software: you can redistribute it and/or modify
  1735. +# it under the terms of the GNU General Public License as published by
  1736. +# the Free Software Foundation, either version 3 of the License, or
  1737. +# (at your option) any later version.
  1738. +
  1739. +# Bromite is distributed in the hope that it will be useful,
  1740. +# but WITHOUT ANY WARRANTY; without even the implied warranty of
  1741. +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1742. +# GNU General Public License for more details.
  1743. +
  1744. +# You should have received a copy of the GNU General Public License
  1745. +# along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1746. +
  1747. +userscripts_java_sources = [
  1748. + "//components/user_scripts/android/java/src/org/chromium/chrome/browser/user_scripts/UserScriptsUtils.java",
  1749. +]
  1750. diff --git a/components/user_scripts/android/user_scripts_bridge.cc b/components/user_scripts/android/user_scripts_bridge.cc
  1751. new file mode 100644
  1752. --- /dev/null
  1753. +++ b/components/user_scripts/android/user_scripts_bridge.cc
  1754. @@ -0,0 +1,178 @@
  1755. +/*
  1756. + This file is part of Bromite.
  1757. +
  1758. + Bromite is free software: you can redistribute it and/or modify
  1759. + it under the terms of the GNU General Public License as published by
  1760. + the Free Software Foundation, either version 3 of the License, or
  1761. + (at your option) any later version.
  1762. +
  1763. + Bromite is distributed in the hope that it will be useful,
  1764. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1765. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1766. + GNU General Public License for more details.
  1767. +
  1768. + You should have received a copy of the GNU General Public License
  1769. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1770. +*/
  1771. +
  1772. +#include <jni.h>
  1773. +#include <algorithm>
  1774. +#include <string>
  1775. +#include <vector>
  1776. +#include <sstream>
  1777. +#include <iterator>
  1778. +
  1779. +#include "base/android/callback_android.h"
  1780. +#include "base/android/jni_android.h"
  1781. +#include "base/android/jni_array.h"
  1782. +#include "base/android/jni_string.h"
  1783. +#include "base/android/scoped_java_ref.h"
  1784. +#include "components/embedder_support/android/browser_context/browser_context_handle.h"
  1785. +#include "ui/android/window_android.h"
  1786. +
  1787. +#include "components/user_scripts/android/user_scripts_jni_headers/UserScriptsBridge_jni.h"
  1788. +#include "../browser/userscripts_browser_client.h"
  1789. +#include "user_scripts_bridge.h"
  1790. +
  1791. +using base::android::AttachCurrentThread;
  1792. +using base::android::ConvertJavaStringToUTF8;
  1793. +using base::android::ConvertUTF16ToJavaString;
  1794. +using base::android::ConvertUTF8ToJavaString;
  1795. +using base::android::JavaParamRef;
  1796. +using base::android::JavaRef;
  1797. +using base::android::ScopedJavaGlobalRef;
  1798. +using base::android::ScopedJavaLocalRef;
  1799. +using content::BrowserContext;
  1800. +
  1801. +namespace {
  1802. +
  1803. +user_scripts::UserScriptsBrowserClient* GetUserScriptsBrowserClient() {
  1804. + return user_scripts::UserScriptsBrowserClient::GetInstance();
  1805. +}
  1806. +
  1807. +class CallbackObserver : public user_scripts::UserScriptLoader::Observer {
  1808. + private:
  1809. + void OnScriptsLoaded(user_scripts::UserScriptLoader* loader,
  1810. + content::BrowserContext* browser_context) override {
  1811. + user_scripts::ShouldRefreshUserScriptList(base::android::AttachCurrentThread());
  1812. + }
  1813. +
  1814. + void OnUserScriptLoaded(user_scripts::UserScriptLoader* loader,
  1815. + bool result, const std::string& error) override {
  1816. + user_scripts::OnUserScriptLoaded(base::android::AttachCurrentThread(),
  1817. + result, error);
  1818. + }
  1819. +
  1820. + void OnUserScriptLoaderDestroyed(user_scripts::UserScriptLoader* loader) override {}
  1821. +};
  1822. +
  1823. +CallbackObserver* g_userscripts_loader_observer = NULL;
  1824. +
  1825. +}
  1826. +
  1827. +namespace user_scripts {
  1828. +
  1829. +static jboolean JNI_UserScriptsBridge_IsFeatureEnabled(
  1830. + JNIEnv* env) {
  1831. + return GetUserScriptsBrowserClient() != NULL;
  1832. +}
  1833. +
  1834. +static jboolean JNI_UserScriptsBridge_IsUserEnabled(
  1835. + JNIEnv* env) {
  1836. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  1837. + if (client == NULL) return false;
  1838. + return client->GetPrefs()->IsEnabled();
  1839. +}
  1840. +
  1841. +static void JNI_UserScriptsBridge_SetUserEnabled(
  1842. + JNIEnv* env,
  1843. + jboolean is_enabled) {
  1844. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  1845. + if (client == NULL) return;
  1846. + client->GetPrefs()->SetEnabled(is_enabled);
  1847. +}
  1848. +
  1849. +static base::android::ScopedJavaLocalRef<jstring> JNI_UserScriptsBridge_GetScriptsInfo(
  1850. + JNIEnv* env) {
  1851. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  1852. + if (client == NULL) return ConvertUTF8ToJavaString(env, {});
  1853. +
  1854. + std::string json = client->GetPrefs()->GetScriptsInfo();
  1855. + return ConvertUTF8ToJavaString(env, json);
  1856. +}
  1857. +
  1858. +static void JNI_UserScriptsBridge_RemoveScript(
  1859. + JNIEnv* env,
  1860. + const JavaParamRef<jstring>& jscript_key) {
  1861. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  1862. + if (client == NULL) return;
  1863. +
  1864. + std::string script_key = base::android::ConvertJavaStringToUTF8(jscript_key);
  1865. + client->GetLoader()->RemoveScript(script_key);
  1866. +}
  1867. +
  1868. +static void JNI_UserScriptsBridge_SetScriptEnabled(
  1869. + JNIEnv* env,
  1870. + const JavaParamRef<jstring>& jscript_key,
  1871. + jboolean is_enabled) {
  1872. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  1873. + if (client == NULL) return;
  1874. +
  1875. + std::string script_key = base::android::ConvertJavaStringToUTF8(jscript_key);
  1876. + client->GetLoader()->SetScriptEnabled(script_key, is_enabled);
  1877. +}
  1878. +
  1879. +static void JNI_UserScriptsBridge_Reload(
  1880. + JNIEnv* env) {
  1881. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  1882. + if (client == NULL) return;
  1883. +
  1884. + client->GetLoader()->StartLoad();
  1885. + user_scripts::ShouldRefreshUserScriptList(env);
  1886. +}
  1887. +
  1888. +static void JNI_UserScriptsBridge_SelectAndAddScriptFromFile(
  1889. + JNIEnv* env,
  1890. + const JavaParamRef<jobject>& jwindow_android) {
  1891. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  1892. + if (client == NULL) return;
  1893. +
  1894. + client->GetLoader()->SelectAndAddScriptFromFile(
  1895. + ui::WindowAndroid::FromJavaWindowAndroid(jwindow_android));
  1896. +}
  1897. +
  1898. +static void JNI_UserScriptsBridge_TryToInstall(JNIEnv* env,
  1899. + const JavaParamRef<jstring>& jscript_path) {
  1900. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  1901. + if (client == NULL) return;
  1902. +
  1903. + std::string script_path = base::android::ConvertJavaStringToUTF8(jscript_path);
  1904. + base::FilePath path(script_path);
  1905. +
  1906. + client->GetLoader()->TryToInstall(path);
  1907. +}
  1908. +
  1909. +static void JNI_UserScriptsBridge_RegisterLoadCallback(
  1910. + JNIEnv* env) {
  1911. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  1912. + if (client == NULL) return;
  1913. +
  1914. + if( g_userscripts_loader_observer == NULL ) {
  1915. + g_userscripts_loader_observer = new CallbackObserver();
  1916. + client->GetLoader()->AddObserver(g_userscripts_loader_observer);
  1917. + }
  1918. +}
  1919. +
  1920. +static void ShouldRefreshUserScriptList(JNIEnv* env) {
  1921. + Java_UserScriptsBridge_shouldRefreshUserScriptList(env);
  1922. +}
  1923. +
  1924. +static void OnUserScriptLoaded(JNIEnv* env,
  1925. + bool result, const std::string& error) {
  1926. + base::android::ScopedJavaLocalRef<jstring> j_error =
  1927. + base::android::ConvertUTF8ToJavaString(env, error);
  1928. +
  1929. + Java_UserScriptsBridge_onUserScriptLoaded(env, result, j_error);
  1930. +}
  1931. +
  1932. +}
  1933. \ No newline at end of file
  1934. diff --git a/components/user_scripts/android/user_scripts_bridge.h b/components/user_scripts/android/user_scripts_bridge.h
  1935. new file mode 100644
  1936. --- /dev/null
  1937. +++ b/components/user_scripts/android/user_scripts_bridge.h
  1938. @@ -0,0 +1,31 @@
  1939. +/*
  1940. + This file is part of Bromite.
  1941. +
  1942. + Bromite is free software: you can redistribute it and/or modify
  1943. + it under the terms of the GNU General Public License as published by
  1944. + the Free Software Foundation, either version 3 of the License, or
  1945. + (at your option) any later version.
  1946. +
  1947. + Bromite is distributed in the hope that it will be useful,
  1948. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1949. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1950. + GNU General Public License for more details.
  1951. +
  1952. + You should have received a copy of the GNU General Public License
  1953. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1954. +*/
  1955. +
  1956. +#ifndef COMPONENTS_USERSCRIPS_HELPER_ANDROID_H_
  1957. +#define COMPONENTS_USERSCRIPS_HELPER_ANDROID_H_
  1958. +
  1959. +#include <jni.h>
  1960. +
  1961. +namespace user_scripts {
  1962. +
  1963. +static void ShouldRefreshUserScriptList(JNIEnv* env);
  1964. +static void OnUserScriptLoaded(JNIEnv* env,
  1965. + bool result, const std::string& error);
  1966. +
  1967. +} // namespace user_scripts
  1968. +
  1969. +#endif
  1970. \ No newline at end of file
  1971. diff --git a/components/user_scripts/browser/BUILD.gn b/components/user_scripts/browser/BUILD.gn
  1972. new file mode 100755
  1973. --- /dev/null
  1974. +++ b/components/user_scripts/browser/BUILD.gn
  1975. @@ -0,0 +1,68 @@
  1976. +# This file is part of Bromite.
  1977. +
  1978. +# Bromite is free software: you can redistribute it and/or modify
  1979. +# it under the terms of the GNU General Public License as published by
  1980. +# the Free Software Foundation, either version 3 of the License, or
  1981. +# (at your option) any later version.
  1982. +
  1983. +# Bromite is distributed in the hope that it will be useful,
  1984. +# but WITHOUT ANY WARRANTY; without even the implied warranty of
  1985. +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1986. +# GNU General Public License for more details.
  1987. +
  1988. +# You should have received a copy of the GNU General Public License
  1989. +# along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1990. +
  1991. +import("//build/config/features.gni")
  1992. +
  1993. +group("browser") {
  1994. + public_deps = [
  1995. + "//components/user_scripts/browser:browser_sources",
  1996. + ]
  1997. +}
  1998. +
  1999. +source_set("browser_sources") {
  2000. + visibility = [ "./*" ]
  2001. +
  2002. + sources = [
  2003. + "file_task_runner.cc",
  2004. + "file_task_runner.h",
  2005. + "userscripts_browser_client.cc",
  2006. + "userscripts_browser_client.h",
  2007. + "user_script_loader.cc",
  2008. + "user_script_loader.h",
  2009. + "user_script_prefs.cc",
  2010. + "user_script_prefs.h",
  2011. + "user_script_pref_info.cc",
  2012. + "user_script_pref_info.h",
  2013. + ]
  2014. +
  2015. + deps = [
  2016. + "//base:i18n",
  2017. + "//components/keyed_service/content",
  2018. + "//components/keyed_service/core",
  2019. + "//components/pref_registry",
  2020. + "//components/prefs",
  2021. + "//content/public/browser",
  2022. + "//crypto:platform",
  2023. + "//components/user_scripts/common",
  2024. + "//services/device/public/mojom",
  2025. + "//services/preferences/public/cpp",
  2026. + "//services/service_manager/public/cpp",
  2027. + "//third_party/blink/public/common",
  2028. + "//third_party/blink/public/mojom/frame",
  2029. + "//ui/display",
  2030. + ]
  2031. +
  2032. + public_deps = [
  2033. + "//content/public/common",
  2034. + ]
  2035. +
  2036. + configs += [
  2037. + "//build/config:precompiled_headers",
  2038. +
  2039. + # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
  2040. + "//build/config/compiler:no_size_t_to_int_warning",
  2041. + "//build/config/compiler:wexit_time_destructors",
  2042. + ]
  2043. +}
  2044. diff --git a/components/user_scripts/browser/file_task_runner.cc b/components/user_scripts/browser/file_task_runner.cc
  2045. new file mode 100755
  2046. --- /dev/null
  2047. +++ b/components/user_scripts/browser/file_task_runner.cc
  2048. @@ -0,0 +1,40 @@
  2049. +/*
  2050. + This file is part of Bromite.
  2051. +
  2052. + Bromite is free software: you can redistribute it and/or modify
  2053. + it under the terms of the GNU General Public License as published by
  2054. + the Free Software Foundation, either version 3 of the License, or
  2055. + (at your option) any later version.
  2056. +
  2057. + Bromite is distributed in the hope that it will be useful,
  2058. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2059. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2060. + GNU General Public License for more details.
  2061. +
  2062. + You should have received a copy of the GNU General Public License
  2063. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2064. +*/
  2065. +
  2066. +#include "file_task_runner.h"
  2067. +
  2068. +#include "base/sequenced_task_runner.h"
  2069. +#include "base/task/lazy_thread_pool_task_runner.h"
  2070. +#include "base/task/task_traits.h"
  2071. +
  2072. +namespace user_scripts {
  2073. +
  2074. +namespace {
  2075. +
  2076. +base::LazyThreadPoolSequencedTaskRunner g_us_task_runner =
  2077. + LAZY_THREAD_POOL_SEQUENCED_TASK_RUNNER_INITIALIZER(
  2078. + base::TaskTraits(base::MayBlock(),
  2079. + base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN,
  2080. + base::TaskPriority::USER_VISIBLE));
  2081. +
  2082. +} // namespace
  2083. +
  2084. +scoped_refptr<base::SequencedTaskRunner> GetUserScriptsFileTaskRunner() {
  2085. + return g_us_task_runner.Get();
  2086. +}
  2087. +
  2088. +} // namespace user_scripts
  2089. diff --git a/components/user_scripts/browser/file_task_runner.h b/components/user_scripts/browser/file_task_runner.h
  2090. new file mode 100755
  2091. --- /dev/null
  2092. +++ b/components/user_scripts/browser/file_task_runner.h
  2093. @@ -0,0 +1,34 @@
  2094. +/*
  2095. + This file is part of Bromite.
  2096. +
  2097. + Bromite is free software: you can redistribute it and/or modify
  2098. + it under the terms of the GNU General Public License as published by
  2099. + the Free Software Foundation, either version 3 of the License, or
  2100. + (at your option) any later version.
  2101. +
  2102. + Bromite is distributed in the hope that it will be useful,
  2103. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2104. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2105. + GNU General Public License for more details.
  2106. +
  2107. + You should have received a copy of the GNU General Public License
  2108. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2109. +*/
  2110. +
  2111. +#ifndef USERSCRIPTS_BROWSER_EXTENSION_FILE_TASK_RUNNER_H_
  2112. +#define USERSCRIPTS_BROWSER_EXTENSION_FILE_TASK_RUNNER_H_
  2113. +
  2114. +#include "base/memory/ref_counted.h"
  2115. +#include "base/task/task_traits.h"
  2116. +
  2117. +namespace base {
  2118. +class SequencedTaskRunner;
  2119. +}
  2120. +
  2121. +namespace user_scripts {
  2122. +
  2123. +scoped_refptr<base::SequencedTaskRunner> GetUserScriptsFileTaskRunner();
  2124. +
  2125. +} // namespace extensions
  2126. +
  2127. +#endif // USERSCRIPTS_BROWSER_EXTENSION_FILE_TASK_RUNNER_H_
  2128. diff --git a/components/user_scripts/browser/user_script_loader.cc b/components/user_scripts/browser/user_script_loader.cc
  2129. new file mode 100755
  2130. --- /dev/null
  2131. +++ b/components/user_scripts/browser/user_script_loader.cc
  2132. @@ -0,0 +1,650 @@
  2133. +/*
  2134. + This file is part of Bromite.
  2135. +
  2136. + Bromite is free software: you can redistribute it and/or modify
  2137. + it under the terms of the GNU General Public License as published by
  2138. + the Free Software Foundation, either version 3 of the License, or
  2139. + (at your option) any later version.
  2140. +
  2141. + Bromite is distributed in the hope that it will be useful,
  2142. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2143. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2144. + GNU General Public License for more details.
  2145. +
  2146. + You should have received a copy of the GNU General Public License
  2147. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2148. +*/
  2149. +
  2150. +#include "user_script_loader.h"
  2151. +
  2152. +#include <stddef.h>
  2153. +
  2154. +#include <set>
  2155. +#include <string>
  2156. +#include <utility>
  2157. +
  2158. +#include "base/bind.h"
  2159. +#include "base/memory/writable_shared_memory_region.h"
  2160. +#include "base/strings/string_util.h"
  2161. +#include "base/version.h"
  2162. +#include "base/task/task_traits.h"
  2163. +#include "base/files/file_util.h"
  2164. +#include "base/files/file_enumerator.h"
  2165. +#include "base/path_service.h"
  2166. +#include "base/base_paths_android.h"
  2167. +#include "base/strings/utf_string_conversions.h"
  2168. +#include "base/android/content_uri_utils.h"
  2169. +#include "base/android/jni_android.h"
  2170. +
  2171. +#include "crypto/sha2.h"
  2172. +#include "base/base64.h"
  2173. +
  2174. +#include "build/build_config.h"
  2175. +#include "content/public/browser/browser_context.h"
  2176. +#include "content/public/browser/browser_task_traits.h"
  2177. +#include "content/public/browser/browser_thread.h"
  2178. +#include "content/public/browser/notification_service.h"
  2179. +#include "content/public/browser/notification_types.h"
  2180. +#include "content/public/browser/render_process_host.h"
  2181. +#include "third_party/blink/public/mojom/file_system_access/native_file_system_manager.mojom.h"
  2182. +#include "ui/shell_dialogs/select_file_dialog.h"
  2183. +#include "content/browser/file_system_access/file_system_chooser.h"
  2184. +#include "chrome/browser/ui/chrome_select_file_policy.h"
  2185. +#include "ui/android/window_android.h"
  2186. +
  2187. +#include "../common/extension_messages.h"
  2188. +#include "file_task_runner.h"
  2189. +#include "user_script_prefs.h"
  2190. +#include "user_script_pref_info.h"
  2191. +
  2192. +using content::BrowserThread;
  2193. +using content::BrowserContext;
  2194. +
  2195. +namespace user_scripts {
  2196. +
  2197. +using blink::mojom::NativeFileSystemStatus;
  2198. +
  2199. +namespace {
  2200. +
  2201. +bool invalidChar(char c)
  2202. +{
  2203. + return !(c>=0 && c <128);
  2204. +}
  2205. +
  2206. +void stripUnicode(std::string& str)
  2207. +{
  2208. + str.erase(remove_if(str.begin(),str.end(), invalidChar), str.end());
  2209. +}
  2210. +
  2211. +// Helper function to parse greasesmonkey headers
  2212. +bool GetDeclarationValue(const base::StringPiece& line,
  2213. + const base::StringPiece& prefix,
  2214. + std::string* value) {
  2215. + base::StringPiece::size_type index = line.find(prefix);
  2216. + if (index == base::StringPiece::npos)
  2217. + return false;
  2218. +
  2219. + std::string temp(line.data() + index + prefix.length(),
  2220. + line.length() - index - prefix.length());
  2221. +
  2222. + if (temp.empty() || !base::IsUnicodeWhitespace(temp[0]))
  2223. + return false;
  2224. +
  2225. + base::TrimWhitespaceASCII(temp, base::TRIM_ALL, value);
  2226. + return true;
  2227. +}
  2228. +
  2229. +} // namespace
  2230. +
  2231. +// static
  2232. +bool UserScriptLoader::ParseMetadataHeader(const base::StringPiece& script_text,
  2233. + std::unique_ptr<UserScript>& script,
  2234. + std::string& error_message) {
  2235. + // http://wiki.greasespot.net/Metadata_block
  2236. + base::StringPiece line;
  2237. + size_t line_start = 0;
  2238. + size_t line_end = line_start;
  2239. + bool in_metadata = false;
  2240. +
  2241. + static const base::StringPiece kUserScriptBegin("// ==UserScript==");
  2242. + static const base::StringPiece kUserScriptEng("// ==/UserScript==");
  2243. + static const base::StringPiece kNamespaceDeclaration("// @namespace");
  2244. + static const base::StringPiece kNameDeclaration("// @name");
  2245. + static const base::StringPiece kVersionDeclaration("// @version");
  2246. + static const base::StringPiece kDescriptionDeclaration("// @description");
  2247. + static const base::StringPiece kIncludeDeclaration("// @include");
  2248. + static const base::StringPiece kExcludeDeclaration("// @exclude");
  2249. + static const base::StringPiece kMatchDeclaration("// @match");
  2250. + static const base::StringPiece kExcludeMatchDeclaration("// @exclude_match");
  2251. + static const base::StringPiece kRunAtDeclaration("// @run-at");
  2252. + static const base::StringPiece kRunAtDocumentStartValue("document-start");
  2253. + static const base::StringPiece kRunAtDocumentEndValue("document-end");
  2254. + static const base::StringPiece kRunAtDocumentIdleValue("document-idle");
  2255. +
  2256. + while (line_start < script_text.length()) {
  2257. + line_end = script_text.find('\n', line_start);
  2258. +
  2259. + // Handle the case where there is no trailing newline in the file.
  2260. + if (line_end == std::string::npos)
  2261. + line_end = script_text.length() - 1;
  2262. +
  2263. + line = base::StringPiece(script_text.data() + line_start,
  2264. + line_end - line_start);
  2265. +
  2266. + if (!in_metadata) {
  2267. + if (base::StartsWith(line, kUserScriptBegin))
  2268. + in_metadata = true;
  2269. + } else {
  2270. + if (base::StartsWith(line, kUserScriptEng))
  2271. + break;
  2272. +
  2273. + std::string value;
  2274. + if (GetDeclarationValue(line, kIncludeDeclaration, &value)) {
  2275. + // We escape some characters that MatchPattern() considers special.
  2276. + base::ReplaceSubstringsAfterOffset(&value, 0, "\\", "\\\\");
  2277. + base::ReplaceSubstringsAfterOffset(&value, 0, "?", "\\?");
  2278. + script->add_glob(value);
  2279. + } else if (GetDeclarationValue(line, kExcludeDeclaration, &value)) {
  2280. + base::ReplaceSubstringsAfterOffset(&value, 0, "\\", "\\\\");
  2281. + base::ReplaceSubstringsAfterOffset(&value, 0, "?", "\\?");
  2282. + script->add_exclude_glob(value);
  2283. + } else if (GetDeclarationValue(line, kNamespaceDeclaration, &value)) {
  2284. + script->set_name_space(value);
  2285. + } else if (GetDeclarationValue(line, kNameDeclaration, &value)) {
  2286. + script->set_name(value);
  2287. + } else if (GetDeclarationValue(line, kVersionDeclaration, &value)) {
  2288. + base::Version version(value);
  2289. + if (version.IsValid())
  2290. + script->set_version(version.GetString());
  2291. + } else if (GetDeclarationValue(line, kDescriptionDeclaration, &value)) {
  2292. + script->set_description(value);
  2293. + } else if (GetDeclarationValue(line, kMatchDeclaration, &value)) {
  2294. + URLPattern pattern(UserScript::ValidUserScriptSchemes());
  2295. + if (URLPattern::ParseResult::kSuccess != pattern.Parse(value)) {
  2296. + error_message = "Invalid UserScript Schema " + value;
  2297. + return false;
  2298. + }
  2299. + script->add_url_pattern(pattern);
  2300. + } else if (GetDeclarationValue(line, kExcludeMatchDeclaration, &value)) {
  2301. + URLPattern exclude(UserScript::ValidUserScriptSchemes());
  2302. + if (URLPattern::ParseResult::kSuccess != exclude.Parse(value)) {
  2303. + error_message = "Invalid UserScript Schema " + value;
  2304. + return false;
  2305. + }
  2306. + script->add_exclude_url_pattern(exclude);
  2307. + } else if (GetDeclarationValue(line, kRunAtDeclaration, &value)) {
  2308. + if (value == kRunAtDocumentStartValue)
  2309. + script->set_run_location(UserScript::DOCUMENT_START);
  2310. + else if (value == kRunAtDocumentEndValue)
  2311. + script->set_run_location(UserScript::DOCUMENT_END);
  2312. + else if (value == kRunAtDocumentIdleValue)
  2313. + script->set_run_location(UserScript::DOCUMENT_IDLE);
  2314. + else {
  2315. + error_message = "Invalid RunAtDeclaration " + value;
  2316. + return false;
  2317. + }
  2318. + }
  2319. +
  2320. + // TODO(aa): Handle more types of metadata.
  2321. + }
  2322. +
  2323. + line_start = line_end + 1;
  2324. + }
  2325. +
  2326. + // If no patterns were specified, default to @include *. This is what
  2327. + // Greasemonkey does.
  2328. + if (script->globs().empty() && script->url_patterns().is_empty())
  2329. + script->add_glob("*");
  2330. +
  2331. + return true;
  2332. +}
  2333. +
  2334. +// static
  2335. +bool LoadUserScriptFromFile(
  2336. + const base::FilePath& user_script_path, const GURL& original_url,
  2337. + std::unique_ptr<UserScript>& script,
  2338. + base::string16* error) {
  2339. +
  2340. + std::string script_key = user_script_path.BaseName().value();
  2341. +
  2342. + std::string content;
  2343. + if (user_script_path.IsContentUri()) {
  2344. + //LOG(INFO) << "---Path " << user_script_path << " is a content uri";
  2345. +
  2346. + base::FilePath tempFilePath;
  2347. + if( base::CreateTemporaryFile(&tempFilePath) == false ) {
  2348. + *error = base::ASCIIToUTF16("Could not read create temp file.");
  2349. + return false;
  2350. + }
  2351. +
  2352. + if( base::CopyFile(user_script_path, tempFilePath) == false ) {
  2353. + *error = base::ASCIIToUTF16("Could not copy file to temp file.");
  2354. + return false;
  2355. + }
  2356. +
  2357. + if (!base::ReadFileToString(tempFilePath, &content)) {
  2358. + *error = base::ASCIIToUTF16("Could not read source file from temp path.");
  2359. + return false;
  2360. + }
  2361. + } else {
  2362. + if (!base::ReadFileToString(user_script_path, &content)) {
  2363. + *error = base::ASCIIToUTF16("Could not read source file.");
  2364. + return false;
  2365. + }
  2366. + }
  2367. +
  2368. + if (!base::IsStringUTF8(content)) {
  2369. + *error = base::ASCIIToUTF16("User script must be UTF8 encoded.");
  2370. + return false;
  2371. + }
  2372. +
  2373. + std::string detailed_error;
  2374. + if (!UserScriptLoader::ParseMetadataHeader(content, script, detailed_error)) {
  2375. + *error = base::ASCIIToUTF16("Invalid script header. " + detailed_error);
  2376. + return false;
  2377. + }
  2378. +
  2379. + // add into key the filename
  2380. + // this value is used in ui to discriminate scripts
  2381. + script->set_key(script_key);
  2382. +
  2383. + script->set_match_origin_as_fallback(MatchOriginAsFallbackBehavior::kNever);
  2384. +
  2385. + // remove unicode chars and set content into File
  2386. + stripUnicode(content);
  2387. + std::unique_ptr<UserScript::File> file(new UserScript::File());
  2388. + file->set_content(content);
  2389. + file->set_url(GURL(/*script_key*/ "script.js")); // name doesn't matter
  2390. +
  2391. + // create SHA256 of file
  2392. + char raw[crypto::kSHA256Length] = {0};
  2393. + std::string key;
  2394. + crypto::SHA256HashString(content, raw, crypto::kSHA256Length);
  2395. + base::Base64Encode(base::StringPiece(raw, crypto::kSHA256Length), &key);
  2396. + file->set_key(key);
  2397. +
  2398. + script->js_scripts().push_back(std::move(file));
  2399. +
  2400. + return true;
  2401. +}
  2402. +
  2403. +// static
  2404. +bool GetOrCreatePath(base::FilePath& path) {
  2405. + base::PathService::Get(base::DIR_ANDROID_APP_DATA, &path);
  2406. + path = path.AppendASCII("snippets");
  2407. +
  2408. + // create snippets directory if not exists
  2409. + if(!base::PathExists(path)) {
  2410. + LOG(INFO) << "Path " << path << " doesn't exists. Creating";
  2411. + base::File::Error error = base::File::FILE_OK;
  2412. + if( !base::CreateDirectoryAndGetError(path, &error) ) {
  2413. + LOG(INFO) <<
  2414. + "ERROR: failed to create directory: " << path
  2415. + << " with error code " << error;
  2416. + return false;
  2417. + }
  2418. + }
  2419. + return true;
  2420. +}
  2421. +
  2422. +// static
  2423. +void LoadUserScripts(UserScriptList* user_scripts) {
  2424. + base::FilePath path;
  2425. + if (GetOrCreatePath(path) == false) return;
  2426. +
  2427. + // enumerate all files from script path
  2428. + // we accept all files, but we check if it's a real
  2429. + // userscript
  2430. + base::FileEnumerator dir_enum(
  2431. + path,
  2432. + /*recursive=*/false, base::FileEnumerator::FILES);
  2433. + base::FilePath full_name;
  2434. + while (full_name = dir_enum.Next(), !full_name.empty()) {
  2435. + std::unique_ptr<UserScript> userscript(new UserScript());
  2436. +
  2437. + base::string16 error;
  2438. + if (LoadUserScriptFromFile(full_name, GURL(), userscript, &error)) {
  2439. + LOG(INFO) << "Found user script " << userscript->name() <<
  2440. + "-" << userscript->version() <<
  2441. + "-" << userscript->description();
  2442. + user_scripts->push_back(std::move(userscript));
  2443. + } else {
  2444. + LOG(INFO) << "User script load error " << error;
  2445. + }
  2446. + }
  2447. +}
  2448. +
  2449. +UserScriptLoader::UserScriptLoader(BrowserContext* browser_context,
  2450. + UserScriptsPrefs* prefs)
  2451. + : loaded_scripts_(new UserScriptList()),
  2452. + ready_(false),
  2453. + browser_context_(browser_context),
  2454. + prefs_(prefs) {}
  2455. +
  2456. +UserScriptLoader::~UserScriptLoader() {
  2457. + for (auto& observer : observers_)
  2458. + observer.OnUserScriptLoaderDestroyed(this);
  2459. +}
  2460. +
  2461. +void UserScriptLoader::OnRenderProcessHostCreated(
  2462. + content::RenderProcessHost* process_host) {
  2463. + if (initial_load_complete()) {
  2464. + SendUpdate(process_host, shared_memory_);
  2465. + }
  2466. +}
  2467. +
  2468. +void UserScriptLoader::AttemptLoad() {
  2469. + // if (ready_ && ScriptsMayHaveChanged()) {
  2470. + // if (is_loading())
  2471. + // queued_load_ = true;
  2472. + // else
  2473. + StartLoad();
  2474. + // }
  2475. +}
  2476. +
  2477. +void UserScriptLoader::StartLoad() {
  2478. + DCHECK_CURRENTLY_ON(BrowserThread::UI);
  2479. + // DCHECK(!is_loading());
  2480. +
  2481. + // LOG(INFO) << "---UserScriptLoader::StartLoad";
  2482. +
  2483. + // Reload any loaded scripts, and clear out |loaded_scripts_| to indicate that
  2484. + // the scripts aren't currently ready.
  2485. + std::unique_ptr<UserScriptList> scripts_to_load = std::move(loaded_scripts_);
  2486. + scripts_to_load->clear();
  2487. +
  2488. + LoadScripts(std::move(scripts_to_load),
  2489. + base::BindOnce(&UserScriptLoader::OnScriptsLoaded,
  2490. + weak_factory_.GetWeakPtr()));
  2491. +}
  2492. +
  2493. +// static
  2494. +base::ReadOnlySharedMemoryRegion UserScriptLoader::Serialize(
  2495. + const UserScriptList& scripts) {
  2496. + base::Pickle pickle;
  2497. + pickle.WriteUInt32(scripts.size());
  2498. + for (const std::unique_ptr<UserScript>& script : scripts) {
  2499. + // TODO(aa): This can be replaced by sending content script metadata to
  2500. + // renderers along with other extension data in ExtensionMsg_Loaded.
  2501. + // See crbug.com/70516.
  2502. + script->Pickle(&pickle);
  2503. + // Write scripts as 'data' so that we can read it out in the slave without
  2504. + // allocating a new string.
  2505. + for (const std::unique_ptr<UserScript::File>& js_file :
  2506. + script->js_scripts()) {
  2507. + base::StringPiece contents = js_file->GetContent();
  2508. + pickle.WriteData(contents.data(), contents.length());
  2509. + }
  2510. + for (const std::unique_ptr<UserScript::File>& css_file :
  2511. + script->css_scripts()) {
  2512. + base::StringPiece contents = css_file->GetContent();
  2513. + pickle.WriteData(contents.data(), contents.length());
  2514. + }
  2515. + }
  2516. +
  2517. + // Create the shared memory object.
  2518. + base::MappedReadOnlyRegion shared_memory =
  2519. + base::ReadOnlySharedMemoryRegion::Create(pickle.size());
  2520. + if (!shared_memory.IsValid())
  2521. + return {};
  2522. +
  2523. + // Copy the pickle to shared memory.
  2524. + memcpy(shared_memory.mapping.memory(), pickle.data(), pickle.size());
  2525. + return std::move(shared_memory.region);
  2526. +}
  2527. +
  2528. +void UserScriptLoader::AddObserver(Observer* observer) {
  2529. + observers_.AddObserver(observer);
  2530. +}
  2531. +
  2532. +void UserScriptLoader::RemoveObserver(Observer* observer) {
  2533. + observers_.RemoveObserver(observer);
  2534. +}
  2535. +
  2536. +void UserScriptLoader::SetReady(bool ready) {
  2537. + bool was_ready = ready_;
  2538. + ready_ = ready;
  2539. + if (ready_ && !was_ready)
  2540. + AttemptLoad();
  2541. +}
  2542. +
  2543. +void UserScriptLoader::OnScriptsLoaded(
  2544. + std::unique_ptr<UserScriptList> user_scripts,
  2545. + base::ReadOnlySharedMemoryRegion shared_memory) {
  2546. + // LOG(INFO) << "---UserScriptLoader::OnScriptsLoaded";
  2547. +
  2548. + // Check user preferences for loaded user scripts
  2549. + prefs_->CompareWithPrefs(*user_scripts);
  2550. + loaded_scripts_ = std::move(user_scripts);
  2551. +
  2552. + shared_memory =
  2553. + UserScriptLoader::Serialize(*loaded_scripts_);
  2554. +
  2555. + if (!shared_memory.IsValid()) {
  2556. + // This can happen if we run out of file descriptors. In that case, we
  2557. + // have a choice between silently omitting all user scripts for new tabs,
  2558. + // by nulling out shared_memory_, or only silently omitting new ones by
  2559. + // leaving the existing object in place. The second seems less bad, even
  2560. + // though it removes the possibility that freeing the shared memory block
  2561. + // would open up enough FDs for long enough for a retry to succeed.
  2562. +
  2563. + // Pretend the extension change didn't happen.
  2564. + return;
  2565. + }
  2566. +
  2567. + // LOG(INFO) << "---UserScriptLoader::OnScriptsLoaded 2";
  2568. +
  2569. + // We've got scripts ready to go.
  2570. + shared_memory_ = std::move(shared_memory);
  2571. +
  2572. + for (content::RenderProcessHost::iterator i(
  2573. + content::RenderProcessHost::AllHostsIterator());
  2574. + !i.IsAtEnd(); i.Advance()) {
  2575. + SendUpdate(i.GetCurrentValue(), shared_memory_);
  2576. + }
  2577. +
  2578. + for (auto& observer : observers_)
  2579. + observer.OnScriptsLoaded(this, browser_context_);
  2580. +}
  2581. +
  2582. +void UserScriptLoader::SendUpdate(
  2583. + content::RenderProcessHost* process,
  2584. + const base::ReadOnlySharedMemoryRegion& shared_memory) {
  2585. + // LOG(INFO) << "---UserScriptLoader::SendUpdate";
  2586. +
  2587. + // If the process is being started asynchronously, early return. We'll end up
  2588. + // calling InitUserScripts when it's created which will call this again.
  2589. + base::ProcessHandle handle = process->GetProcess().Handle();
  2590. + if (!handle)
  2591. + return;
  2592. +
  2593. + base::ReadOnlySharedMemoryRegion region_for_process =
  2594. + shared_memory.Duplicate();
  2595. + if (!region_for_process.IsValid())
  2596. + return;
  2597. +
  2598. + process->Send(new ExtensionMsg_UpdateUserScripts(
  2599. + std::move(region_for_process)));
  2600. +}
  2601. +
  2602. +void LoadScriptsOnFileTaskRunner(
  2603. + std::unique_ptr<UserScriptList> user_scripts,
  2604. + UserScriptLoader::LoadScriptsCallback callback) {
  2605. + DCHECK(GetUserScriptsFileTaskRunner()->RunsTasksInCurrentSequence());
  2606. + DCHECK(user_scripts.get());
  2607. +
  2608. + // load user scripts from path
  2609. + LoadUserScripts(user_scripts.get());
  2610. +
  2611. + base::ReadOnlySharedMemoryRegion memory;
  2612. +
  2613. + // Explicit priority to prevent unwanted task priority inheritance.
  2614. + content::GetUIThreadTaskRunner({base::TaskPriority::USER_BLOCKING})
  2615. + ->PostTask(FROM_HERE,
  2616. + base::BindOnce(std::move(callback), std::move(user_scripts),
  2617. + std::move(memory)));
  2618. +}
  2619. +
  2620. +void UserScriptLoader::LoadScripts(
  2621. + std::unique_ptr<UserScriptList> user_scripts,
  2622. + LoadScriptsCallback callback) {
  2623. + DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  2624. +
  2625. + // LOG(INFO) << "---UserScriptLoader::LoadScripts";
  2626. +
  2627. + GetUserScriptsFileTaskRunner()->PostTask(
  2628. + FROM_HERE,
  2629. + base::BindOnce(&LoadScriptsOnFileTaskRunner, std::move(user_scripts),
  2630. + std::move(callback)));
  2631. +}
  2632. +
  2633. +void RemoveScriptsOnFileTaskRunner(
  2634. + const std::string& script_id,
  2635. + UserScriptLoader::RemoveScriptCallback callback) {
  2636. + DCHECK(GetUserScriptsFileTaskRunner()->RunsTasksInCurrentSequence());
  2637. +
  2638. + base::FilePath path;
  2639. + if (GetOrCreatePath(path)) {
  2640. + base::FilePath file = path.Append(script_id);
  2641. + if( base::DeleteFile(file) == false ) {
  2642. + LOG(INFO) <<
  2643. + "ERROR: failed to delete file : " << path;
  2644. + }
  2645. + }
  2646. +
  2647. + content::GetUIThreadTaskRunner({base::TaskPriority::USER_BLOCKING})
  2648. + ->PostTask(FROM_HERE,
  2649. + base::BindOnce(std::move(callback)));
  2650. +}
  2651. +
  2652. +void UserScriptLoader::OnScriptRemoved() {
  2653. + StartLoad();
  2654. +}
  2655. +
  2656. +void UserScriptLoader::RemoveScript(const std::string& script_id) {
  2657. + prefs_->RemoveScriptFromPrefs(script_id);
  2658. +
  2659. + GetUserScriptsFileTaskRunner()->PostTask(
  2660. + FROM_HERE,
  2661. + base::BindOnce(&RemoveScriptsOnFileTaskRunner,
  2662. + std::move(script_id),
  2663. + base::BindOnce(&UserScriptLoader::OnScriptRemoved,
  2664. + weak_factory_.GetWeakPtr())));
  2665. +}
  2666. +
  2667. +void UserScriptLoader::SetScriptEnabled(const std::string& script_id, bool is_enabled) {
  2668. + prefs_->SetScriptEnabled(script_id, is_enabled);
  2669. + StartLoad();
  2670. +}
  2671. +
  2672. +void UserScriptLoader::SelectAndAddScriptFromFile(ui::WindowAndroid* nativeWindow) {
  2673. + DCHECK_CURRENTLY_ON(BrowserThread::UI);
  2674. +
  2675. + dialog_ = ui::SelectFileDialog::Create(
  2676. + this, std::make_unique<ChromeSelectFilePolicy>(nullptr /*web_contents*/));
  2677. +
  2678. + ui::SelectFileDialog::FileTypeInfo allowed_file_info;
  2679. + allowed_file_info.extensions = {{FILE_PATH_LITERAL("js")}};
  2680. + allowed_file_info.allowed_paths =
  2681. + ui::SelectFileDialog::FileTypeInfo::ANY_PATH;
  2682. + base::FilePath suggested_name;
  2683. +
  2684. + std::vector<base::string16> types;
  2685. + types.push_back(base::ASCIIToUTF16("*/*")); /*= java SelectFileDialog.ALL_TYPES*/
  2686. + std::pair<std::vector<base::string16>, bool> accept_types = std::make_pair(
  2687. + types, false /*use_media_capture*/);
  2688. +
  2689. + dialog_->SelectFile(
  2690. + ui::SelectFileDialog::SELECT_OPEN_FILE,
  2691. + base::string16() /* dialog title*/, suggested_name, &allowed_file_info,
  2692. + 0 /* file type index */, std::string() /* default file extension */,
  2693. + nativeWindow,
  2694. + &accept_types /* params */);
  2695. +}
  2696. +
  2697. +
  2698. +void LoadScriptFromPathOnFileTaskRunner(
  2699. + const base::FilePath& path,
  2700. + const std::string& display_name,
  2701. + UserScriptLoader::LoadSingleScriptCallback callback ) {
  2702. + DCHECK(GetUserScriptsFileTaskRunner()->RunsTasksInCurrentSequence());
  2703. +
  2704. + std::unique_ptr<UserScript> userscript(new UserScript());
  2705. + base::string16 error;
  2706. + bool result = LoadUserScriptFromFile(path, GURL(), userscript, &error);
  2707. +
  2708. + if(result) {
  2709. + if (display_name.empty() == false) {
  2710. + userscript->set_key(display_name);
  2711. + }
  2712. +
  2713. + LOG(INFO) << "User Script Loaded " << userscript->name() <<
  2714. + "-" << userscript->version() <<
  2715. + "-" << userscript->description();
  2716. + base::FilePath destination;
  2717. + result = GetOrCreatePath(destination);
  2718. + if( result == false ) {
  2719. + error = base::ASCIIToUTF16("Cannot create destination.");
  2720. + } else {
  2721. + destination = destination.Append(userscript->key());
  2722. + result = base::CopyFile(path, destination);
  2723. + if (result == false) {
  2724. + error = base::ASCIIToUTF16("Copy error.");
  2725. + }
  2726. + }
  2727. + } else {
  2728. + LOG(INFO) << "User Script Load error " << error;
  2729. + }
  2730. +
  2731. + const std::string string_error = base::UTF16ToASCII(error);
  2732. +
  2733. + content::GetUIThreadTaskRunner({base::TaskPriority::USER_BLOCKING})
  2734. + ->PostTask(FROM_HERE,
  2735. + base::BindOnce(std::move(callback), result,
  2736. + std::move(string_error)));
  2737. +}
  2738. +
  2739. +void UserScriptLoader::TryToInstall(const base::FilePath& script_path) {
  2740. + base::string16 file_display_name;
  2741. + base::MaybeGetFileDisplayName(script_path, &file_display_name);
  2742. +
  2743. + std::string display_name = script_path.BaseName().value();
  2744. + if (base::IsStringASCII(file_display_name))
  2745. + display_name = base::UTF16ToASCII(file_display_name);
  2746. +
  2747. + GetUserScriptsFileTaskRunner()->PostTask(
  2748. + FROM_HERE,
  2749. + base::BindOnce(
  2750. + &LoadScriptFromPathOnFileTaskRunner,
  2751. + script_path, display_name,
  2752. + base::BindOnce(
  2753. + &UserScriptLoader::LoadScriptFromPathOnFileTaskRunnerCallback,
  2754. + weak_factory_.GetWeakPtr()
  2755. + )
  2756. + ));
  2757. +}
  2758. +
  2759. +void UserScriptLoader::FileSelected(
  2760. + const base::FilePath& path, int index, void* params) {
  2761. + LOG(INFO) << "UserScriptLoader::FileSelected " << path;
  2762. +
  2763. + UserScriptLoader::TryToInstall(path);
  2764. +}
  2765. +
  2766. +void UserScriptLoader::LoadScriptFromPathOnFileTaskRunnerCallback(
  2767. + bool result, const std::string& error) {
  2768. + // LOG(INFO) << "Return from LoadScriptFromPathOnFileTaskRunnerCallback "
  2769. + // << result << " " << error;
  2770. +
  2771. + for (auto& observer : observers_)
  2772. + observer.OnUserScriptLoaded(this, result, error);
  2773. +
  2774. + StartLoad();
  2775. +}
  2776. +
  2777. +void UserScriptLoader::FileSelectionCanceled(
  2778. + void* params) {
  2779. + LOG(INFO) << "UserScriptLoader::FileSelectionCanceled";
  2780. +}
  2781. +
  2782. +} // namespace extensions
  2783. diff --git a/components/user_scripts/browser/user_script_loader.h b/components/user_scripts/browser/user_script_loader.h
  2784. new file mode 100755
  2785. --- /dev/null
  2786. +++ b/components/user_scripts/browser/user_script_loader.h
  2787. @@ -0,0 +1,173 @@
  2788. +/*
  2789. + This file is part of Bromite.
  2790. +
  2791. + Bromite is free software: you can redistribute it and/or modify
  2792. + it under the terms of the GNU General Public License as published by
  2793. + the Free Software Foundation, either version 3 of the License, or
  2794. + (at your option) any later version.
  2795. +
  2796. + Bromite is distributed in the hope that it will be useful,
  2797. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2798. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2799. + GNU General Public License for more details.
  2800. +
  2801. + You should have received a copy of the GNU General Public License
  2802. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2803. +*/
  2804. +
  2805. +#ifndef USERSCRIPTS_BROWSER_USER_SCRIPT_LOADER_H_
  2806. +#define USERSCRIPTS_BROWSER_USER_SCRIPT_LOADER_H_
  2807. +
  2808. +#include <map>
  2809. +#include <memory>
  2810. +#include <set>
  2811. +
  2812. +#include "base/callback_forward.h"
  2813. +#include "base/compiler_specific.h"
  2814. +#include "base/macros.h"
  2815. +#include "base/memory/read_only_shared_memory_region.h"
  2816. +#include "base/memory/weak_ptr.h"
  2817. +#include "base/observer_list.h"
  2818. +#include "base/scoped_observer.h"
  2819. +#include "content/public/browser/render_process_host_creation_observer.h"
  2820. +#include "third_party/blink/public/mojom/file_system_access/native_file_system_manager.mojom.h"
  2821. +#include "ui/shell_dialogs/select_file_dialog.h"
  2822. +#include "content/browser/file_system_access/file_system_chooser.h"
  2823. +#include "ui/android/window_android.h"
  2824. +
  2825. +#include "../common/host_id.h"
  2826. +#include "../common/user_script.h"
  2827. +#include "user_script_prefs.h"
  2828. +
  2829. +namespace base {
  2830. +class ReadOnlySharedMemoryRegion;
  2831. +}
  2832. +
  2833. +namespace content {
  2834. +class BrowserContext;
  2835. +class RenderProcessHost;
  2836. +}
  2837. +
  2838. +namespace user_scripts {
  2839. +
  2840. +// Manages one "logical unit" of user scripts in shared memory by constructing a
  2841. +// new shared memory region when the set of scripts changes. Also notifies
  2842. +// renderers of new shared memory region when new renderers appear, or when
  2843. +// script reloading completes. Script loading lives on the file thread.
  2844. +class UserScriptLoader : public content::RenderProcessHostCreationObserver,
  2845. + public ui::SelectFileDialog::Listener {
  2846. + public:
  2847. + using LoadScriptsCallback =
  2848. + base::OnceCallback<void(std::unique_ptr<UserScriptList>,
  2849. + base::ReadOnlySharedMemoryRegion shared_memory)>;
  2850. + using LoadSingleScriptCallback =
  2851. + base::OnceCallback<void(bool result, const std::string& error)>;
  2852. +
  2853. + using RemoveScriptCallback =
  2854. + base::OnceCallback<void()>;
  2855. + class Observer {
  2856. + public:
  2857. + virtual void OnScriptsLoaded(UserScriptLoader* loader,
  2858. + content::BrowserContext* browser_context) = 0;
  2859. + virtual void OnUserScriptLoaderDestroyed(UserScriptLoader* loader) = 0;
  2860. + virtual void OnUserScriptLoaded(UserScriptLoader* loader,
  2861. + bool result, const std::string& error) = 0;
  2862. + };
  2863. +
  2864. + // Parses the includes out of |script| and returns them in |includes|.
  2865. + static bool ParseMetadataHeader(const base::StringPiece& script_text,
  2866. + std::unique_ptr<UserScript>& script,
  2867. + std::string& error_message);
  2868. +
  2869. + UserScriptLoader(content::BrowserContext* browser_context,
  2870. + UserScriptsPrefs* prefs);
  2871. + //const HostID& host_id);
  2872. + ~UserScriptLoader() override;
  2873. +
  2874. + // Initiates procedure to start loading scripts on the file thread.
  2875. + void StartLoad();
  2876. +
  2877. + // Returns true if we have any scripts ready.
  2878. + bool initial_load_complete() const { return shared_memory_.IsValid(); }
  2879. +
  2880. + // Pickle user scripts and return pointer to the shared memory.
  2881. + static base::ReadOnlySharedMemoryRegion Serialize(
  2882. + const user_scripts::UserScriptList& scripts);
  2883. +
  2884. + // Adds or removes observers.
  2885. + void AddObserver(Observer* observer);
  2886. + void RemoveObserver(Observer* observer);
  2887. +
  2888. + // Sets the flag if the initial set of hosts has finished loading; if it's
  2889. + // set to be true, calls AttempLoad() to bootstrap.
  2890. + void SetReady(bool ready);
  2891. +
  2892. + void RemoveScript(const std::string& script_id);
  2893. + void SetScriptEnabled(const std::string& script_id, bool is_enabled);
  2894. +
  2895. + void SelectAndAddScriptFromFile(ui::WindowAndroid* wa);
  2896. + void TryToInstall(const base::FilePath& script_path);
  2897. +
  2898. + protected:
  2899. + void LoadScripts(std::unique_ptr<UserScriptList> user_scripts,
  2900. + LoadScriptsCallback callback);
  2901. +
  2902. + content::BrowserContext* browser_context() const { return browser_context_; }
  2903. +
  2904. + UserScriptsPrefs* prefs() const { return prefs_; }
  2905. +
  2906. + private:
  2907. + void OnRenderProcessHostCreated(
  2908. + content::RenderProcessHost* process_host) override;
  2909. +
  2910. + // Attempts to initiate a load.
  2911. + void AttemptLoad();
  2912. +
  2913. + // Called once we have finished loading the scripts on the file thread.
  2914. + void OnScriptsLoaded(std::unique_ptr<UserScriptList> user_scripts,
  2915. + base::ReadOnlySharedMemoryRegion shared_memory);
  2916. +
  2917. + // Sends the renderer process a new set of user scripts. If
  2918. + // |changed_hosts| is not empty, this signals that only the scripts from
  2919. + // those hosts should be updated. Otherwise, all hosts will be
  2920. + // updated.
  2921. + void SendUpdate(content::RenderProcessHost* process,
  2922. + const base::ReadOnlySharedMemoryRegion& shared_memory);
  2923. +
  2924. + // Contains the scripts that were found the last time scripts were updated.
  2925. + base::ReadOnlySharedMemoryRegion shared_memory_;
  2926. +
  2927. + // List of scripts that are currently loaded. This is null when a load is in
  2928. + // progress.
  2929. + std::unique_ptr<UserScriptList> loaded_scripts_;
  2930. +
  2931. + // If the initial set of hosts has finished loading.
  2932. + bool ready_;
  2933. +
  2934. + // The browser_context for which the scripts managed here are installed.
  2935. + content::BrowserContext* browser_context_;
  2936. +
  2937. + // Manage load and store from preferences
  2938. + UserScriptsPrefs* prefs_;
  2939. +
  2940. + // The associated observers.
  2941. + base::ObserverList<Observer>::Unchecked observers_;
  2942. +
  2943. + void OnScriptRemoved();
  2944. +
  2945. + // Manage file dialog requests
  2946. + scoped_refptr<ui::SelectFileDialog> dialog_;
  2947. + void FileSelected(const base::FilePath& path,
  2948. + int index, void* params) override;
  2949. + void FileSelectionCanceled(void* params) override;
  2950. + void LoadScriptFromPathOnFileTaskRunnerCallback(
  2951. + bool result, const std::string& error );
  2952. +
  2953. + base::WeakPtrFactory<UserScriptLoader> weak_factory_{this};
  2954. +
  2955. + DISALLOW_COPY_AND_ASSIGN(UserScriptLoader);
  2956. +};
  2957. +
  2958. +} // namespace extensions
  2959. +
  2960. +#endif // USERSCRIPTS_BROWSER_USER_SCRIPT_LOADER_H_
  2961. diff --git a/components/user_scripts/browser/user_script_pref_info.cc b/components/user_scripts/browser/user_script_pref_info.cc
  2962. new file mode 100644
  2963. --- /dev/null
  2964. +++ b/components/user_scripts/browser/user_script_pref_info.cc
  2965. @@ -0,0 +1,34 @@
  2966. +/*
  2967. + This file is part of Bromite.
  2968. +
  2969. + Bromite is free software: you can redistribute it and/or modify
  2970. + it under the terms of the GNU General Public License as published by
  2971. + the Free Software Foundation, either version 3 of the License, or
  2972. + (at your option) any later version.
  2973. +
  2974. + Bromite is distributed in the hope that it will be useful,
  2975. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2976. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2977. + GNU General Public License for more details.
  2978. +
  2979. + You should have received a copy of the GNU General Public License
  2980. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2981. +*/
  2982. +
  2983. +#include "user_script_pref_info.h"
  2984. +
  2985. +namespace user_scripts {
  2986. +
  2987. +UserScriptsListPrefs::ScriptInfo::ScriptInfo(const std::string& name,
  2988. + const std::string& description,
  2989. + const base::Time& install_time,
  2990. + bool enabled)
  2991. + : install_time(install_time),
  2992. + enabled(enabled),
  2993. + name_(name),
  2994. + description_(description) {}
  2995. +
  2996. +UserScriptsListPrefs::ScriptInfo::ScriptInfo(const ScriptInfo& other) = default;
  2997. +UserScriptsListPrefs::ScriptInfo::~ScriptInfo() = default;
  2998. +
  2999. +}
  3000. \ No newline at end of file
  3001. diff --git a/components/user_scripts/browser/user_script_pref_info.h b/components/user_scripts/browser/user_script_pref_info.h
  3002. new file mode 100644
  3003. --- /dev/null
  3004. +++ b/components/user_scripts/browser/user_script_pref_info.h
  3005. @@ -0,0 +1,58 @@
  3006. +/*
  3007. + This file is part of Bromite.
  3008. +
  3009. + Bromite is free software: you can redistribute it and/or modify
  3010. + it under the terms of the GNU General Public License as published by
  3011. + the Free Software Foundation, either version 3 of the License, or
  3012. + (at your option) any later version.
  3013. +
  3014. + Bromite is distributed in the hope that it will be useful,
  3015. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  3016. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  3017. + GNU General Public License for more details.
  3018. +
  3019. + You should have received a copy of the GNU General Public License
  3020. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  3021. +*/
  3022. +
  3023. +#ifndef USERSCRIPTS_BROWSER_USERSCRIPT_PREF_INFO_H_
  3024. +#define USERSCRIPTS_BROWSER_USERSCRIPT_PREF_INFO_H_
  3025. +
  3026. +#include "base/values.h"
  3027. +#include "base/time/time.h"
  3028. +#include "components/keyed_service/core/keyed_service.h"
  3029. +
  3030. +namespace user_scripts {
  3031. +
  3032. +class UserScriptsListPrefs : public KeyedService {
  3033. + public:
  3034. + struct ScriptInfo {
  3035. + ScriptInfo(const std::string& name,
  3036. + const std::string& description,
  3037. + const base::Time& install_time,
  3038. + bool enabled);
  3039. + ScriptInfo(const ScriptInfo& other);
  3040. + ~ScriptInfo();
  3041. +
  3042. + const std::string& name() const { return name_; }
  3043. + void set_name(const std::string& name) { name_ = name; }
  3044. +
  3045. + const std::string& description() const { return description_; }
  3046. + void set_description(const std::string& description) { description_ = description; }
  3047. +
  3048. + const std::string& version() const { return version_; }
  3049. + void set_version(const std::string& version) { version_ = version; }
  3050. +
  3051. + base::Time install_time;
  3052. + bool enabled;
  3053. +
  3054. + private:
  3055. + std::string name_;
  3056. + std::string description_;
  3057. + std::string version_;
  3058. + };
  3059. +};
  3060. +
  3061. +}
  3062. +
  3063. +#endif // USERSCRIPTS_BROWSER_USERSCRIPT_PREF_INFO_H_
  3064. \ No newline at end of file
  3065. diff --git a/components/user_scripts/browser/user_script_prefs.cc b/components/user_scripts/browser/user_script_prefs.cc
  3066. new file mode 100644
  3067. --- /dev/null
  3068. +++ b/components/user_scripts/browser/user_script_prefs.cc
  3069. @@ -0,0 +1,241 @@
  3070. +/*
  3071. + This file is part of Bromite.
  3072. +
  3073. + Bromite is free software: you can redistribute it and/or modify
  3074. + it under the terms of the GNU General Public License as published by
  3075. + the Free Software Foundation, either version 3 of the License, or
  3076. + (at your option) any later version.
  3077. +
  3078. + Bromite is distributed in the hope that it will be useful,
  3079. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  3080. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  3081. + GNU General Public License for more details.
  3082. +
  3083. + You should have received a copy of the GNU General Public License
  3084. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  3085. +*/
  3086. +
  3087. +#include <map>
  3088. +
  3089. +#include "base/values.h"
  3090. +#include "base/strings/string_number_conversions.h"
  3091. +#include "base/json/json_writer.h"
  3092. +
  3093. +#include "chrome/browser/browser_process.h"
  3094. +#include "chrome/browser/profiles/profile.h"
  3095. +#include "chrome/browser/profiles/profile_manager.h"
  3096. +
  3097. +#include "components/prefs/pref_service.h"
  3098. +#include "components/prefs/scoped_user_pref_update.h"
  3099. +#include "components/pref_registry/pref_registry_syncable.h"
  3100. +#include "user_script_prefs.h"
  3101. +#include "user_script_pref_info.h"
  3102. +#include "../common/user_script.h"
  3103. +
  3104. +namespace user_scripts {
  3105. +
  3106. +namespace {
  3107. +
  3108. +const char kUserScriptsEnabled[] = "userscripts.enabled";
  3109. +
  3110. +const char kUserScriptsList[] = "userscripts.scripts";
  3111. +const char kScriptIsEnabled[] = "enabled";
  3112. +const char kScriptName[] = "name";
  3113. +const char kScriptDescription[] = "description";
  3114. +const char kScriptVersion[] = "version";
  3115. +const char kScriptInstallTime[] = "install_time";
  3116. +
  3117. +class PrefUpdate : public DictionaryPrefUpdate {
  3118. + public:
  3119. + PrefUpdate(PrefService* service,
  3120. + const std::string& id,
  3121. + const std::string& path)
  3122. + : DictionaryPrefUpdate(service, path), id_(id) {}
  3123. +
  3124. + ~PrefUpdate() override = default;
  3125. +
  3126. + base::DictionaryValue* Get() override {
  3127. + base::DictionaryValue* dict = DictionaryPrefUpdate::Get();
  3128. + base::Value* dict_item =
  3129. + dict->FindKeyOfType(id_, base::Value::Type::DICTIONARY);
  3130. + if (!dict_item)
  3131. + dict_item = dict->SetKey(id_, base::Value(base::Value::Type::DICTIONARY));
  3132. + return static_cast<base::DictionaryValue*>(dict_item);
  3133. + }
  3134. +
  3135. + private:
  3136. + const std::string id_;
  3137. +
  3138. + DISALLOW_COPY_AND_ASSIGN(PrefUpdate);
  3139. +};
  3140. +
  3141. +bool GetInt64FromPref(const base::DictionaryValue* dict,
  3142. + const std::string& key,
  3143. + int64_t* value) {
  3144. + DCHECK(dict);
  3145. + std::string value_str;
  3146. + if (!dict->GetStringWithoutPathExpansion(key, &value_str)) {
  3147. + VLOG(2) << "Can't find key in local pref dictionary. Invalid key: " << key
  3148. + << ".";
  3149. + return false;
  3150. + }
  3151. +
  3152. + if (!base::StringToInt64(value_str, value)) {
  3153. + VLOG(2) << "Can't change string to int64_t. Invalid string value: "
  3154. + << value_str << ".";
  3155. + return false;
  3156. + }
  3157. +
  3158. + return true;
  3159. +}
  3160. +
  3161. +}
  3162. +
  3163. +UserScriptsPrefs::UserScriptsPrefs(
  3164. + PrefService* prefs)
  3165. + : prefs_(prefs) {
  3166. +}
  3167. +
  3168. +// static
  3169. +void UserScriptsPrefs::RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
  3170. + registry->RegisterBooleanPref(kUserScriptsEnabled, false);
  3171. + registry->RegisterDictionaryPref(kUserScriptsList);
  3172. +}
  3173. +
  3174. +bool UserScriptsPrefs::IsEnabled() {
  3175. + return prefs_->GetBoolean(kUserScriptsEnabled);
  3176. +}
  3177. +
  3178. +void UserScriptsPrefs::SetEnabled(bool enabled) {
  3179. + prefs_->SetBoolean(kUserScriptsEnabled, enabled);
  3180. +}
  3181. +
  3182. +void UserScriptsPrefs::CompareWithPrefs(UserScriptList& user_scripts) {
  3183. + if( IsEnabled() == false ) {
  3184. + LOG(INFO) << "UserScripts disabled";
  3185. + user_scripts.clear();
  3186. + return;
  3187. + }
  3188. +
  3189. + std::vector<std::string> all_scripts;
  3190. +
  3191. + auto it = user_scripts.begin();
  3192. + while (it != user_scripts.end())
  3193. + {
  3194. + std::string key = it->get()->key();
  3195. + all_scripts.push_back(key);
  3196. +
  3197. + std::unique_ptr<UserScriptsListPrefs::ScriptInfo> scriptInfo =
  3198. + UserScriptsPrefs::CreateScriptInfoFromPrefs(key);
  3199. +
  3200. + // add or update prefs
  3201. + scriptInfo->set_name(it->get()->name());
  3202. + scriptInfo->set_description(it->get()->description());
  3203. + scriptInfo->set_version(it->get()->version());
  3204. +
  3205. + // LOG(INFO) << "---UserScriptsPrefs::CompareWithPrefs name " << scriptInfo->name();
  3206. +
  3207. + PrefUpdate update(prefs_, key, kUserScriptsList);
  3208. + base::DictionaryValue* script_dict = update.Get();
  3209. +
  3210. + script_dict->SetString(kScriptName, scriptInfo->name());
  3211. + script_dict->SetString(kScriptDescription, scriptInfo->description());
  3212. + script_dict->SetBoolean(kScriptIsEnabled, scriptInfo->enabled);
  3213. + script_dict->SetString(kScriptVersion, scriptInfo->version());
  3214. +
  3215. + std::string install_time_str =
  3216. + base::NumberToString(scriptInfo->install_time.ToInternalValue());
  3217. + script_dict->SetString(kScriptInstallTime, install_time_str);
  3218. +
  3219. + if (!scriptInfo->enabled) {
  3220. + // LOG(INFO) << "---UserScriptsPrefs::CompareWithPrefs removed " << key;
  3221. + it = user_scripts.erase(it);
  3222. + } else {
  3223. + // LOG(INFO) << "---UserScriptsPrefs::CompareWithPrefs using " << key;
  3224. + ++it;
  3225. + }
  3226. + }
  3227. +
  3228. + // remove script from prefs if no more present
  3229. + std::vector<std::string> all_scripts_to_remove;
  3230. + const base::DictionaryValue* dict =
  3231. + prefs_->GetDictionary(kUserScriptsList);
  3232. + for (base::DictionaryValue::Iterator script_it(*dict); !script_it.IsAtEnd();
  3233. + script_it.Advance()) {
  3234. + const std::string& key = script_it.key();
  3235. +
  3236. + if (std::find(all_scripts.begin(), all_scripts.end(), key) == all_scripts.end()) {
  3237. + all_scripts_to_remove.push_back(key);
  3238. + }
  3239. + }
  3240. +
  3241. + DictionaryPrefUpdate update(prefs_, kUserScriptsList);
  3242. + base::DictionaryValue* const update_dict = update.Get();
  3243. + for (auto key : all_scripts_to_remove) {
  3244. + update_dict->RemoveKey(key);
  3245. + }
  3246. +
  3247. + return;
  3248. +}
  3249. +
  3250. +std::string UserScriptsPrefs::GetScriptsInfo() {
  3251. + std::string json_string;
  3252. +
  3253. + const base::DictionaryValue* dict =
  3254. + prefs_->GetDictionary(kUserScriptsList);
  3255. +
  3256. + if (dict) {
  3257. + base::JSONWriter::WriteWithOptions(
  3258. + *dict, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json_string);
  3259. + base::TrimWhitespaceASCII(json_string, base::TRIM_ALL, &json_string);
  3260. + }
  3261. +
  3262. + return json_string;
  3263. +}
  3264. +
  3265. +std::unique_ptr<UserScriptsListPrefs::ScriptInfo> UserScriptsPrefs::CreateScriptInfoFromPrefs(
  3266. + const std::string& script_id) const {
  3267. +
  3268. + auto scriptInfo = std::make_unique<UserScriptsListPrefs::ScriptInfo>(
  3269. + script_id, "", base::Time::Now(), false);
  3270. +
  3271. + const base::DictionaryValue* scripts =
  3272. + prefs_->GetDictionary(kUserScriptsList);
  3273. + if (!scripts)
  3274. + return scriptInfo;
  3275. +
  3276. + const base::DictionaryValue* script = static_cast<const base::DictionaryValue*>(
  3277. + scripts->FindDictKey(script_id));
  3278. + if (!script)
  3279. + return scriptInfo;
  3280. +
  3281. + const std::string* name = script->FindStringKey(kScriptName);
  3282. + const std::string* description = script->FindStringKey(kScriptDescription);
  3283. + const std::string* version = script->FindStringKey(kScriptVersion);
  3284. +
  3285. + scriptInfo->set_name( name ? *name : "no name" );
  3286. + scriptInfo->set_description( description ? *description : "no description" );
  3287. + scriptInfo->set_version( version ? *version : "no version" );
  3288. + scriptInfo->enabled = script->FindBoolKey(kScriptIsEnabled).value_or(false);
  3289. +
  3290. + int64_t time_interval = 0;
  3291. + if (GetInt64FromPref(script, kScriptInstallTime, &time_interval)) {
  3292. + scriptInfo->install_time = base::Time::FromInternalValue(time_interval);
  3293. + }
  3294. +
  3295. + return scriptInfo;
  3296. +}
  3297. +
  3298. +void UserScriptsPrefs::RemoveScriptFromPrefs(const std::string& script_id) {
  3299. + DictionaryPrefUpdate update(prefs_, kUserScriptsList);
  3300. + base::DictionaryValue* const update_dict = update.Get();
  3301. + update_dict->RemoveKey(script_id);
  3302. +}
  3303. +
  3304. +void UserScriptsPrefs::SetScriptEnabled(const std::string& script_id, bool is_enabled) {
  3305. + PrefUpdate update(prefs_, script_id, kUserScriptsList);
  3306. + base::DictionaryValue* script_dict = update.Get();
  3307. + script_dict->SetBoolean(kScriptIsEnabled, is_enabled);
  3308. +}
  3309. +
  3310. +}
  3311. diff --git a/components/user_scripts/browser/user_script_prefs.h b/components/user_scripts/browser/user_script_prefs.h
  3312. new file mode 100644
  3313. --- /dev/null
  3314. +++ b/components/user_scripts/browser/user_script_prefs.h
  3315. @@ -0,0 +1,55 @@
  3316. +/*
  3317. + This file is part of Bromite.
  3318. +
  3319. + Bromite is free software: you can redistribute it and/or modify
  3320. + it under the terms of the GNU General Public License as published by
  3321. + the Free Software Foundation, either version 3 of the License, or
  3322. + (at your option) any later version.
  3323. +
  3324. + Bromite is distributed in the hope that it will be useful,
  3325. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  3326. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  3327. + GNU General Public License for more details.
  3328. +
  3329. + You should have received a copy of the GNU General Public License
  3330. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  3331. +*/
  3332. +
  3333. +#ifndef USERSCRIPTS_BROWSER_USERSCRIPT_PREFS_H_
  3334. +#define USERSCRIPTS_BROWSER_USERSCRIPT_PREFS_H_
  3335. +
  3336. +#include "content/public/browser/browser_context.h"
  3337. +#include "components/prefs/pref_service.h"
  3338. +#include "components/pref_registry/pref_registry_syncable.h"
  3339. +
  3340. +#include "user_script_pref_info.h"
  3341. +#include "../common/user_script.h"
  3342. +
  3343. +namespace user_scripts {
  3344. +
  3345. +class UserScriptsPrefs {
  3346. + public:
  3347. + UserScriptsPrefs(
  3348. + PrefService* prefs);
  3349. +
  3350. + static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
  3351. +
  3352. + bool IsEnabled();
  3353. + void SetEnabled(bool enabled);
  3354. +
  3355. + void CompareWithPrefs(UserScriptList& user_scripts);
  3356. +
  3357. + std::string GetScriptsInfo();
  3358. + void RemoveScriptFromPrefs(const std::string& script_id);
  3359. + void SetScriptEnabled(const std::string& script_id, bool is_enabled);
  3360. +
  3361. + std::unique_ptr<UserScriptsListPrefs::ScriptInfo> CreateScriptInfoFromPrefs(
  3362. + const std::string& script_id) const;
  3363. +
  3364. + private:
  3365. + PrefService* prefs_;
  3366. +};
  3367. +
  3368. +}
  3369. +
  3370. +#endif // USERSCRIPTS_BROWSER_USERSCRIPT_PREFS_H_
  3371. \ No newline at end of file
  3372. diff --git a/components/user_scripts/browser/userscripts_browser_client.cc b/components/user_scripts/browser/userscripts_browser_client.cc
  3373. new file mode 100755
  3374. --- /dev/null
  3375. +++ b/components/user_scripts/browser/userscripts_browser_client.cc
  3376. @@ -0,0 +1,79 @@
  3377. +/*
  3378. + This file is part of Bromite.
  3379. +
  3380. + Bromite is free software: you can redistribute it and/or modify
  3381. + it under the terms of the GNU General Public License as published by
  3382. + the Free Software Foundation, either version 3 of the License, or
  3383. + (at your option) any later version.
  3384. +
  3385. + Bromite is distributed in the hope that it will be useful,
  3386. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  3387. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  3388. + GNU General Public License for more details.
  3389. +
  3390. + You should have received a copy of the GNU General Public License
  3391. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  3392. +*/
  3393. +
  3394. +#include "userscripts_browser_client.h"
  3395. +
  3396. +#include "base/logging.h"
  3397. +
  3398. +#include "chrome/browser/browser_process.h"
  3399. +
  3400. +#include "chrome/browser/profiles/profile.h"
  3401. +#include "chrome/browser/profiles/profile_manager.h"
  3402. +
  3403. +#include "../common/user_scripts_features.h"
  3404. +#include "user_script_loader.h"
  3405. +#include "file_task_runner.h"
  3406. +#include "user_script_prefs.h"
  3407. +
  3408. +namespace user_scripts {
  3409. +
  3410. +namespace {
  3411. +
  3412. +// remember: was ExtensionsBrowserClient
  3413. +UserScriptsBrowserClient* g_userscripts_browser_client = NULL;
  3414. +
  3415. +} // namespace
  3416. +
  3417. +UserScriptsBrowserClient::UserScriptsBrowserClient() {}
  3418. +
  3419. +UserScriptsBrowserClient::~UserScriptsBrowserClient() = default;
  3420. +
  3421. +// static
  3422. +UserScriptsBrowserClient* UserScriptsBrowserClient::GetInstance() {
  3423. + // only for browser process
  3424. + if(!g_browser_process)
  3425. + return NULL;
  3426. +
  3427. + if (base::FeatureList::IsEnabled(features::kEnableUserScripts) == false)
  3428. + return NULL;
  3429. +
  3430. + // singleton
  3431. + if(g_userscripts_browser_client)
  3432. + return g_userscripts_browser_client;
  3433. +
  3434. + // make file task runner
  3435. + GetUserScriptsFileTaskRunner().get();
  3436. +
  3437. + // new instance singleton
  3438. + g_userscripts_browser_client = new UserScriptsBrowserClient();
  3439. +
  3440. + return g_userscripts_browser_client;
  3441. +}
  3442. +
  3443. +void UserScriptsBrowserClient::SetProfile(content::BrowserContext* context) {
  3444. + browser_context_ = context;
  3445. +
  3446. + prefs_ =
  3447. + std::make_unique<user_scripts::UserScriptsPrefs>(
  3448. + static_cast<Profile*>(context)->GetPrefs());
  3449. +
  3450. + userscript_loader_ =
  3451. + std::make_unique<user_scripts::UserScriptLoader>(browser_context_, prefs_.get());
  3452. + userscript_loader_->SetReady(true);
  3453. +}
  3454. +
  3455. +} // namespace user_scripts
  3456. diff --git a/components/user_scripts/browser/userscripts_browser_client.h b/components/user_scripts/browser/userscripts_browser_client.h
  3457. new file mode 100755
  3458. --- /dev/null
  3459. +++ b/components/user_scripts/browser/userscripts_browser_client.h
  3460. @@ -0,0 +1,62 @@
  3461. +/*
  3462. + This file is part of Bromite.
  3463. +
  3464. + Bromite is free software: you can redistribute it and/or modify
  3465. + it under the terms of the GNU General Public License as published by
  3466. + the Free Software Foundation, either version 3 of the License, or
  3467. + (at your option) any later version.
  3468. +
  3469. + Bromite is distributed in the hope that it will be useful,
  3470. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  3471. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  3472. + GNU General Public License for more details.
  3473. +
  3474. + You should have received a copy of the GNU General Public License
  3475. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  3476. +*/
  3477. +
  3478. +#ifndef USERSCRIPTS_BROWSER_USERSCRIPTS_BROWSER_CLIENT_H_
  3479. +#define USERSCRIPTS_BROWSER_USERSCRIPTS_BROWSER_CLIENT_H_
  3480. +
  3481. +#include <memory>
  3482. +#include <string>
  3483. +#include <vector>
  3484. +
  3485. +#include "content/public/browser/browser_context.h"
  3486. +
  3487. +#include "../common/user_script.h"
  3488. +#include "user_script_loader.h"
  3489. +#include "user_script_prefs.h"
  3490. +
  3491. +namespace user_scripts {
  3492. +
  3493. +class UserScriptsBrowserClient {
  3494. + public:
  3495. + UserScriptsBrowserClient();
  3496. + UserScriptsBrowserClient(const UserScriptsBrowserClient&) = delete;
  3497. + UserScriptsBrowserClient& operator=(const UserScriptsBrowserClient&) = delete;
  3498. + virtual ~UserScriptsBrowserClient();
  3499. +
  3500. + // Returns the single instance of |this|.
  3501. + static UserScriptsBrowserClient* GetInstance();
  3502. +
  3503. + void SetProfile(content::BrowserContext* context);
  3504. +
  3505. + user_scripts::UserScriptsPrefs* GetPrefs() {
  3506. + return prefs_.get();
  3507. + }
  3508. +
  3509. + user_scripts::UserScriptLoader* GetLoader() {
  3510. + return userscript_loader_.get();
  3511. + }
  3512. +
  3513. + private:
  3514. + std::unique_ptr<UserScriptList> scripts_;
  3515. + content::BrowserContext* browser_context_;
  3516. + std::unique_ptr<user_scripts::UserScriptsPrefs> prefs_;
  3517. + std::unique_ptr<user_scripts::UserScriptLoader> userscript_loader_;
  3518. +};
  3519. +
  3520. +} // namespace extensions
  3521. +
  3522. +#endif // USERSCRIPTS_BROWSER_USERSCRIPTS_BROWSER_CLIENT_H_
  3523. diff --git a/components/user_scripts/common/BUILD.gn b/components/user_scripts/common/BUILD.gn
  3524. new file mode 100755
  3525. --- /dev/null
  3526. +++ b/components/user_scripts/common/BUILD.gn
  3527. @@ -0,0 +1,52 @@
  3528. +# Copyright 2014 The Chromium Authors. All rights reserved.
  3529. +# Use of this source code is governed by a BSD-style license that can be
  3530. +# found in the LICENSE file.
  3531. +
  3532. +import("//build/config/features.gni")
  3533. +import("//mojo/public/tools/bindings/mojom.gni")
  3534. +
  3535. +static_library("common") {
  3536. + sources = [
  3537. + "user_scripts_features.cc",
  3538. + "user_scripts_features.h",
  3539. + "constants.h",
  3540. + "host_id.cc",
  3541. + "host_id.h",
  3542. + "script_constants.h",
  3543. + "url_pattern_set.cc",
  3544. + "url_pattern_set.h",
  3545. + "url_pattern.cc",
  3546. + "url_pattern.h",
  3547. + "user_script.cc",
  3548. + "user_script.h",
  3549. + "view_type.cc",
  3550. + "view_type.h",
  3551. + "extension_messages.cc",
  3552. + "extension_messages.h",
  3553. + "extension_message_generator.cc",
  3554. + "extension_message_generator.h",
  3555. + ]
  3556. +
  3557. + configs += [
  3558. + "//build/config:precompiled_headers",
  3559. +
  3560. + # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
  3561. + "//build/config/compiler:no_size_t_to_int_warning",
  3562. + "//build/config/compiler:wexit_time_destructors",
  3563. + ]
  3564. +
  3565. + public_deps = [
  3566. + "//components/services/app_service/public/cpp:app_file_handling",
  3567. + "//content/public/common",
  3568. + "//ipc",
  3569. + "//skia",
  3570. + ]
  3571. +
  3572. + deps = [
  3573. + "//base",
  3574. + "//components/url_formatter",
  3575. + "//components/url_matcher",
  3576. + "//components/version_info",
  3577. + "//crypto",
  3578. + ]
  3579. +}
  3580. diff --git a/components/user_scripts/common/constants.h b/components/user_scripts/common/constants.h
  3581. new file mode 100755
  3582. --- /dev/null
  3583. +++ b/components/user_scripts/common/constants.h
  3584. @@ -0,0 +1,21 @@
  3585. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  3586. +// Use of this source code is governed by a BSD-style license that can be
  3587. +// found in the LICENSE file.
  3588. +
  3589. +#ifndef USERSCRIPTS_COMMON_CONSTANTS_H_
  3590. +#define USERSCRIPTS_COMMON_CONSTANTS_H_
  3591. +
  3592. +#include "base/files/file_path.h"
  3593. +#include "base/strings/string_piece_forward.h"
  3594. +#include "components/services/app_service/public/mojom/types.mojom.h"
  3595. +#include "components/version_info/channel.h"
  3596. +#include "ui/base/layout.h"
  3597. +
  3598. +namespace user_scripts {
  3599. +
  3600. +// The origin of injected CSS.
  3601. +enum CSSOrigin { /*CSS_ORIGIN_AUTHOR,*/ CSS_ORIGIN_USER };
  3602. +
  3603. +} // namespace user_scripts
  3604. +
  3605. +#endif // USERSCRIPTS_COMMON_CONSTANTS_H_
  3606. diff --git a/components/user_scripts/common/error_utils.cc b/components/user_scripts/common/error_utils.cc
  3607. new file mode 100755
  3608. --- /dev/null
  3609. +++ b/components/user_scripts/common/error_utils.cc
  3610. @@ -0,0 +1,54 @@
  3611. +// Copyright (c) 2011 The Chromium Authors. All rights reserved.
  3612. +// Use of this source code is governed by a BSD-style license that can be
  3613. +// found in the LICENSE file.
  3614. +
  3615. +#include "error_utils.h"
  3616. +
  3617. +#include <initializer_list>
  3618. +
  3619. +#include "base/check_op.h"
  3620. +#include "base/strings/string_tokenizer.h"
  3621. +#include "base/strings/string_util.h"
  3622. +#include "base/strings/utf_string_conversions.h"
  3623. +
  3624. +namespace user_scripts {
  3625. +
  3626. +namespace {
  3627. +
  3628. +std::string FormatErrorMessageInternal(
  3629. + base::StringPiece format,
  3630. + std::initializer_list<base::StringPiece> args) {
  3631. + std::string format_str = format.as_string();
  3632. + base::StringTokenizer tokenizer(format_str, "*");
  3633. + tokenizer.set_options(base::StringTokenizer::RETURN_DELIMS);
  3634. +
  3635. + std::vector<base::StringPiece> result_pieces;
  3636. + auto* args_it = args.begin();
  3637. + while (tokenizer.GetNext()) {
  3638. + if (!tokenizer.token_is_delim()) {
  3639. + result_pieces.push_back(tokenizer.token_piece());
  3640. + continue;
  3641. + }
  3642. +
  3643. + CHECK_NE(args_it, args.end())
  3644. + << "More placeholders (*) than substitutions.";
  3645. +
  3646. + // Substitute the argument.
  3647. + result_pieces.push_back(*args_it);
  3648. + args_it++;
  3649. + }
  3650. +
  3651. + // Not all substitutions were consumed.
  3652. + CHECK_EQ(args_it, args.end()) << "Fewer placeholders (*) than substitutions.";
  3653. +
  3654. + return base::JoinString(result_pieces, "" /* separator */);
  3655. +}
  3656. +
  3657. +} // namespace
  3658. +
  3659. +std::string ErrorUtils::FormatErrorMessage(base::StringPiece format,
  3660. + base::StringPiece s1) {
  3661. + return FormatErrorMessageInternal(format, {s1});
  3662. +}
  3663. +
  3664. +} // namespace user_scripts
  3665. diff --git a/components/user_scripts/common/error_utils.h b/components/user_scripts/common/error_utils.h
  3666. new file mode 100755
  3667. --- /dev/null
  3668. +++ b/components/user_scripts/common/error_utils.h
  3669. @@ -0,0 +1,25 @@
  3670. +// Copyright (c) 2011 The Chromium Authors. All rights reserved.
  3671. +// Use of this source code is governed by a BSD-style license that can be
  3672. +// found in the LICENSE file.
  3673. +
  3674. +#ifndef USERSCRIPTS_COMMON_ERROR_UTILS_H_
  3675. +#define USERSCRIPTS_COMMON_ERROR_UTILS_H_
  3676. +
  3677. +#include <string>
  3678. +
  3679. +#include "base/strings/string16.h"
  3680. +#include "base/strings/string_piece.h"
  3681. +
  3682. +namespace user_scripts {
  3683. +
  3684. +class ErrorUtils {
  3685. + public:
  3686. + // Creates an error messages from a pattern.
  3687. + static std::string FormatErrorMessage(base::StringPiece format,
  3688. + base::StringPiece s1);
  3689. +
  3690. +};
  3691. +
  3692. +} // namespace extensions
  3693. +
  3694. +#endif // USERSCRIPTS_COMMON_ERROR_UTILS_H_
  3695. diff --git a/components/user_scripts/common/extension_message_generator.cc b/components/user_scripts/common/extension_message_generator.cc
  3696. new file mode 100755
  3697. --- /dev/null
  3698. +++ b/components/user_scripts/common/extension_message_generator.cc
  3699. @@ -0,0 +1,29 @@
  3700. +// Copyright 2014 The Chromium Authors. All rights reserved.
  3701. +// Use of this source code is governed by a BSD-style license that can be
  3702. +// found in the LICENSE file.
  3703. +
  3704. +// Get basic type definitions.
  3705. +#define IPC_MESSAGE_IMPL
  3706. +#include "components/user_scripts/common/extension_message_generator.h"
  3707. +
  3708. +// Generate constructors.
  3709. +#include "ipc/struct_constructor_macros.h"
  3710. +#include "components/user_scripts/common/extension_message_generator.h"
  3711. +
  3712. +// Generate param traits write methods.
  3713. +#include "ipc/param_traits_write_macros.h"
  3714. +namespace IPC {
  3715. +#include "components/user_scripts/common/extension_message_generator.h"
  3716. +} // namespace IPC
  3717. +
  3718. +// Generate param traits read methods.
  3719. +#include "ipc/param_traits_read_macros.h"
  3720. +namespace IPC {
  3721. +#include "components/user_scripts/common/extension_message_generator.h"
  3722. +} // namespace IPC
  3723. +
  3724. +// Generate param traits log methods.
  3725. +#include "ipc/param_traits_log_macros.h"
  3726. +namespace IPC {
  3727. +#include "components/user_scripts/common/extension_message_generator.h"
  3728. +} // namespace IPC
  3729. diff --git a/components/user_scripts/common/extension_message_generator.h b/components/user_scripts/common/extension_message_generator.h
  3730. new file mode 100755
  3731. --- /dev/null
  3732. +++ b/components/user_scripts/common/extension_message_generator.h
  3733. @@ -0,0 +1,11 @@
  3734. +// Copyright 2014 The Chromium Authors. All rights reserved.
  3735. +// Use of this source code is governed by a BSD-style license that can be
  3736. +// found in the LICENSE file.
  3737. +
  3738. +// Multiply-included file, hence no include guard.
  3739. +
  3740. +#undef EXTENSIONS_COMMON_EXTENSION_MESSAGES_H_
  3741. +#include "extension_messages.h"
  3742. +#ifndef EXTENSIONS_COMMON_EXTENSION_MESSAGES_H_
  3743. +#error "Failed to include header extension_messages.h"
  3744. +#endif
  3745. diff --git a/components/user_scripts/common/extension_messages.cc b/components/user_scripts/common/extension_messages.cc
  3746. new file mode 100755
  3747. --- /dev/null
  3748. +++ b/components/user_scripts/common/extension_messages.cc
  3749. @@ -0,0 +1,40 @@
  3750. +// Copyright 2014 The Chromium Authors. All rights reserved.
  3751. +// Use of this source code is governed by a BSD-style license that can be
  3752. +// found in the LICENSE file.
  3753. +
  3754. +#include "extension_messages.h"
  3755. +
  3756. +#include <stddef.h>
  3757. +
  3758. +#include <memory>
  3759. +#include <utility>
  3760. +
  3761. +#include "content/public/common/common_param_traits.h"
  3762. +
  3763. +namespace IPC {
  3764. +
  3765. +void ParamTraits<HostID>::Write(base::Pickle* m, const param_type& p) {
  3766. + WriteParam(m, p.type());
  3767. + WriteParam(m, p.id());
  3768. +}
  3769. +
  3770. +bool ParamTraits<HostID>::Read(const base::Pickle* m,
  3771. + base::PickleIterator* iter,
  3772. + param_type* r) {
  3773. + HostID::HostType type;
  3774. + std::string id;
  3775. + if (!ReadParam(m, iter, &type))
  3776. + return false;
  3777. + if (!ReadParam(m, iter, &id))
  3778. + return false;
  3779. + *r = HostID(type, id);
  3780. + return true;
  3781. +}
  3782. +
  3783. +void ParamTraits<HostID>::Log(
  3784. + const param_type& p, std::string* l) {
  3785. + LogParam(p.type(), l);
  3786. + LogParam(p.id(), l);
  3787. +}
  3788. +
  3789. +} // namespace IPC
  3790. diff --git a/components/user_scripts/common/extension_messages.h b/components/user_scripts/common/extension_messages.h
  3791. new file mode 100755
  3792. --- /dev/null
  3793. +++ b/components/user_scripts/common/extension_messages.h
  3794. @@ -0,0 +1,70 @@
  3795. +// Copyright 2014 The Chromium Authors. All rights reserved.
  3796. +// Use of this source code is governed by a BSD-style license that can be
  3797. +// found in the LICENSE file.
  3798. +
  3799. +// IPC messages for extensions.
  3800. +
  3801. +#ifndef EXTENSIONS_COMMON_EXTENSION_MESSAGES_H_
  3802. +#define EXTENSIONS_COMMON_EXTENSION_MESSAGES_H_
  3803. +
  3804. +#include <stdint.h>
  3805. +
  3806. +#include <map>
  3807. +#include <memory>
  3808. +#include <set>
  3809. +#include <string>
  3810. +#include <vector>
  3811. +
  3812. +#include "base/macros.h"
  3813. +#include "base/memory/read_only_shared_memory_region.h"
  3814. +#include "base/values.h"
  3815. +#include "content/public/common/common_param_traits.h"
  3816. +#include "constants.h"
  3817. +#include "host_id.h"
  3818. +#include "ipc/ipc_message_macros.h"
  3819. +#include "url/gurl.h"
  3820. +#include "url/origin.h"
  3821. +
  3822. +#define IPC_MESSAGE_START ExtensionMsgStart
  3823. +
  3824. +IPC_ENUM_TRAITS_MAX_VALUE(HostID::HostType, HostID::HOST_TYPE_LAST)
  3825. +
  3826. +// Singly-included section for custom IPC traits.
  3827. +#ifndef INTERNAL_EXTENSIONS_COMMON_EXTENSION_MESSAGES_H_
  3828. +#define INTERNAL_EXTENSIONS_COMMON_EXTENSION_MESSAGES_H_
  3829. +
  3830. +namespace IPC {
  3831. +
  3832. +template <>
  3833. +struct ParamTraits<HostID> {
  3834. + typedef HostID param_type;
  3835. + static void Write(base::Pickle* m, const param_type& p);
  3836. + static bool Read(const base::Pickle* m,
  3837. + base::PickleIterator* iter,
  3838. + param_type* r);
  3839. + static void Log(const param_type& p, std::string* l);
  3840. +};
  3841. +
  3842. +
  3843. +} // namespace IPC
  3844. +
  3845. +#endif // INTERNAL_EXTENSIONS_COMMON_EXTENSION_MESSAGES_H_
  3846. +
  3847. +// Notification that the user scripts have been updated. It has one
  3848. +// ReadOnlySharedMemoryRegion argument consisting of the pickled script data.
  3849. +// This memory region is valid in the context of the renderer.
  3850. +// If |owner| is not empty, then the shared memory handle refers to |owner|'s
  3851. +// programmatically-defined scripts. Otherwise, the handle refers to all
  3852. +// hosts' statically defined scripts. So far, only extension-hosts support
  3853. +// statically defined scripts; WebUI-hosts don't.
  3854. +// If |changed_hosts| is not empty, only the host in that set will
  3855. +// be updated. Otherwise, all hosts that have scripts in the shared memory
  3856. +// region will be updated. Note that the empty set => all hosts case is not
  3857. +// supported for per-extension programmatically-defined script regions; in such
  3858. +// regions, the owner is expected to list itself as the only changed host.
  3859. +// If |whitelisted_only| is true, this process should only run whitelisted
  3860. +// scripts and not all user scripts.
  3861. +IPC_MESSAGE_CONTROL1(ExtensionMsg_UpdateUserScripts,
  3862. + base::ReadOnlySharedMemoryRegion)
  3863. +
  3864. +#endif // EXTENSIONS_COMMON_EXTENSION_MESSAGES_H_
  3865. diff --git a/components/user_scripts/common/host_id.cc b/components/user_scripts/common/host_id.cc
  3866. new file mode 100755
  3867. --- /dev/null
  3868. +++ b/components/user_scripts/common/host_id.cc
  3869. @@ -0,0 +1,31 @@
  3870. +// Copyright 2015 The Chromium Authors. All rights reserved.
  3871. +// Use of this source code is governed by a BSD-style license that can be
  3872. +// found in the LICENSE file.
  3873. +
  3874. +#include "host_id.h"
  3875. +
  3876. +#include <tuple>
  3877. +
  3878. +HostID::HostID()
  3879. + : type_(HostType::EXTENSIONS) {
  3880. +}
  3881. +
  3882. +HostID::HostID(HostType type, const std::string& id)
  3883. + : type_(type), id_(id) {
  3884. +}
  3885. +
  3886. +HostID::HostID(const HostID& host_id)
  3887. + : type_(host_id.type()),
  3888. + id_(host_id.id()) {
  3889. +}
  3890. +
  3891. +HostID::~HostID() {
  3892. +}
  3893. +
  3894. +bool HostID::operator<(const HostID& host_id) const {
  3895. + return std::tie(type_, id_) < std::tie(host_id.type_, host_id.id_);
  3896. +}
  3897. +
  3898. +bool HostID::operator==(const HostID& host_id) const {
  3899. + return type_ == host_id.type_ && id_ == host_id.id_;
  3900. +}
  3901. diff --git a/components/user_scripts/common/host_id.h b/components/user_scripts/common/host_id.h
  3902. new file mode 100755
  3903. --- /dev/null
  3904. +++ b/components/user_scripts/common/host_id.h
  3905. @@ -0,0 +1,35 @@
  3906. +// Copyright 2015 The Chromium Authors. All rights reserved.
  3907. +// Use of this source code is governed by a BSD-style license that can be
  3908. +// found in the LICENSE file.
  3909. +
  3910. +#ifndef EXTENSIONS_COMMON_HOST_ID_H_
  3911. +#define EXTENSIONS_COMMON_HOST_ID_H_
  3912. +
  3913. +#include <string>
  3914. +
  3915. +// IDs of hosts who own user scripts.
  3916. +// A HostID is immutable after creation.
  3917. +struct HostID {
  3918. + enum HostType { EXTENSIONS, WEBUI, HOST_TYPE_LAST = WEBUI };
  3919. +
  3920. + HostID();
  3921. + HostID(HostType type, const std::string& id);
  3922. + HostID(const HostID& host_id);
  3923. + ~HostID();
  3924. +
  3925. + bool operator<(const HostID& host_id) const;
  3926. + bool operator==(const HostID& host_id) const;
  3927. +
  3928. + HostType type() const { return type_; }
  3929. + const std::string& id() const { return id_; }
  3930. +
  3931. + private:
  3932. + // The type of the host.
  3933. + HostType type_;
  3934. +
  3935. + // Similar to extension_id, host_id is a unique indentifier for a host,
  3936. + // e.g., an Extension or WebUI.
  3937. + std::string id_;
  3938. +};
  3939. +
  3940. +#endif // EXTENSIONS_COMMON_HOST_ID_H_
  3941. diff --git a/components/user_scripts/common/script_constants.h b/components/user_scripts/common/script_constants.h
  3942. new file mode 100755
  3943. --- /dev/null
  3944. +++ b/components/user_scripts/common/script_constants.h
  3945. @@ -0,0 +1,33 @@
  3946. +// Copyright 2020 The Chromium Authors. All rights reserved.
  3947. +// Use of this source code is governed by a BSD-style license that can be
  3948. +// found in the LICENSE file.
  3949. +
  3950. +#ifndef EXTENSIONS_COMMON_SCRIPT_CONSTANTS_H_
  3951. +#define EXTENSIONS_COMMON_SCRIPT_CONSTANTS_H_
  3952. +
  3953. +namespace user_scripts {
  3954. +
  3955. +// Whether to fall back to matching the origin for frames where the URL
  3956. +// cannot be matched directly, such as those with about: or data: schemes.
  3957. +enum class MatchOriginAsFallbackBehavior {
  3958. + // Never fall back on the origin; this means scripts will never match on
  3959. + // these frames.
  3960. + kNever,
  3961. + // Match the origin only for about:-scheme frames, and then climb the frame
  3962. + // tree to find an appropriate ancestor to get a full URL (including path).
  3963. + // This is for supporting the "match_about_blank" key.
  3964. + // TODO(devlin): I wonder if we could simplify this to be "MatchForAbout",
  3965. + // and not worry about climbing the frame tree. It would be a behavior
  3966. + // change, but I wonder how many extensions it would impact in practice.
  3967. + kMatchForAboutSchemeAndClimbTree,
  3968. + // Match the origin as a fallback whenever applicable. This won't have a
  3969. + // corresponding path.
  3970. + kAlways,
  3971. +};
  3972. +
  3973. +// TODO(devlin): Move the other non-UserScript-specific constants like
  3974. +// RunLocation and InjectionType from UserScript into here.
  3975. +
  3976. +} // namespace extensions
  3977. +
  3978. +#endif // EXTENSIONS_COMMON_SCRIPT_CONSTANTS_H_
  3979. diff --git a/components/user_scripts/common/url_pattern.cc b/components/user_scripts/common/url_pattern.cc
  3980. new file mode 100755
  3981. --- /dev/null
  3982. +++ b/components/user_scripts/common/url_pattern.cc
  3983. @@ -0,0 +1,807 @@
  3984. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  3985. +// Use of this source code is governed by a BSD-style license that can be
  3986. +// found in the LICENSE file.
  3987. +
  3988. +#include "url_pattern.h"
  3989. +
  3990. +#include <stddef.h>
  3991. +
  3992. +#include <ostream>
  3993. +
  3994. +#include "base/logging.h"
  3995. +#include "base/stl_util.h"
  3996. +#include "base/strings/pattern.h"
  3997. +#include "base/strings/strcat.h"
  3998. +#include "base/strings/string_number_conversions.h"
  3999. +#include "base/strings/string_split.h"
  4000. +#include "base/strings/string_util.h"
  4001. +#include "base/strings/stringprintf.h"
  4002. +#include "content/public/common/url_constants.h"
  4003. +#include "constants.h"
  4004. +#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
  4005. +#include "net/base/url_util.h"
  4006. +#include "url/gurl.h"
  4007. +#include "url/url_util.h"
  4008. +
  4009. +const char URLPattern::kAllUrlsPattern[] = "<all_urls>";
  4010. +
  4011. +namespace {
  4012. +
  4013. +// TODO(aa): What about more obscure schemes like javascript: ?
  4014. +// Note: keep this array in sync with kValidSchemeMasks.
  4015. +const char* const kValidSchemes[] = {
  4016. + url::kHttpScheme, url::kHttpsScheme,
  4017. + url::kFileScheme, url::kFtpScheme,
  4018. + /*content::kChromeUIScheme,*/ /*extensions::kExtensionScheme,*/
  4019. + url::kFileSystemScheme, url::kWsScheme,
  4020. + url::kWssScheme, url::kDataScheme,
  4021. +};
  4022. +
  4023. +const int kValidSchemeMasks[] = {
  4024. + URLPattern::SCHEME_HTTP, URLPattern::SCHEME_HTTPS,
  4025. + URLPattern::SCHEME_FILE, URLPattern::SCHEME_FTP,
  4026. + /*URLPattern::SCHEME_CHROMEUI,*/ /*URLPattern::SCHEME_EXTENSION,*/
  4027. + URLPattern::SCHEME_FILESYSTEM, URLPattern::SCHEME_WS,
  4028. + URLPattern::SCHEME_WSS, URLPattern::SCHEME_DATA,
  4029. +};
  4030. +
  4031. +static_assert(base::size(kValidSchemes) == base::size(kValidSchemeMasks),
  4032. + "must keep these arrays in sync");
  4033. +
  4034. +const char kParseSuccess[] = "Success.";
  4035. +const char kParseErrorMissingSchemeSeparator[] = "Missing scheme separator.";
  4036. +const char kParseErrorInvalidScheme[] = "Invalid scheme.";
  4037. +const char kParseErrorWrongSchemeType[] = "Wrong scheme type.";
  4038. +const char kParseErrorEmptyHost[] = "Host can not be empty.";
  4039. +const char kParseErrorInvalidHostWildcard[] = "Invalid host wildcard.";
  4040. +const char kParseErrorEmptyPath[] = "Empty path.";
  4041. +const char kParseErrorInvalidPort[] = "Invalid port.";
  4042. +const char kParseErrorInvalidHost[] = "Invalid host.";
  4043. +
  4044. +// Message explaining each URLPattern::ParseResult.
  4045. +const char* const kParseResultMessages[] = {
  4046. + kParseSuccess,
  4047. + kParseErrorMissingSchemeSeparator,
  4048. + kParseErrorInvalidScheme,
  4049. + kParseErrorWrongSchemeType,
  4050. + kParseErrorEmptyHost,
  4051. + kParseErrorInvalidHostWildcard,
  4052. + kParseErrorEmptyPath,
  4053. + kParseErrorInvalidPort,
  4054. + kParseErrorInvalidHost,
  4055. +};
  4056. +
  4057. +static_assert(static_cast<int>(URLPattern::ParseResult::kNumParseResults) ==
  4058. + base::size(kParseResultMessages),
  4059. + "must add message for each parse result");
  4060. +
  4061. +const char kPathSeparator[] = "/";
  4062. +
  4063. +bool IsStandardScheme(base::StringPiece scheme) {
  4064. + // "*" gets the same treatment as a standard scheme.
  4065. + if (scheme == "*")
  4066. + return true;
  4067. +
  4068. + return url::IsStandard(scheme.data(),
  4069. + url::Component(0, static_cast<int>(scheme.length())));
  4070. +}
  4071. +
  4072. +bool IsValidPortForScheme(base::StringPiece scheme, base::StringPiece port) {
  4073. + if (port == "*")
  4074. + return true;
  4075. +
  4076. + // Only accept non-wildcard ports if the scheme uses ports.
  4077. + if (url::DefaultPortForScheme(scheme.data(), scheme.length()) ==
  4078. + url::PORT_UNSPECIFIED) {
  4079. + return false;
  4080. + }
  4081. +
  4082. + int parsed_port = url::PORT_UNSPECIFIED;
  4083. + if (!base::StringToInt(port, &parsed_port))
  4084. + return false;
  4085. + return (parsed_port >= 0) && (parsed_port < 65536);
  4086. +}
  4087. +
  4088. +// Returns |path| with the trailing wildcard stripped if one existed.
  4089. +//
  4090. +// The functions that rely on this (OverlapsWith and Contains) are only
  4091. +// called for the patterns inside URLPatternSet. In those cases, we know that
  4092. +// the path will have only a single wildcard at the end. This makes figuring
  4093. +// out overlap much easier. It seems like there is probably a computer-sciency
  4094. +// way to solve the general case, but we don't need that yet.
  4095. +base::StringPiece StripTrailingWildcard(base::StringPiece path) {
  4096. + if (base::EndsWith(path, "*"))
  4097. + path.remove_suffix(1);
  4098. + return path;
  4099. +}
  4100. +
  4101. +// Removes trailing dot from |host_piece| if any.
  4102. +base::StringPiece CanonicalizeHostForMatching(base::StringPiece host_piece) {
  4103. + if (base::EndsWith(host_piece, "."))
  4104. + host_piece.remove_suffix(1);
  4105. + return host_piece;
  4106. +}
  4107. +
  4108. +} // namespace
  4109. +
  4110. +// static
  4111. +bool URLPattern::IsValidSchemeForExtensions(base::StringPiece scheme) {
  4112. + for (size_t i = 0; i < base::size(kValidSchemes); ++i) {
  4113. + if (scheme == kValidSchemes[i])
  4114. + return true;
  4115. + }
  4116. + return false;
  4117. +}
  4118. +
  4119. +// static
  4120. +int URLPattern::GetValidSchemeMaskForExtensions() {
  4121. + int result = 0;
  4122. + for (size_t i = 0; i < base::size(kValidSchemeMasks); ++i)
  4123. + result |= kValidSchemeMasks[i];
  4124. + return result;
  4125. +}
  4126. +
  4127. +URLPattern::URLPattern()
  4128. + : valid_schemes_(SCHEME_NONE),
  4129. + match_all_urls_(false),
  4130. + match_subdomains_(false),
  4131. + port_("*") {}
  4132. +
  4133. +URLPattern::URLPattern(int valid_schemes)
  4134. + : valid_schemes_(valid_schemes),
  4135. + match_all_urls_(false),
  4136. + match_subdomains_(false),
  4137. + port_("*") {}
  4138. +
  4139. +URLPattern::URLPattern(int valid_schemes, base::StringPiece pattern)
  4140. + // Strict error checking is used, because this constructor is only
  4141. + // appropriate when we know |pattern| is valid.
  4142. + : valid_schemes_(valid_schemes),
  4143. + match_all_urls_(false),
  4144. + match_subdomains_(false),
  4145. + port_("*") {
  4146. + ParseResult result = Parse(pattern);
  4147. + if (result != ParseResult::kSuccess) {
  4148. + const char* error_string = GetParseResultString(result);
  4149. + // Temporarily add more logging to investigate why this code path is
  4150. + // reached. For http://crbug.com/856948
  4151. + LOG(ERROR) << "Invalid pattern was given " << pattern << " result "
  4152. + << error_string;
  4153. + NOTREACHED() << "URLPattern invalid: '" << pattern
  4154. + << "'; error: " << error_string;
  4155. + }
  4156. +}
  4157. +
  4158. +URLPattern::URLPattern(const URLPattern& other) = default;
  4159. +
  4160. +URLPattern::URLPattern(URLPattern&& other) = default;
  4161. +
  4162. +URLPattern::~URLPattern() {
  4163. +}
  4164. +
  4165. +URLPattern& URLPattern::operator=(const URLPattern& other) = default;
  4166. +
  4167. +URLPattern& URLPattern::operator=(URLPattern&& other) = default;
  4168. +
  4169. +bool URLPattern::operator<(const URLPattern& other) const {
  4170. + return GetAsString() < other.GetAsString();
  4171. +}
  4172. +
  4173. +bool URLPattern::operator>(const URLPattern& other) const {
  4174. + return GetAsString() > other.GetAsString();
  4175. +}
  4176. +
  4177. +bool URLPattern::operator==(const URLPattern& other) const {
  4178. + return GetAsString() == other.GetAsString();
  4179. +}
  4180. +
  4181. +std::ostream& operator<<(std::ostream& out, const URLPattern& url_pattern) {
  4182. + return out << '"' << url_pattern.GetAsString() << '"';
  4183. +}
  4184. +
  4185. +URLPattern::ParseResult URLPattern::Parse(base::StringPiece pattern) {
  4186. + spec_.clear();
  4187. + SetMatchAllURLs(false);
  4188. + SetMatchSubdomains(false);
  4189. + SetPort("*");
  4190. +
  4191. + // Special case pattern to match every valid URL.
  4192. + if (pattern == kAllUrlsPattern) {
  4193. + SetMatchAllURLs(true);
  4194. + return ParseResult::kSuccess;
  4195. + }
  4196. +
  4197. + // Parse out the scheme.
  4198. + size_t scheme_end_pos = pattern.find(url::kStandardSchemeSeparator);
  4199. + bool has_standard_scheme_separator = true;
  4200. +
  4201. + // Some urls also use ':' alone as the scheme separator.
  4202. + if (scheme_end_pos == base::StringPiece::npos) {
  4203. + scheme_end_pos = pattern.find(':');
  4204. + has_standard_scheme_separator = false;
  4205. + }
  4206. +
  4207. + if (scheme_end_pos == base::StringPiece::npos)
  4208. + return ParseResult::kMissingSchemeSeparator;
  4209. +
  4210. + if (!SetScheme(pattern.substr(0, scheme_end_pos)))
  4211. + return ParseResult::kInvalidScheme;
  4212. +
  4213. + bool standard_scheme = IsStandardScheme(scheme_);
  4214. + if (standard_scheme != has_standard_scheme_separator)
  4215. + return ParseResult::kWrongSchemeSeparator;
  4216. +
  4217. + // Advance past the scheme separator.
  4218. + scheme_end_pos +=
  4219. + (standard_scheme ? strlen(url::kStandardSchemeSeparator) : 1);
  4220. + if (scheme_end_pos >= pattern.size())
  4221. + return ParseResult::kEmptyHost;
  4222. +
  4223. + // Parse out the host and path.
  4224. + size_t host_start_pos = scheme_end_pos;
  4225. + size_t path_start_pos = 0;
  4226. +
  4227. + if (!standard_scheme) {
  4228. + path_start_pos = host_start_pos;
  4229. + } else if (scheme_ == url::kFileScheme) {
  4230. + size_t host_end_pos = pattern.find(kPathSeparator, host_start_pos);
  4231. + if (host_end_pos == base::StringPiece::npos) {
  4232. + // Allow hostname omission.
  4233. + // e.g. file://* is interpreted as file:///*,
  4234. + // file://foo* is interpreted as file:///foo*.
  4235. + path_start_pos = host_start_pos - 1;
  4236. + } else {
  4237. + // Ignore hostname if scheme is file://.
  4238. + // e.g. file://localhost/foo is equal to file:///foo.
  4239. + path_start_pos = host_end_pos;
  4240. + }
  4241. + } else {
  4242. + size_t host_end_pos = pattern.find(kPathSeparator, host_start_pos);
  4243. +
  4244. + // Host is required.
  4245. + if (host_start_pos == host_end_pos)
  4246. + return ParseResult::kEmptyHost;
  4247. +
  4248. + if (host_end_pos == base::StringPiece::npos)
  4249. + return ParseResult::kEmptyPath;
  4250. +
  4251. + base::StringPiece host_and_port =
  4252. + pattern.substr(host_start_pos, host_end_pos - host_start_pos);
  4253. +
  4254. + size_t port_separator_pos = base::StringPiece::npos;
  4255. + if (host_and_port[0] != '[') {
  4256. + // Not IPv6 (either IPv4 or just a normal address).
  4257. + port_separator_pos = host_and_port.find(':');
  4258. + } else { // IPv6.
  4259. + size_t host_end_pos = host_and_port.find(']');
  4260. + if (host_end_pos == base::StringPiece::npos)
  4261. + return ParseResult::kInvalidHost;
  4262. + if (host_end_pos == 1)
  4263. + return ParseResult::kEmptyHost;
  4264. +
  4265. + if (host_end_pos < host_and_port.length() - 1) {
  4266. + // The host isn't the only component. Check for a port. This would
  4267. + // require a ':' to follow the closing ']' from the host.
  4268. + if (host_and_port[host_end_pos + 1] != ':')
  4269. + return ParseResult::kInvalidHost;
  4270. +
  4271. + port_separator_pos = host_end_pos + 1;
  4272. + }
  4273. + }
  4274. +
  4275. + if (port_separator_pos != base::StringPiece::npos &&
  4276. + !SetPort(host_and_port.substr(port_separator_pos + 1))) {
  4277. + return ParseResult::kInvalidPort;
  4278. + }
  4279. +
  4280. + // Note: this substr() will be the entire string if the port position
  4281. + // wasn't found.
  4282. + base::StringPiece host_piece = host_and_port.substr(0, port_separator_pos);
  4283. +
  4284. + if (host_piece.empty())
  4285. + return ParseResult::kEmptyHost;
  4286. +
  4287. + if (host_piece == "*") {
  4288. + match_subdomains_ = true;
  4289. + host_piece = base::StringPiece();
  4290. + } else if (base::StartsWith(host_piece, "*.")) {
  4291. + if (host_piece.length() == 2) {
  4292. + // We don't allow just '*.' as a host.
  4293. + return ParseResult::kEmptyHost;
  4294. + }
  4295. + match_subdomains_ = true;
  4296. + host_piece = host_piece.substr(2);
  4297. + }
  4298. +
  4299. + host_ = host_piece.as_string();
  4300. +
  4301. + path_start_pos = host_end_pos;
  4302. + }
  4303. +
  4304. + SetPath(pattern.substr(path_start_pos));
  4305. +
  4306. + // No other '*' can occur in the host, though. This isn't necessary, but is
  4307. + // done as a convenience to developers who might otherwise be confused and
  4308. + // think '*' works as a glob in the host.
  4309. + if (host_.find('*') != std::string::npos)
  4310. + return ParseResult::kInvalidHostWildcard;
  4311. +
  4312. + if (!host_.empty()) {
  4313. + // If |host_| is present (i.e., isn't a wildcard), we need to canonicalize
  4314. + // it.
  4315. + url::CanonHostInfo host_info;
  4316. + host_ = net::CanonicalizeHost(host_, &host_info);
  4317. + // net::CanonicalizeHost() returns an empty string on failure.
  4318. + if (host_.empty())
  4319. + return ParseResult::kInvalidHost;
  4320. + }
  4321. +
  4322. + // Null characters are not allowed in hosts.
  4323. + if (host_.find('\0') != std::string::npos)
  4324. + return ParseResult::kInvalidHost;
  4325. +
  4326. + return ParseResult::kSuccess;
  4327. +}
  4328. +
  4329. +void URLPattern::SetValidSchemes(int valid_schemes) {
  4330. + // TODO(devlin): Should we check that valid_schemes agrees with |scheme_|
  4331. + // here? Otherwise, valid_schemes_ and schemes_ may stop agreeing with each
  4332. + // other (e.g., in the case of `*://*/*`, where the scheme should only be
  4333. + // http or https).
  4334. + spec_.clear();
  4335. + valid_schemes_ = valid_schemes;
  4336. +}
  4337. +
  4338. +void URLPattern::SetHost(base::StringPiece host) {
  4339. + spec_.clear();
  4340. + host_.assign(host.data(), host.size());
  4341. +}
  4342. +
  4343. +void URLPattern::SetMatchAllURLs(bool val) {
  4344. + spec_.clear();
  4345. + match_all_urls_ = val;
  4346. +
  4347. + if (val) {
  4348. + match_subdomains_ = true;
  4349. + scheme_ = "*";
  4350. + host_.clear();
  4351. + SetPath("/*");
  4352. + }
  4353. +}
  4354. +
  4355. +void URLPattern::SetMatchSubdomains(bool val) {
  4356. + spec_.clear();
  4357. + match_subdomains_ = val;
  4358. +}
  4359. +
  4360. +bool URLPattern::SetScheme(base::StringPiece scheme) {
  4361. + spec_.clear();
  4362. + scheme_.assign(scheme.data(), scheme.size());
  4363. + if (scheme_ == "*") {
  4364. + valid_schemes_ &= (SCHEME_HTTP | SCHEME_HTTPS);
  4365. + } else if (!IsValidScheme(scheme_)) {
  4366. + return false;
  4367. + }
  4368. + return true;
  4369. +}
  4370. +
  4371. +bool URLPattern::IsValidScheme(base::StringPiece scheme) const {
  4372. + if (valid_schemes_ == SCHEME_ALL)
  4373. + return true;
  4374. +
  4375. + for (size_t i = 0; i < base::size(kValidSchemes); ++i) {
  4376. + if (scheme == kValidSchemes[i] && (valid_schemes_ & kValidSchemeMasks[i]))
  4377. + return true;
  4378. + }
  4379. +
  4380. + return false;
  4381. +}
  4382. +
  4383. +void URLPattern::SetPath(base::StringPiece path) {
  4384. + spec_.clear();
  4385. + path_.assign(path.data(), path.size());
  4386. + path_escaped_ = path_;
  4387. + base::ReplaceSubstringsAfterOffset(&path_escaped_, 0, "\\", "\\\\");
  4388. + base::ReplaceSubstringsAfterOffset(&path_escaped_, 0, "?", "\\?");
  4389. +}
  4390. +
  4391. +bool URLPattern::SetPort(base::StringPiece port) {
  4392. + spec_.clear();
  4393. + if (IsValidPortForScheme(scheme_, port)) {
  4394. + port_.assign(port.data(), port.size());
  4395. + return true;
  4396. + }
  4397. + return false;
  4398. +}
  4399. +
  4400. +bool URLPattern::MatchesURL(const GURL& test) const {
  4401. + // Invalid URLs can never match.
  4402. + if (!test.is_valid())
  4403. + return false;
  4404. +
  4405. + const GURL* test_url = &test;
  4406. + bool has_inner_url = test.inner_url() != nullptr;
  4407. +
  4408. + if (has_inner_url) {
  4409. + if (!test.SchemeIsFileSystem())
  4410. + return false; // The only nested URLs we handle are filesystem URLs.
  4411. + test_url = test.inner_url();
  4412. + }
  4413. +
  4414. + // Ensure the scheme matches first, since <all_urls> may not match this URL if
  4415. + // the scheme is excluded.
  4416. + if (!MatchesScheme(test_url->scheme_piece()))
  4417. + return false;
  4418. +
  4419. + if (match_all_urls_)
  4420. + return true;
  4421. +
  4422. + // Unless |match_all_urls_| is true, the grammar only permits matching
  4423. + // URLs with nonempty paths.
  4424. + if (!test.has_path())
  4425. + return false;
  4426. +
  4427. + std::string path_for_request = test.PathForRequest();
  4428. + if (has_inner_url) {
  4429. + path_for_request = base::StringPrintf("%s%s", test_url->path_piece().data(),
  4430. + path_for_request.c_str());
  4431. + }
  4432. +
  4433. + return MatchesSecurityOriginHelper(*test_url) &&
  4434. + MatchesPath(path_for_request);
  4435. +}
  4436. +
  4437. +bool URLPattern::MatchesSecurityOrigin(const GURL& test) const {
  4438. + const GURL* test_url = &test;
  4439. + bool has_inner_url = test.inner_url() != NULL;
  4440. +
  4441. + if (has_inner_url) {
  4442. + if (!test.SchemeIsFileSystem())
  4443. + return false; // The only nested URLs we handle are filesystem URLs.
  4444. + test_url = test.inner_url();
  4445. + }
  4446. +
  4447. + if (!MatchesScheme(test_url->scheme()))
  4448. + return false;
  4449. +
  4450. + if (match_all_urls_)
  4451. + return true;
  4452. +
  4453. + return MatchesSecurityOriginHelper(*test_url);
  4454. +}
  4455. +
  4456. +bool URLPattern::MatchesScheme(base::StringPiece test) const {
  4457. + if (!IsValidScheme(test))
  4458. + return false;
  4459. +
  4460. + return scheme_ == "*" || test == scheme_;
  4461. +}
  4462. +
  4463. +bool URLPattern::MatchesHost(base::StringPiece host) const {
  4464. + // TODO(devlin): This is a bit sad. Parsing urls is expensive. However, it's
  4465. + // important that we do this conversion to a GURL in order to canonicalize the
  4466. + // host (the pattern's host_ already is canonicalized from Parse()). We can't
  4467. + // just do string comparison.
  4468. + return MatchesHost(
  4469. + GURL(base::StringPrintf("%s%s%s/", url::kHttpScheme,
  4470. + url::kStandardSchemeSeparator, host.data())));
  4471. +}
  4472. +
  4473. +bool URLPattern::MatchesHost(const GURL& test) const {
  4474. + base::StringPiece test_host(CanonicalizeHostForMatching(test.host_piece()));
  4475. + const base::StringPiece pattern_host(CanonicalizeHostForMatching(host_));
  4476. +
  4477. + // If the hosts are exactly equal, we have a match.
  4478. + if (test_host == pattern_host)
  4479. + return true;
  4480. +
  4481. + // If we're matching subdomains, and we have no host in the match pattern,
  4482. + // that means that we're matching all hosts, which means we have a match no
  4483. + // matter what the test host is.
  4484. + if (match_subdomains_ && pattern_host.empty())
  4485. + return true;
  4486. +
  4487. + // Otherwise, we can only match if our match pattern matches subdomains.
  4488. + if (!match_subdomains_)
  4489. + return false;
  4490. +
  4491. + // We don't do subdomain matching against IP addresses, so we can give up now
  4492. + // if the test host is an IP address.
  4493. + if (test.HostIsIPAddress())
  4494. + return false;
  4495. +
  4496. + // Check if the test host is a subdomain of our host.
  4497. + if (test_host.length() <= (pattern_host.length() + 1))
  4498. + return false;
  4499. +
  4500. + if (!base::EndsWith(test_host, pattern_host))
  4501. + return false;
  4502. +
  4503. + return test_host[test_host.length() - pattern_host.length() - 1] == '.';
  4504. +}
  4505. +
  4506. +bool URLPattern::MatchesEffectiveTld(
  4507. + net::registry_controlled_domains::PrivateRegistryFilter private_filter,
  4508. + net::registry_controlled_domains::UnknownRegistryFilter unknown_filter)
  4509. + const {
  4510. + // Check if it matches all urls or is a pattern like http://*/*.
  4511. + if (match_all_urls_ || (match_subdomains_ && host_.empty()))
  4512. + return true;
  4513. +
  4514. + // If this doesn't even match subdomains, it can't possibly be a TLD wildcard.
  4515. + if (!match_subdomains_)
  4516. + return false;
  4517. +
  4518. + // If there was more than just a TLD in the host (e.g., *.foobar.com), it
  4519. + // doesn't match all hosts in an effective TLD.
  4520. + if (net::registry_controlled_domains::HostHasRegistryControlledDomain(
  4521. + host_, unknown_filter, private_filter)) {
  4522. + return false;
  4523. + }
  4524. +
  4525. + // At this point the host could either be just a TLD ("com") or some unknown
  4526. + // TLD-like string ("notatld"). To disambiguate between them construct a
  4527. + // fake URL, and check the registry.
  4528. + //
  4529. + // If we recognized this TLD, then this is a pattern like *.com, and it
  4530. + // matches an effective TLD.
  4531. + return net::registry_controlled_domains::HostHasRegistryControlledDomain(
  4532. + "notatld." + host_, unknown_filter, private_filter);
  4533. +}
  4534. +
  4535. +bool URLPattern::MatchesSingleOrigin() const {
  4536. + // Strictly speaking, the port is part of the origin, but in URLPattern it
  4537. + // defaults to *. It's not very interesting anyway, so leave it out.
  4538. + return !MatchesEffectiveTld() && scheme_ != "*" && !match_subdomains_;
  4539. +}
  4540. +
  4541. +bool URLPattern::MatchesPath(base::StringPiece test) const {
  4542. + // Make the behaviour of OverlapsWith consistent with MatchesURL, which is
  4543. + // need to match hosted apps on e.g. 'google.com' also run on 'google.com/'.
  4544. + // The below if is a no-copy way of doing (test + "/*" == path_escaped_).
  4545. + if (path_escaped_.length() == test.length() + 2 &&
  4546. + base::StartsWith(path_escaped_.c_str(), test) &&
  4547. + base::EndsWith(path_escaped_, "/*")) {
  4548. + return true;
  4549. + }
  4550. +
  4551. + return base::MatchPattern(test, path_escaped_);
  4552. +}
  4553. +
  4554. +const std::string& URLPattern::GetAsString() const {
  4555. + if (!spec_.empty())
  4556. + return spec_;
  4557. +
  4558. + if (match_all_urls_) {
  4559. + spec_ = kAllUrlsPattern;
  4560. + return spec_;
  4561. + }
  4562. +
  4563. + bool standard_scheme = IsStandardScheme(scheme_);
  4564. +
  4565. + std::string spec = scheme_ +
  4566. + (standard_scheme ? url::kStandardSchemeSeparator : ":");
  4567. +
  4568. + if (scheme_ != url::kFileScheme && standard_scheme) {
  4569. + if (match_subdomains_) {
  4570. + spec += "*";
  4571. + if (!host_.empty())
  4572. + spec += ".";
  4573. + }
  4574. +
  4575. + if (!host_.empty())
  4576. + spec += host_;
  4577. +
  4578. + if (port_ != "*") {
  4579. + spec += ":";
  4580. + spec += port_;
  4581. + }
  4582. + }
  4583. +
  4584. + if (!path_.empty())
  4585. + spec += path_;
  4586. +
  4587. + spec_ = std::move(spec);
  4588. + return spec_;
  4589. +}
  4590. +
  4591. +bool URLPattern::OverlapsWith(const URLPattern& other) const {
  4592. + if (match_all_urls() || other.match_all_urls())
  4593. + return true;
  4594. + return (MatchesAnyScheme(other.GetExplicitSchemes()) ||
  4595. + other.MatchesAnyScheme(GetExplicitSchemes()))
  4596. + && (MatchesHost(other.host()) || other.MatchesHost(host()))
  4597. + && (MatchesPortPattern(other.port()) || other.MatchesPortPattern(port()))
  4598. + && (MatchesPath(StripTrailingWildcard(other.path())) ||
  4599. + other.MatchesPath(StripTrailingWildcard(path())));
  4600. +}
  4601. +
  4602. +bool URLPattern::Contains(const URLPattern& other) const {
  4603. + // Important: it's not enough to just check match_all_urls(); we also need to
  4604. + // make sure that the schemes in this pattern are a superset of those in
  4605. + // |other|.
  4606. + if (match_all_urls() &&
  4607. + (valid_schemes_ & other.valid_schemes_) == other.valid_schemes_) {
  4608. + return true;
  4609. + }
  4610. +
  4611. + return MatchesAllSchemes(other.GetExplicitSchemes()) &&
  4612. + MatchesHost(other.host()) &&
  4613. + (!other.match_subdomains_ || match_subdomains_) &&
  4614. + MatchesPortPattern(other.port()) &&
  4615. + MatchesPath(StripTrailingWildcard(other.path()));
  4616. +}
  4617. +
  4618. +base::Optional<URLPattern> URLPattern::CreateIntersection(
  4619. + const URLPattern& other) const {
  4620. + // Easy case: Schemes don't overlap. Return nullopt.
  4621. + int intersection_schemes = URLPattern::SCHEME_NONE;
  4622. + if (valid_schemes_ == URLPattern::SCHEME_ALL)
  4623. + intersection_schemes = other.valid_schemes_;
  4624. + else if (other.valid_schemes_ == URLPattern::SCHEME_ALL)
  4625. + intersection_schemes = valid_schemes_;
  4626. + else
  4627. + intersection_schemes = valid_schemes_ & other.valid_schemes_;
  4628. +
  4629. + if (intersection_schemes == URLPattern::SCHEME_NONE)
  4630. + return base::nullopt;
  4631. +
  4632. + {
  4633. + // In a few cases, we can (mostly) return a copy of one of the patterns.
  4634. + // This can happen when either:
  4635. + // - The URLPattern's are identical (possibly excluding valid_schemes_)
  4636. + // - One of the patterns has match_all_urls() equal to true.
  4637. + // NOTE(devlin): Theoretically, we could use Contains() instead of
  4638. + // match_all_urls() here. However, Contains() strips the trailing wildcard
  4639. + // from the path, which could yield the incorrect result.
  4640. + const URLPattern* copy_source = nullptr;
  4641. + if (*this == other || other.match_all_urls())
  4642. + copy_source = this;
  4643. + else if (match_all_urls())
  4644. + copy_source = &other;
  4645. +
  4646. + if (copy_source) {
  4647. + // NOTE: equality checks don't take into account valid_schemes_, and
  4648. + // schemes can be different in the case of match_all_urls() as well, so
  4649. + // we can't always just return *copy_source.
  4650. + if (intersection_schemes == copy_source->valid_schemes_)
  4651. + return *copy_source;
  4652. + URLPattern result(intersection_schemes);
  4653. + ParseResult parse_result = result.Parse(copy_source->GetAsString());
  4654. + CHECK_EQ(ParseResult::kSuccess, parse_result);
  4655. + return result;
  4656. + }
  4657. + }
  4658. +
  4659. + // No more easy cases. Go through component by component to find the patterns
  4660. + // that intersect.
  4661. +
  4662. + // Note: Alias the function type (rather than using auto) because
  4663. + // MatchesHost() is overloaded.
  4664. + using match_function_type = bool (URLPattern::*)(base::StringPiece) const;
  4665. +
  4666. + auto get_intersection = [this, &other](base::StringPiece own_str,
  4667. + base::StringPiece other_str,
  4668. + match_function_type match_function,
  4669. + base::StringPiece* out) {
  4670. + if ((this->*match_function)(other_str)) {
  4671. + *out = other_str;
  4672. + return true;
  4673. + }
  4674. + if ((other.*match_function)(own_str)) {
  4675. + *out = own_str;
  4676. + return true;
  4677. + }
  4678. + return false;
  4679. + };
  4680. +
  4681. + base::StringPiece scheme;
  4682. + base::StringPiece host;
  4683. + base::StringPiece port;
  4684. + base::StringPiece path;
  4685. + // If any pieces fail to overlap, then there is no intersection.
  4686. + if (!get_intersection(scheme_, other.scheme_, &URLPattern::MatchesScheme,
  4687. + &scheme) ||
  4688. + !get_intersection(host_, other.host_, &URLPattern::MatchesHost, &host) ||
  4689. + !get_intersection(port_, other.port_, &URLPattern::MatchesPortPattern,
  4690. + &port) ||
  4691. + !get_intersection(path_, other.path_, &URLPattern::MatchesPath, &path)) {
  4692. + return base::nullopt;
  4693. + }
  4694. +
  4695. + // Only match subdomains if both patterns match subdomains.
  4696. + base::StringPiece subdomains;
  4697. + if (match_subdomains_ && other.match_subdomains_) {
  4698. + // The host may be empty (e.g., in the case of *://*/* - in that case, only
  4699. + // append '*' instead of '*.'.
  4700. + subdomains = host.empty() ? "*" : "*.";
  4701. + }
  4702. +
  4703. + base::StringPiece scheme_separator =
  4704. + IsStandardScheme(scheme) ? url::kStandardSchemeSeparator : ":";
  4705. +
  4706. + std::string pattern_str = base::StrCat(
  4707. + {scheme, scheme_separator, subdomains, host, ":", port, path});
  4708. +
  4709. + URLPattern pattern(intersection_schemes);
  4710. + ParseResult result = pattern.Parse(pattern_str);
  4711. + // TODO(devlin): I don't think there's any way this should ever fail, but
  4712. + // use a CHECK() to flush any cases out. If nothing crops up, downgrade this
  4713. + // to a DCHECK in M72.
  4714. + CHECK_EQ(ParseResult::kSuccess, result);
  4715. +
  4716. + return pattern;
  4717. +}
  4718. +
  4719. +bool URLPattern::MatchesAnyScheme(
  4720. + const std::vector<std::string>& schemes) const {
  4721. + for (auto i = schemes.cbegin(); i != schemes.cend(); ++i) {
  4722. + if (MatchesScheme(*i))
  4723. + return true;
  4724. + }
  4725. +
  4726. + return false;
  4727. +}
  4728. +
  4729. +bool URLPattern::MatchesAllSchemes(
  4730. + const std::vector<std::string>& schemes) const {
  4731. + for (auto i = schemes.cbegin(); i != schemes.cend(); ++i) {
  4732. + if (!MatchesScheme(*i))
  4733. + return false;
  4734. + }
  4735. +
  4736. + return true;
  4737. +}
  4738. +
  4739. +bool URLPattern::MatchesSecurityOriginHelper(const GURL& test) const {
  4740. + // Ignore hostname if scheme is file://.
  4741. + if (scheme_ != url::kFileScheme && !MatchesHost(test))
  4742. + return false;
  4743. +
  4744. + if (!MatchesPortPattern(base::NumberToString(test.EffectiveIntPort())))
  4745. + return false;
  4746. +
  4747. + return true;
  4748. +}
  4749. +
  4750. +bool URLPattern::MatchesPortPattern(base::StringPiece port) const {
  4751. + return port_ == "*" || port_ == port;
  4752. +}
  4753. +
  4754. +std::vector<std::string> URLPattern::GetExplicitSchemes() const {
  4755. + std::vector<std::string> result;
  4756. +
  4757. + if (scheme_ != "*" && !match_all_urls_ && IsValidScheme(scheme_)) {
  4758. + result.push_back(scheme_);
  4759. + return result;
  4760. + }
  4761. +
  4762. + for (size_t i = 0; i < base::size(kValidSchemes); ++i) {
  4763. + if (MatchesScheme(kValidSchemes[i])) {
  4764. + result.push_back(kValidSchemes[i]);
  4765. + }
  4766. + }
  4767. +
  4768. + return result;
  4769. +}
  4770. +
  4771. +std::vector<URLPattern> URLPattern::ConvertToExplicitSchemes() const {
  4772. + std::vector<std::string> explicit_schemes = GetExplicitSchemes();
  4773. + std::vector<URLPattern> result;
  4774. +
  4775. + for (std::vector<std::string>::const_iterator i = explicit_schemes.begin();
  4776. + i != explicit_schemes.end(); ++i) {
  4777. + URLPattern temp = *this;
  4778. + temp.SetScheme(*i);
  4779. + temp.SetMatchAllURLs(false);
  4780. + result.push_back(temp);
  4781. + }
  4782. +
  4783. + return result;
  4784. +}
  4785. +
  4786. +// static
  4787. +const char* URLPattern::GetParseResultString(
  4788. + URLPattern::ParseResult parse_result) {
  4789. + return kParseResultMessages[static_cast<int>(parse_result)];
  4790. +}
  4791. diff --git a/components/user_scripts/common/url_pattern.h b/components/user_scripts/common/url_pattern.h
  4792. new file mode 100755
  4793. --- /dev/null
  4794. +++ b/components/user_scripts/common/url_pattern.h
  4795. @@ -0,0 +1,301 @@
  4796. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  4797. +// Use of this source code is governed by a BSD-style license that can be
  4798. +// found in the LICENSE file.
  4799. +#ifndef EXTENSIONS_COMMON_URL_PATTERN_H_
  4800. +#define EXTENSIONS_COMMON_URL_PATTERN_H_
  4801. +
  4802. +#include <functional>
  4803. +#include <iosfwd>
  4804. +#include <string>
  4805. +#include <vector>
  4806. +
  4807. +#include "base/strings/string_piece.h"
  4808. +#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
  4809. +
  4810. +class GURL;
  4811. +
  4812. +// A pattern that can be used to match URLs. A URLPattern is a very restricted
  4813. +// subset of URL syntax:
  4814. +//
  4815. +// <url-pattern> := <scheme>://<host><port><path> | '<all_urls>'
  4816. +// <scheme> := '*' | 'http' | 'https' | 'file' | 'ftp' | 'chrome' |
  4817. +// 'chrome-extension' | 'filesystem'
  4818. +// <host> := '*' | <IPv4 address> | [<IPv6 address>] |
  4819. +// '*.' <anychar except '/' and '*'>+
  4820. +// <port> := [':' ('*' | <port number between 0 and 65535>)]
  4821. +// <path> := '/' <any chars>
  4822. +//
  4823. +// * Host is not used when the scheme is 'file'.
  4824. +// * The path can have embedded '*' characters which act as glob wildcards.
  4825. +// * '<all_urls>' is a special pattern that matches any valid URL that contains
  4826. +// a valid scheme (as specified by valid_schemes_).
  4827. +// * The '*' scheme pattern excludes file URLs.
  4828. +//
  4829. +// Examples of valid patterns:
  4830. +// - http://*/*
  4831. +// - http://*/foo*
  4832. +// - https://*.google.com/foo*bar
  4833. +// - file://monkey*
  4834. +// - http://127.0.0.1/*
  4835. +// - http://[2607:f8b0:4005:805::200e]/*
  4836. +//
  4837. +// Examples of invalid patterns:
  4838. +// - http://* -- path not specified
  4839. +// - http://*foo/bar -- * not allowed as substring of host component
  4840. +// - http://foo.*.bar/baz -- * must be first component
  4841. +// - http:/bar -- scheme separator not found
  4842. +// - foo://* -- invalid scheme
  4843. +// - chrome:// -- we don't support chrome internal URLs
  4844. +class URLPattern {
  4845. + public:
  4846. + // A collection of scheme bitmasks for use with valid_schemes.
  4847. + enum SchemeMasks {
  4848. + SCHEME_NONE = 0,
  4849. + SCHEME_HTTP = 1 << 0,
  4850. + SCHEME_HTTPS = 1 << 1,
  4851. + SCHEME_FILE = 1 << 2,
  4852. + SCHEME_FTP = 1 << 3,
  4853. + SCHEME_CHROMEUI = 1 << 4,
  4854. + SCHEME_EXTENSION = 1 << 5,
  4855. + SCHEME_FILESYSTEM = 1 << 6,
  4856. + SCHEME_WS = 1 << 7,
  4857. + SCHEME_WSS = 1 << 8,
  4858. + SCHEME_DATA = 1 << 9,
  4859. +
  4860. + // IMPORTANT!
  4861. + // SCHEME_ALL will match every scheme, including chrome://, chrome-
  4862. + // extension://, about:, etc. Because this has lots of security
  4863. + // implications, third-party extensions should usually not be able to get
  4864. + // access to URL patterns initialized this way. If there is a reason
  4865. + // for violating this general rule, document why this it safe.
  4866. + SCHEME_ALL = -1,
  4867. + };
  4868. +
  4869. + // Error codes returned from Parse().
  4870. + enum class ParseResult {
  4871. + kSuccess = 0,
  4872. + kMissingSchemeSeparator,
  4873. + kInvalidScheme,
  4874. + kWrongSchemeSeparator,
  4875. + kEmptyHost,
  4876. + kInvalidHostWildcard,
  4877. + kEmptyPath,
  4878. + kInvalidPort,
  4879. + kInvalidHost,
  4880. + kNumParseResults,
  4881. + };
  4882. +
  4883. + // The <all_urls> string pattern.
  4884. + static const char kAllUrlsPattern[];
  4885. +
  4886. + // Returns true if the given |scheme| is considered valid for extensions.
  4887. + static bool IsValidSchemeForExtensions(base::StringPiece scheme);
  4888. +
  4889. + // Returns the mask for all schemes considered valid for extensions.
  4890. + static int GetValidSchemeMaskForExtensions();
  4891. +
  4892. + explicit URLPattern(int valid_schemes);
  4893. +
  4894. + // Convenience to construct a URLPattern from a string. If the string is not
  4895. + // known ahead of time, use Parse() instead, which returns success or failure.
  4896. + URLPattern(int valid_schemes, base::StringPiece pattern);
  4897. +
  4898. + URLPattern();
  4899. + URLPattern(const URLPattern& other);
  4900. + URLPattern(URLPattern&& other);
  4901. + ~URLPattern();
  4902. +
  4903. + URLPattern& operator=(const URLPattern& other);
  4904. + URLPattern& operator=(URLPattern&& other);
  4905. +
  4906. + bool operator<(const URLPattern& other) const;
  4907. + bool operator>(const URLPattern& other) const;
  4908. + bool operator==(const URLPattern& other) const;
  4909. +
  4910. + // Initializes this instance by parsing the provided string. Returns
  4911. + // URLPattern::ParseResult::kSuccess on success, or an error code otherwise.
  4912. + // On failure, this instance will have some intermediate values and is in an
  4913. + // invalid state.
  4914. + ParseResult Parse(base::StringPiece pattern_str);
  4915. +
  4916. + // Gets the bitmask of valid schemes.
  4917. + int valid_schemes() const { return valid_schemes_; }
  4918. + void SetValidSchemes(int valid_schemes);
  4919. +
  4920. + // Gets the host the pattern matches. This can be an empty string if the
  4921. + // pattern matches all hosts (the input was <scheme>://*/<whatever>).
  4922. + const std::string& host() const { return host_; }
  4923. + void SetHost(base::StringPiece host);
  4924. +
  4925. + // Gets whether to match subdomains of host().
  4926. + bool match_subdomains() const { return match_subdomains_; }
  4927. + void SetMatchSubdomains(bool val);
  4928. +
  4929. + // Gets the path the pattern matches with the leading slash. This can have
  4930. + // embedded asterisks which are interpreted using glob rules.
  4931. + const std::string& path() const { return path_; }
  4932. + void SetPath(base::StringPiece path);
  4933. +
  4934. + // Returns true if this pattern matches all (valid) urls.
  4935. + bool match_all_urls() const { return match_all_urls_; }
  4936. + void SetMatchAllURLs(bool val);
  4937. +
  4938. + // Sets the scheme for pattern matches. This can be a single '*' if the
  4939. + // pattern matches all valid schemes (as defined by the valid_schemes_
  4940. + // property). Returns false on failure (if the scheme is not valid).
  4941. + bool SetScheme(base::StringPiece scheme);
  4942. + // Note: You should use MatchesScheme() instead of this getter unless you
  4943. + // absolutely need the exact scheme. This is exposed for testing.
  4944. + const std::string& scheme() const { return scheme_; }
  4945. +
  4946. + // Returns true if the specified scheme can be used in this URL pattern, and
  4947. + // false otherwise. Uses valid_schemes_ to determine validity.
  4948. + bool IsValidScheme(base::StringPiece scheme) const;
  4949. +
  4950. + // Returns true if this instance matches the specified URL. Always returns
  4951. + // false for invalid URLs.
  4952. + bool MatchesURL(const GURL& test) const;
  4953. +
  4954. + // Returns true if this instance matches the specified security origin.
  4955. + bool MatchesSecurityOrigin(const GURL& test) const;
  4956. +
  4957. + // Returns true if |test| matches our scheme.
  4958. + // Note that if test is "filesystem", this may fail whereas MatchesURL
  4959. + // may succeed. MatchesURL is smart enough to look at the inner_url instead
  4960. + // of the outer "filesystem:" part.
  4961. + bool MatchesScheme(base::StringPiece test) const;
  4962. +
  4963. + // Returns true if |test| matches our host.
  4964. + bool MatchesHost(base::StringPiece test) const;
  4965. + bool MatchesHost(const GURL& test) const;
  4966. +
  4967. + // Returns true if |test| matches our path.
  4968. + bool MatchesPath(base::StringPiece test) const;
  4969. +
  4970. + // Returns true if the pattern matches all patterns in an (e)TLD. This
  4971. + // includes patterns like *://*.com/*, *://*.co.uk/*, etc. A pattern that
  4972. + // matches all domains (e.g., *://*/*) will return true.
  4973. + // |private_filter| specifies whether private registries (like appspot.com)
  4974. + // should be considered; if included, patterns like *://*.appspot.com/* will
  4975. + // return true. By default, we exclude private registries (so *.appspot.com
  4976. + // returns false).
  4977. + // Note: This is an expensive method, and should be used sparingly!
  4978. + // You should probably use URLPatternSet::ShouldWarnAllHosts(), which is
  4979. + // cached.
  4980. + bool MatchesEffectiveTld(
  4981. + net::registry_controlled_domains::PrivateRegistryFilter private_filter =
  4982. + net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES,
  4983. + net::registry_controlled_domains::UnknownRegistryFilter unknown_filter =
  4984. + net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES) const;
  4985. +
  4986. + // Returns true if the pattern only matches a single origin. The pattern may
  4987. + // include a path.
  4988. + bool MatchesSingleOrigin() const;
  4989. +
  4990. + // Sets the port. Returns false if the port is invalid.
  4991. + bool SetPort(base::StringPiece port);
  4992. + const std::string& port() const { return port_; }
  4993. +
  4994. + // Returns a string representing this instance.
  4995. + const std::string& GetAsString() const;
  4996. +
  4997. + // Determines whether there is a URL that would match this instance and
  4998. + // another instance. This method is symmetrical: Calling
  4999. + // other.OverlapsWith(this) would result in the same answer.
  5000. + bool OverlapsWith(const URLPattern& other) const;
  5001. +
  5002. + // Returns true if this pattern matches all possible URLs that |other| can
  5003. + // match. For example, http://*.google.com encompasses http://www.google.com.
  5004. + bool Contains(const URLPattern& other) const;
  5005. +
  5006. + // Creates a new URLPattern that represents the intersection of this
  5007. + // URLPattern with the |other|, or base::nullopt if no intersection exists.
  5008. + // For instance, given the patterns http://*.google.com/* and
  5009. + // *://maps.google.com/*, the intersection is http://maps.google.com/*.
  5010. + // NOTES:
  5011. + // - Though scheme intersections are supported, the serialization of
  5012. + // URLPatternSet does not record them. Be sure that this is safe for your
  5013. + // use cases.
  5014. + // - Path intersection is done on a best-effort basis. If one path clearly
  5015. + // contains another, it will be handled correctly, but this method does not
  5016. + // deal with cases like /*a* and /*b* (where technically the intersection
  5017. + // is /*a*b*|/*b*a*); the intersection returned for that case will be empty.
  5018. + base::Optional<URLPattern> CreateIntersection(const URLPattern& other) const;
  5019. +
  5020. + // Converts this URLPattern into an equivalent set of URLPatterns that don't
  5021. + // use a wildcard in the scheme component. If this URLPattern doesn't use a
  5022. + // wildcard scheme, then the returned set will contain one element that is
  5023. + // equivalent to this instance.
  5024. + std::vector<URLPattern> ConvertToExplicitSchemes() const;
  5025. +
  5026. + static bool EffectiveHostCompare(const URLPattern& a, const URLPattern& b) {
  5027. + if (a.match_all_urls_ && b.match_all_urls_)
  5028. + return false;
  5029. + return a.host_.compare(b.host_) < 0;
  5030. + }
  5031. +
  5032. + // Used for origin comparisons in a std::set.
  5033. + class EffectiveHostCompareFunctor {
  5034. + public:
  5035. + bool operator()(const URLPattern& a, const URLPattern& b) const {
  5036. + return EffectiveHostCompare(a, b);
  5037. + }
  5038. + };
  5039. +
  5040. + // Get an error string for a ParseResult.
  5041. + static const char* GetParseResultString(URLPattern::ParseResult parse_result);
  5042. +
  5043. + private:
  5044. + // Returns true if any of the |schemes| items matches our scheme.
  5045. + bool MatchesAnyScheme(const std::vector<std::string>& schemes) const;
  5046. +
  5047. + // Returns true if all of the |schemes| items matches our scheme.
  5048. + bool MatchesAllSchemes(const std::vector<std::string>& schemes) const;
  5049. +
  5050. + bool MatchesSecurityOriginHelper(const GURL& test) const;
  5051. +
  5052. + // Returns true if our port matches the |port| pattern (it may be "*").
  5053. + bool MatchesPortPattern(base::StringPiece port) const;
  5054. +
  5055. + // If the URLPattern contains a wildcard scheme, returns a list of
  5056. + // equivalent literal schemes, otherwise returns the current scheme.
  5057. + std::vector<std::string> GetExplicitSchemes() const;
  5058. +
  5059. + // A bitmask containing the schemes which are considered valid for this
  5060. + // pattern. Parse() uses this to decide whether a pattern contains a valid
  5061. + // scheme.
  5062. + int valid_schemes_;
  5063. +
  5064. + // True if this is a special-case "<all_urls>" pattern.
  5065. + bool match_all_urls_;
  5066. +
  5067. + // The scheme for the pattern.
  5068. + std::string scheme_;
  5069. +
  5070. + // The host without any leading "*" components.
  5071. + std::string host_;
  5072. +
  5073. + // Whether we should match subdomains of the host. This is true if the first
  5074. + // component of the pattern's host was "*".
  5075. + bool match_subdomains_;
  5076. +
  5077. + // The port.
  5078. + std::string port_;
  5079. +
  5080. + // The path to match. This is everything after the host of the URL, or
  5081. + // everything after the scheme in the case of file:// URLs.
  5082. + std::string path_;
  5083. +
  5084. + // The path with "?" and "\" characters escaped for use with the
  5085. + // MatchPattern() function.
  5086. + std::string path_escaped_;
  5087. +
  5088. + // A string representing this URLPattern.
  5089. + mutable std::string spec_;
  5090. +};
  5091. +
  5092. +std::ostream& operator<<(std::ostream& out, const URLPattern& url_pattern);
  5093. +
  5094. +typedef std::vector<URLPattern> URLPatternList;
  5095. +
  5096. +#endif // EXTENSIONS_COMMON_URL_PATTERN_H_
  5097. diff --git a/components/user_scripts/common/url_pattern_set.cc b/components/user_scripts/common/url_pattern_set.cc
  5098. new file mode 100755
  5099. --- /dev/null
  5100. +++ b/components/user_scripts/common/url_pattern_set.cc
  5101. @@ -0,0 +1,330 @@
  5102. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  5103. +// Use of this source code is governed by a BSD-style license that can be
  5104. +// found in the LICENSE file.
  5105. +
  5106. +#include "url_pattern_set.h"
  5107. +
  5108. +#include <iterator>
  5109. +#include <ostream>
  5110. +
  5111. +#include "base/logging.h"
  5112. +#include "base/stl_util.h"
  5113. +#include "base/values.h"
  5114. +#include "error_utils.h"
  5115. +#include "url_pattern.h"
  5116. +#include "url/gurl.h"
  5117. +#include "url/origin.h"
  5118. +#include "url/url_constants.h"
  5119. +#include "user_scripts_features.h"
  5120. +
  5121. +namespace user_scripts {
  5122. +
  5123. +namespace {
  5124. +
  5125. +const char kInvalidURLPatternError[] = "Invalid url pattern '*'";
  5126. +
  5127. +} // namespace
  5128. +
  5129. +// static
  5130. +URLPatternSet URLPatternSet::CreateDifference(const URLPatternSet& set1,
  5131. + const URLPatternSet& set2) {
  5132. + return URLPatternSet(base::STLSetDifference<std::set<URLPattern>>(
  5133. + set1.patterns_, set2.patterns_));
  5134. +}
  5135. +
  5136. +// static
  5137. +URLPatternSet URLPatternSet::CreateIntersection(
  5138. + const URLPatternSet& set1,
  5139. + const URLPatternSet& set2,
  5140. + IntersectionBehavior intersection_behavior) {
  5141. + // Note: leverage return value optimization; always return the same object.
  5142. + URLPatternSet result;
  5143. +
  5144. + if (intersection_behavior == IntersectionBehavior::kStringComparison) {
  5145. + // String comparison just relies on STL set behavior, which looks at the
  5146. + // string representation.
  5147. + result = URLPatternSet(base::STLSetIntersection<std::set<URLPattern>>(
  5148. + set1.patterns_, set2.patterns_));
  5149. + return result;
  5150. + }
  5151. +
  5152. + // Look for a semantic intersection.
  5153. +
  5154. + // Step 1: Iterate over each set. Find any patterns that are completely
  5155. + // contained by the other (thus being necessarily present in any intersection)
  5156. + // and add them, collecting the others in a set of unique items.
  5157. + // Note: Use a collection of pointers for the uniques to avoid excessive
  5158. + // copies. Since these are owned by the URLPatternSet passed in, which is
  5159. + // const, this should be safe.
  5160. + std::vector<const URLPattern*> unique_set1;
  5161. + for (const URLPattern& pattern : set1) {
  5162. + if (set2.ContainsPattern(pattern))
  5163. + result.patterns_.insert(pattern);
  5164. + else
  5165. + unique_set1.push_back(&pattern);
  5166. + }
  5167. + std::vector<const URLPattern*> unique_set2;
  5168. + for (const URLPattern& pattern : set2) {
  5169. + if (set1.ContainsPattern(pattern))
  5170. + result.patterns_.insert(pattern);
  5171. + else
  5172. + unique_set2.push_back(&pattern);
  5173. + }
  5174. +
  5175. + // If we're just looking for patterns contained by both, we're done.
  5176. + if (intersection_behavior == IntersectionBehavior::kPatternsContainedByBoth)
  5177. + return result;
  5178. +
  5179. + DCHECK_EQ(IntersectionBehavior::kDetailed, intersection_behavior);
  5180. +
  5181. + // Step 2: Iterate over all the unique patterns and find the intersections
  5182. + // they have with the other patterns.
  5183. + for (const auto* pattern : unique_set1) {
  5184. + for (const auto* pattern2 : unique_set2) {
  5185. + base::Optional<URLPattern> intersection =
  5186. + pattern->CreateIntersection(*pattern2);
  5187. + if (intersection)
  5188. + result.patterns_.insert(std::move(*intersection));
  5189. + }
  5190. + }
  5191. +
  5192. + return result;
  5193. +}
  5194. +
  5195. +// static
  5196. +URLPatternSet URLPatternSet::CreateUnion(const URLPatternSet& set1,
  5197. + const URLPatternSet& set2) {
  5198. + return URLPatternSet(
  5199. + base::STLSetUnion<std::set<URLPattern>>(set1.patterns_, set2.patterns_));
  5200. +}
  5201. +
  5202. +// static
  5203. +URLPatternSet URLPatternSet::CreateUnion(
  5204. + const std::vector<URLPatternSet>& sets) {
  5205. + URLPatternSet result;
  5206. + if (sets.empty())
  5207. + return result;
  5208. +
  5209. + // N-way union algorithm is basic O(nlog(n)) merge algorithm.
  5210. + //
  5211. + // Do the first merge step into a working set so that we don't mutate any of
  5212. + // the input.
  5213. + // TODO(devlin): Looks like this creates a bunch of copies; we can probably
  5214. + // clean that up.
  5215. + std::vector<URLPatternSet> working;
  5216. + for (size_t i = 0; i < sets.size(); i += 2) {
  5217. + if (i + 1 < sets.size())
  5218. + working.push_back(CreateUnion(sets[i], sets[i + 1]));
  5219. + else
  5220. + working.push_back(sets[i].Clone());
  5221. + }
  5222. +
  5223. + for (size_t skip = 1; skip < working.size(); skip *= 2) {
  5224. + for (size_t i = 0; i < (working.size() - skip); i += skip) {
  5225. + URLPatternSet u = CreateUnion(working[i], working[i + skip]);
  5226. + working[i].patterns_.swap(u.patterns_);
  5227. + }
  5228. + }
  5229. +
  5230. + result.patterns_.swap(working[0].patterns_);
  5231. + return result;
  5232. +}
  5233. +
  5234. +URLPatternSet::URLPatternSet() = default;
  5235. +
  5236. +URLPatternSet::URLPatternSet(URLPatternSet&& rhs) = default;
  5237. +
  5238. +URLPatternSet::URLPatternSet(const std::set<URLPattern>& patterns)
  5239. + : patterns_(patterns) {}
  5240. +
  5241. +URLPatternSet::~URLPatternSet() = default;
  5242. +
  5243. +URLPatternSet& URLPatternSet::operator=(URLPatternSet&& rhs) = default;
  5244. +
  5245. +bool URLPatternSet::operator==(const URLPatternSet& other) const {
  5246. + return patterns_ == other.patterns_;
  5247. +}
  5248. +
  5249. +std::ostream& operator<<(std::ostream& out,
  5250. + const URLPatternSet& url_pattern_set) {
  5251. + out << "{ ";
  5252. +
  5253. + auto iter = url_pattern_set.patterns().cbegin();
  5254. + if (!url_pattern_set.patterns().empty()) {
  5255. + out << *iter;
  5256. + ++iter;
  5257. + }
  5258. +
  5259. + for (;iter != url_pattern_set.patterns().end(); ++iter)
  5260. + out << ", " << *iter;
  5261. +
  5262. + if (!url_pattern_set.patterns().empty())
  5263. + out << " ";
  5264. +
  5265. + out << "}";
  5266. + return out;
  5267. +}
  5268. +
  5269. +URLPatternSet URLPatternSet::Clone() const {
  5270. + return URLPatternSet(patterns_);
  5271. +}
  5272. +
  5273. +bool URLPatternSet::is_empty() const {
  5274. + return patterns_.empty();
  5275. +}
  5276. +
  5277. +size_t URLPatternSet::size() const {
  5278. + return patterns_.size();
  5279. +}
  5280. +
  5281. +bool URLPatternSet::AddPattern(const URLPattern& pattern) {
  5282. + return patterns_.insert(pattern).second;
  5283. +}
  5284. +
  5285. +void URLPatternSet::AddPatterns(const URLPatternSet& set) {
  5286. + patterns_.insert(set.patterns().begin(),
  5287. + set.patterns().end());
  5288. +}
  5289. +
  5290. +void URLPatternSet::ClearPatterns() {
  5291. + patterns_.clear();
  5292. +}
  5293. +
  5294. +bool URLPatternSet::AddOrigin(int valid_schemes, const GURL& origin) {
  5295. + if (origin.is_empty())
  5296. + return false;
  5297. + const url::Origin real_origin = url::Origin::Create(origin);
  5298. + DCHECK(real_origin.IsSameOriginWith(url::Origin::Create(origin.GetOrigin())));
  5299. + URLPattern origin_pattern(valid_schemes);
  5300. + // Origin adding could fail if |origin| does not match |valid_schemes|.
  5301. + if (origin_pattern.Parse(origin.spec()) !=
  5302. + URLPattern::ParseResult::kSuccess) {
  5303. + return false;
  5304. + }
  5305. + origin_pattern.SetPath("/*");
  5306. + return AddPattern(origin_pattern);
  5307. +}
  5308. +
  5309. +bool URLPatternSet::Contains(const URLPatternSet& other) const {
  5310. + for (auto it = other.begin(); it != other.end(); ++it) {
  5311. + if (!ContainsPattern(*it))
  5312. + return false;
  5313. + }
  5314. +
  5315. + return true;
  5316. +}
  5317. +
  5318. +bool URLPatternSet::ContainsPattern(const URLPattern& pattern) const {
  5319. + for (auto it = begin(); it != end(); ++it) {
  5320. + if (it->Contains(pattern))
  5321. + return true;
  5322. + }
  5323. + return false;
  5324. +}
  5325. +
  5326. +bool URLPatternSet::MatchesURL(const GURL& url) const {
  5327. + for (auto pattern = patterns_.cbegin(); pattern != patterns_.cend();
  5328. + ++pattern) {
  5329. + if (pattern->MatchesURL(url)) {
  5330. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  5331. + LOG(INFO) << "UserScripts: URLPatternSet::MatchesURL true " << url.spec();
  5332. +
  5333. + return true;
  5334. + }
  5335. + }
  5336. +
  5337. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  5338. + LOG(INFO) << "UserScripts: URLPatternSet::MatchesURL false " << url.spec();
  5339. +
  5340. + return false;
  5341. +}
  5342. +
  5343. +bool URLPatternSet::MatchesAllURLs() const {
  5344. + for (auto host = begin(); host != end(); ++host) {
  5345. + if (host->match_all_urls() ||
  5346. + (host->match_subdomains() && host->host().empty()))
  5347. + return true;
  5348. + }
  5349. + return false;
  5350. +}
  5351. +
  5352. +bool URLPatternSet::MatchesSecurityOrigin(const GURL& origin) const {
  5353. + for (auto pattern = patterns_.begin(); pattern != patterns_.end();
  5354. + ++pattern) {
  5355. + if (pattern->MatchesSecurityOrigin(origin))
  5356. + return true;
  5357. + }
  5358. +
  5359. + return false;
  5360. +}
  5361. +
  5362. +bool URLPatternSet::OverlapsWith(const URLPatternSet& other) const {
  5363. + // Two extension extents overlap if there is any one URL that would match at
  5364. + // least one pattern in each of the extents.
  5365. + for (auto i = patterns_.cbegin(); i != patterns_.cend(); ++i) {
  5366. + for (auto j = other.patterns().cbegin(); j != other.patterns().cend();
  5367. + ++j) {
  5368. + if (i->OverlapsWith(*j))
  5369. + return true;
  5370. + }
  5371. + }
  5372. +
  5373. + return false;
  5374. +}
  5375. +
  5376. +std::unique_ptr<base::ListValue> URLPatternSet::ToValue() const {
  5377. + std::unique_ptr<base::ListValue> value(new base::ListValue);
  5378. + for (auto i = patterns_.cbegin(); i != patterns_.cend(); ++i)
  5379. + value->AppendIfNotPresent(std::make_unique<base::Value>(i->GetAsString()));
  5380. + return value;
  5381. +}
  5382. +
  5383. +bool URLPatternSet::Populate(const std::vector<std::string>& patterns,
  5384. + int valid_schemes,
  5385. + bool allow_file_access,
  5386. + std::string* error) {
  5387. + ClearPatterns();
  5388. + for (size_t i = 0; i < patterns.size(); ++i) {
  5389. + URLPattern pattern(valid_schemes);
  5390. + if (pattern.Parse(patterns[i]) != URLPattern::ParseResult::kSuccess) {
  5391. + if (error) {
  5392. + *error = ErrorUtils::FormatErrorMessage(kInvalidURLPatternError,
  5393. + patterns[i]);
  5394. + } else {
  5395. + LOG(ERROR) << "Invalid url pattern: " << patterns[i];
  5396. + }
  5397. + return false;
  5398. + }
  5399. + if (!allow_file_access && pattern.MatchesScheme(url::kFileScheme)) {
  5400. + pattern.SetValidSchemes(
  5401. + pattern.valid_schemes() & ~URLPattern::SCHEME_FILE);
  5402. + }
  5403. + AddPattern(pattern);
  5404. + }
  5405. + return true;
  5406. +}
  5407. +
  5408. +std::unique_ptr<std::vector<std::string>> URLPatternSet::ToStringVector()
  5409. + const {
  5410. + std::unique_ptr<std::vector<std::string>> value(new std::vector<std::string>);
  5411. + for (auto i = patterns_.cbegin(); i != patterns_.cend(); ++i) {
  5412. + value->push_back(i->GetAsString());
  5413. + }
  5414. + return value;
  5415. +}
  5416. +
  5417. +bool URLPatternSet::Populate(const base::ListValue& value,
  5418. + int valid_schemes,
  5419. + bool allow_file_access,
  5420. + std::string* error) {
  5421. + std::vector<std::string> patterns;
  5422. + for (size_t i = 0; i < value.GetSize(); ++i) {
  5423. + std::string item;
  5424. + if (!value.GetString(i, &item))
  5425. + return false;
  5426. + patterns.push_back(item);
  5427. + }
  5428. + return Populate(patterns, valid_schemes, allow_file_access, error);
  5429. +}
  5430. +
  5431. +} // namespace extensions
  5432. diff --git a/components/user_scripts/common/url_pattern_set.h b/components/user_scripts/common/url_pattern_set.h
  5433. new file mode 100755
  5434. --- /dev/null
  5435. +++ b/components/user_scripts/common/url_pattern_set.h
  5436. @@ -0,0 +1,161 @@
  5437. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  5438. +// Use of this source code is governed by a BSD-style license that can be
  5439. +// found in the LICENSE file.
  5440. +
  5441. +#ifndef EXTENSIONS_COMMON_URL_PATTERN_SET_H_
  5442. +#define EXTENSIONS_COMMON_URL_PATTERN_SET_H_
  5443. +
  5444. +#include <stddef.h>
  5445. +
  5446. +#include <iosfwd>
  5447. +#include <memory>
  5448. +#include <set>
  5449. +
  5450. +#include "base/macros.h"
  5451. +#include "url_pattern.h"
  5452. +
  5453. +class GURL;
  5454. +
  5455. +namespace base {
  5456. +class ListValue;
  5457. +class Value;
  5458. +}
  5459. +
  5460. +namespace user_scripts {
  5461. +
  5462. +// Represents the set of URLs an extension uses for web content.
  5463. +class URLPatternSet {
  5464. + public:
  5465. + typedef std::set<URLPattern>::const_iterator const_iterator;
  5466. + typedef std::set<URLPattern>::iterator iterator;
  5467. +
  5468. + // Returns |set1| - |set2|.
  5469. + static URLPatternSet CreateDifference(const URLPatternSet& set1,
  5470. + const URLPatternSet& set2);
  5471. +
  5472. + enum class IntersectionBehavior {
  5473. + // For the following descriptions, consider the two URLPatternSets:
  5474. + // Set 1: {"https://example.com/*", "https://*.google.com/*", "http://*/*"}
  5475. + // Set 2: {"https://example.com/*", "https://google.com/maps",
  5476. + // "*://chromium.org/*"}
  5477. +
  5478. + // Only includes patterns that are exactly in both sets. The intersection of
  5479. + // the two sets above is {"https://example.com/*"}, since that is the only
  5480. + // pattern that appears exactly in each.
  5481. + kStringComparison,
  5482. +
  5483. + // Includes patterns that are effectively contained by both sets. The
  5484. + // intersection of the two sets above is
  5485. + // {
  5486. + // "https://example.com/*" (contained exactly by each set)
  5487. + // "https://google.com/maps" (contained exactly by set 2 and a strict
  5488. + // subset of https://*.google.com/* in set 1)
  5489. + // }
  5490. + kPatternsContainedByBoth,
  5491. +
  5492. + // Includes patterns that are contained by both sets and creates new
  5493. + // patterns to represent the intersection of any others. The intersection of
  5494. + // the two sets above is
  5495. + // {
  5496. + // "https://example.com/*" (contained exactly by each set)
  5497. + // "https://google.com/maps" (contained exactly by set 2 and a strict
  5498. + // subset of https://*.google.com/* in set 1)
  5499. + // "http://chromium.org/*" (the overlap between "http://*/*" in set 1 and
  5500. + // *://chromium.org/*" in set 2).
  5501. + // }
  5502. + // Note that this is the most computationally expensive - potentially
  5503. + // O(n^2) - since it can require comparing each pattern in one set to every
  5504. + // pattern in the other set.
  5505. + kDetailed,
  5506. + };
  5507. +
  5508. + // Returns the intersection of |set1| and |set2| according to
  5509. + // |intersection_behavior|.
  5510. + static URLPatternSet CreateIntersection(
  5511. + const URLPatternSet& set1,
  5512. + const URLPatternSet& set2,
  5513. + IntersectionBehavior intersection_behavior);
  5514. +
  5515. + // Returns the union of |set1| and |set2|.
  5516. + static URLPatternSet CreateUnion(const URLPatternSet& set1,
  5517. + const URLPatternSet& set2);
  5518. +
  5519. + // Returns the union of all sets in |sets|.
  5520. + static URLPatternSet CreateUnion(const std::vector<URLPatternSet>& sets);
  5521. +
  5522. + URLPatternSet();
  5523. + URLPatternSet(URLPatternSet&& rhs);
  5524. + explicit URLPatternSet(const std::set<URLPattern>& patterns);
  5525. + ~URLPatternSet();
  5526. +
  5527. + URLPatternSet& operator=(URLPatternSet&& rhs);
  5528. + bool operator==(const URLPatternSet& rhs) const;
  5529. +
  5530. + bool is_empty() const;
  5531. + size_t size() const;
  5532. + const std::set<URLPattern>& patterns() const { return patterns_; }
  5533. + const_iterator begin() const { return patterns_.begin(); }
  5534. + const_iterator end() const { return patterns_.end(); }
  5535. + iterator erase(iterator iter) { return patterns_.erase(iter); }
  5536. +
  5537. + // Returns a copy of this URLPatternSet; not instrumented as a copy
  5538. + // constructor to avoid accidental/unnecessary copies.
  5539. + URLPatternSet Clone() const;
  5540. +
  5541. + // Adds a pattern to the set. Returns true if a new pattern was inserted,
  5542. + // false if the pattern was already in the set.
  5543. + bool AddPattern(const URLPattern& pattern);
  5544. +
  5545. + // Adds all patterns from |set| into this.
  5546. + void AddPatterns(const URLPatternSet& set);
  5547. +
  5548. + void ClearPatterns();
  5549. +
  5550. + // Adds a pattern based on |origin| to the set.
  5551. + bool AddOrigin(int valid_schemes, const GURL& origin);
  5552. +
  5553. + // Returns true if every URL that matches |set| is matched by this. In other
  5554. + // words, if every pattern in |set| is encompassed by a pattern in this.
  5555. + bool Contains(const URLPatternSet& set) const;
  5556. +
  5557. + // Returns true if any pattern in this set encompasses |pattern|.
  5558. + bool ContainsPattern(const URLPattern& pattern) const;
  5559. +
  5560. + // Test if the extent contains a URL.
  5561. + bool MatchesURL(const GURL& url) const;
  5562. +
  5563. + // Test if the extent matches all URLs (for example, <all_urls>).
  5564. + bool MatchesAllURLs() const;
  5565. +
  5566. + bool MatchesSecurityOrigin(const GURL& origin) const;
  5567. +
  5568. + // Returns true if there is a single URL that would be in two extents.
  5569. + bool OverlapsWith(const URLPatternSet& other) const;
  5570. +
  5571. + // Converts to and from Value for serialization to preferences.
  5572. + std::unique_ptr<base::ListValue> ToValue() const;
  5573. + bool Populate(const base::ListValue& value,
  5574. + int valid_schemes,
  5575. + bool allow_file_access,
  5576. + std::string* error);
  5577. +
  5578. + // Converts to and from a vector of strings.
  5579. + std::unique_ptr<std::vector<std::string>> ToStringVector() const;
  5580. + bool Populate(const std::vector<std::string>& patterns,
  5581. + int valid_schemes,
  5582. + bool allow_file_access,
  5583. + std::string* error);
  5584. +
  5585. + private:
  5586. + // The list of URL patterns that comprise the extent.
  5587. + std::set<URLPattern> patterns_;
  5588. +
  5589. + DISALLOW_COPY_AND_ASSIGN(URLPatternSet);
  5590. +};
  5591. +
  5592. +std::ostream& operator<<(std::ostream& out,
  5593. + const URLPatternSet& url_pattern_set);
  5594. +
  5595. +} // namespace extensions
  5596. +
  5597. +#endif // EXTENSIONS_COMMON_URL_PATTERN_SET_H_
  5598. diff --git a/components/user_scripts/common/user_script.cc b/components/user_scripts/common/user_script.cc
  5599. new file mode 100755
  5600. --- /dev/null
  5601. +++ b/components/user_scripts/common/user_script.cc
  5602. @@ -0,0 +1,351 @@
  5603. +// Copyright 2013 The Chromium Authors. All rights reserved.
  5604. +// Use of this source code is governed by a BSD-style license that can be
  5605. +// found in the LICENSE file.
  5606. +
  5607. +#include "user_script.h"
  5608. +
  5609. +#include <stddef.h>
  5610. +#include <stdint.h>
  5611. +
  5612. +#include <memory>
  5613. +#include <utility>
  5614. +
  5615. +#include "base/atomic_sequence_num.h"
  5616. +#include "base/command_line.h"
  5617. +#include "base/pickle.h"
  5618. +#include "base/strings/pattern.h"
  5619. +#include "base/strings/string_util.h"
  5620. +#include "user_scripts_features.h"
  5621. +
  5622. +namespace {
  5623. +
  5624. +// This cannot be a plain int or int64_t because we need to generate unique IDs
  5625. +// from multiple threads.
  5626. +base::AtomicSequenceNumber g_user_script_id_generator;
  5627. +
  5628. +bool UrlMatchesGlobs(const std::vector<std::string>* globs,
  5629. + const GURL& url) {
  5630. + for (auto glob = globs->cbegin(); glob != globs->cend(); ++glob) {
  5631. + if (base::MatchPattern(url.spec(), *glob))
  5632. + return true;
  5633. + }
  5634. +
  5635. + return false;
  5636. +}
  5637. +
  5638. +} // namespace
  5639. +
  5640. +namespace user_scripts {
  5641. +
  5642. +// The bitmask for valid user script injectable schemes used by URLPattern.
  5643. +enum {
  5644. + kValidUserScriptSchemes = //URLPattern::SCHEME_CHROMEUI |
  5645. + URLPattern::SCHEME_HTTP |
  5646. + URLPattern::SCHEME_HTTPS
  5647. + //| URLPattern::SCHEME_FILE |
  5648. + //URLPattern::SCHEME_FTP
  5649. +};
  5650. +
  5651. +// static
  5652. +const char UserScript::kFileExtension[] = ".user.js";
  5653. +
  5654. +// static
  5655. +int UserScript::GenerateUserScriptID() {
  5656. + return g_user_script_id_generator.GetNext();
  5657. +}
  5658. +
  5659. +bool UserScript::IsURLUserScript(const GURL& url,
  5660. + const std::string& mime_type) {
  5661. + return base::EndsWith(url.ExtractFileName(), kFileExtension,
  5662. + base::CompareCase::INSENSITIVE_ASCII) &&
  5663. + mime_type != "text/html";
  5664. +}
  5665. +
  5666. +// static
  5667. +int UserScript::ValidUserScriptSchemes(bool canExecuteScriptEverywhere) {
  5668. + if (canExecuteScriptEverywhere)
  5669. + return URLPattern::SCHEME_ALL;
  5670. + int valid_schemes = kValidUserScriptSchemes;
  5671. + // if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
  5672. + // switches::kExtensionsOnChromeURLs)) {
  5673. + // valid_schemes &= ~URLPattern::SCHEME_CHROMEUI;
  5674. + // }
  5675. + return valid_schemes;
  5676. +}
  5677. +
  5678. +UserScript::File::File(const base::FilePath& extension_root,
  5679. + const base::FilePath& relative_path,
  5680. + const GURL& url)
  5681. + : extension_root_(extension_root),
  5682. + relative_path_(relative_path),
  5683. + url_(url) {
  5684. +}
  5685. +
  5686. +UserScript::File::File() {}
  5687. +
  5688. +UserScript::File::File(const File& other)
  5689. + : extension_root_(other.extension_root_),
  5690. + relative_path_(other.relative_path_),
  5691. + url_(other.url_),
  5692. + external_content_(other.external_content_),
  5693. + content_(other.content_),
  5694. + key_(other.key_) {}
  5695. +
  5696. +UserScript::File::~File() {}
  5697. +
  5698. +UserScript::UserScript() = default;
  5699. +UserScript::~UserScript() = default;
  5700. +
  5701. +// static.
  5702. +// std::unique_ptr<UserScript> UserScript::CopyMetadataFrom(
  5703. +// const UserScript& other) {
  5704. +// std::unique_ptr<UserScript> script(new UserScript());
  5705. +// script->run_location_ = other.run_location_;
  5706. +// script->name_space_ = other.name_space_;
  5707. +// script->name_ = other.name_;
  5708. +// script->description_ = other.description_;
  5709. +// script->version_ = other.version_;
  5710. +// script->globs_ = other.globs_;
  5711. +// script->exclude_globs_ = other.exclude_globs_;
  5712. +// script->url_set_ = other.url_set_.Clone();
  5713. +// script->exclude_url_set_ = other.exclude_url_set_.Clone();
  5714. +
  5715. +// // Note: File content is not copied.
  5716. +// for (const std::unique_ptr<File>& file : other.js_scripts()) {
  5717. +// std::unique_ptr<File> file_copy(new File(*file));
  5718. +// script->js_scripts_.push_back(std::move(file_copy));
  5719. +// }
  5720. +// for (const std::unique_ptr<File>& file : other.css_scripts()) {
  5721. +// std::unique_ptr<File> file_copy(new File(*file));
  5722. +// script->css_scripts_.push_back(std::move(file_copy));
  5723. +// }
  5724. +// script->host_id_ = other.host_id_;
  5725. +// script->consumer_instance_type_ = other.consumer_instance_type_;
  5726. +// script->user_script_id_ = other.user_script_id_;
  5727. +// script->emulate_greasemonkey_ = other.emulate_greasemonkey_;
  5728. +// script->match_all_frames_ = other.match_all_frames_;
  5729. +// script->match_origin_as_fallback_ = other.match_origin_as_fallback_;
  5730. +// script->incognito_enabled_ = other.incognito_enabled_;
  5731. +
  5732. +// return script;
  5733. +// }
  5734. +
  5735. +void UserScript::add_url_pattern(const URLPattern& pattern) {
  5736. + url_set_.AddPattern(pattern);
  5737. +}
  5738. +
  5739. +void UserScript::add_exclude_url_pattern(const URLPattern& pattern) {
  5740. + exclude_url_set_.AddPattern(pattern);
  5741. +}
  5742. +
  5743. +bool UserScript::MatchesURL(const GURL& url) const {
  5744. + if (!url_set_.is_empty()) {
  5745. + if (!url_set_.MatchesURL(url)) {
  5746. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  5747. + LOG(INFO) << "UserScripts: No Match for url_set";
  5748. + return false;
  5749. + }
  5750. + }
  5751. +
  5752. + if (!exclude_url_set_.is_empty()) {
  5753. + if (exclude_url_set_.MatchesURL(url)) {
  5754. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  5755. + LOG(INFO) << "UserScripts: No Match for exclude_url_set";
  5756. + return false;
  5757. + }
  5758. + }
  5759. +
  5760. + if (!globs_.empty()) {
  5761. + if (!UrlMatchesGlobs(&globs_, url)) {
  5762. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  5763. + LOG(INFO) << "UserScripts: No Match for globs";
  5764. + return false;
  5765. + }
  5766. + }
  5767. +
  5768. + if (!exclude_globs_.empty()) {
  5769. + if (UrlMatchesGlobs(&exclude_globs_, url)) {
  5770. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  5771. + LOG(INFO) << "UserScripts: No Match for exclude_globs";
  5772. + return false;
  5773. + }
  5774. + }
  5775. +
  5776. + return true;
  5777. +}
  5778. +
  5779. +bool UserScript::MatchesDocument(const GURL& effective_document_url,
  5780. + bool is_subframe) const {
  5781. + if (is_subframe && !match_all_frames())
  5782. + return false;
  5783. +
  5784. + return MatchesURL(effective_document_url);
  5785. +}
  5786. +
  5787. +void UserScript::File::Pickle(base::Pickle* pickle) const {
  5788. + pickle->WriteString(url_.spec());
  5789. + // Do not write path. It's not needed in the renderer.
  5790. + // Do not write content. It will be serialized by other means.
  5791. +}
  5792. +
  5793. +void UserScript::File::Unpickle(const base::Pickle& pickle,
  5794. + base::PickleIterator* iter) {
  5795. + // Read the url from the pickle.
  5796. + std::string url;
  5797. + CHECK(iter->ReadString(&url));
  5798. + set_url(GURL(url));
  5799. +}
  5800. +
  5801. +void UserScript::Pickle(base::Pickle* pickle) const {
  5802. + // Write the simple types to the pickle.
  5803. + pickle->WriteInt(run_location());
  5804. + pickle->WriteInt(user_script_id_);
  5805. + pickle->WriteBool(emulate_greasemonkey());
  5806. + pickle->WriteBool(match_all_frames());
  5807. + pickle->WriteInt(static_cast<int>(match_origin_as_fallback()));
  5808. + pickle->WriteBool(is_incognito_enabled());
  5809. +
  5810. + PickleHostID(pickle, host_id_);
  5811. + pickle->WriteInt(consumer_instance_type());
  5812. + PickleGlobs(pickle, globs_);
  5813. + PickleGlobs(pickle, exclude_globs_);
  5814. + PickleURLPatternSet(pickle, url_set_);
  5815. + PickleURLPatternSet(pickle, exclude_url_set_);
  5816. + PickleScripts(pickle, js_scripts_);
  5817. + PickleScripts(pickle, css_scripts_);
  5818. +}
  5819. +
  5820. +void UserScript::PickleGlobs(base::Pickle* pickle,
  5821. + const std::vector<std::string>& globs) const {
  5822. + pickle->WriteUInt32(globs.size());
  5823. + for (auto glob = globs.cbegin(); glob != globs.cend(); ++glob) {
  5824. + pickle->WriteString(*glob);
  5825. + }
  5826. +}
  5827. +
  5828. +void UserScript::PickleHostID(base::Pickle* pickle,
  5829. + const HostID& host_id) const {
  5830. + pickle->WriteInt(host_id.type());
  5831. + pickle->WriteString(host_id.id());
  5832. +}
  5833. +
  5834. +void UserScript::PickleURLPatternSet(base::Pickle* pickle,
  5835. + const URLPatternSet& pattern_list) const {
  5836. + pickle->WriteUInt32(pattern_list.patterns().size());
  5837. + for (auto pattern = pattern_list.begin(); pattern != pattern_list.end();
  5838. + ++pattern) {
  5839. + pickle->WriteInt(pattern->valid_schemes());
  5840. + pickle->WriteString(pattern->GetAsString());
  5841. + }
  5842. +}
  5843. +
  5844. +void UserScript::PickleScripts(base::Pickle* pickle,
  5845. + const FileList& scripts) const {
  5846. + pickle->WriteUInt32(scripts.size());
  5847. + for (const std::unique_ptr<File>& file : scripts)
  5848. + file->Pickle(pickle);
  5849. +}
  5850. +
  5851. +void UserScript::Unpickle(const base::Pickle& pickle,
  5852. + base::PickleIterator* iter) {
  5853. + // Read the run location.
  5854. + int run_location = 0;
  5855. + CHECK(iter->ReadInt(&run_location));
  5856. + CHECK(run_location >= 0 && run_location < RUN_LOCATION_LAST);
  5857. + run_location_ = static_cast<RunLocation>(run_location);
  5858. +
  5859. + CHECK(iter->ReadInt(&user_script_id_));
  5860. + CHECK(iter->ReadBool(&emulate_greasemonkey_));
  5861. + CHECK(iter->ReadBool(&match_all_frames_));
  5862. + int match_origin_as_fallback_int = 0;
  5863. + CHECK(iter->ReadInt(&match_origin_as_fallback_int));
  5864. + match_origin_as_fallback_ =
  5865. + static_cast<MatchOriginAsFallbackBehavior>(match_origin_as_fallback_int);
  5866. + CHECK(iter->ReadBool(&incognito_enabled_));
  5867. +
  5868. + UnpickleHostID(pickle, iter, &host_id_);
  5869. +
  5870. + int consumer_instance_type = 0;
  5871. + CHECK(iter->ReadInt(&consumer_instance_type));
  5872. + consumer_instance_type_ =
  5873. + static_cast<ConsumerInstanceType>(consumer_instance_type);
  5874. +
  5875. + UnpickleGlobs(pickle, iter, &globs_);
  5876. + UnpickleGlobs(pickle, iter, &exclude_globs_);
  5877. + UnpickleURLPatternSet(pickle, iter, &url_set_);
  5878. + UnpickleURLPatternSet(pickle, iter, &exclude_url_set_);
  5879. + UnpickleScripts(pickle, iter, &js_scripts_);
  5880. + UnpickleScripts(pickle, iter, &css_scripts_);
  5881. +}
  5882. +
  5883. +void UserScript::UnpickleGlobs(const base::Pickle& pickle,
  5884. + base::PickleIterator* iter,
  5885. + std::vector<std::string>* globs) {
  5886. + uint32_t num_globs = 0;
  5887. + CHECK(iter->ReadUInt32(&num_globs));
  5888. + globs->clear();
  5889. + for (uint32_t i = 0; i < num_globs; ++i) {
  5890. + std::string glob;
  5891. + CHECK(iter->ReadString(&glob));
  5892. + globs->push_back(glob);
  5893. + }
  5894. +}
  5895. +
  5896. +void UserScript::UnpickleHostID(const base::Pickle& pickle,
  5897. + base::PickleIterator* iter,
  5898. + HostID* host_id) {
  5899. + int type = 0;
  5900. + std::string id;
  5901. + CHECK(iter->ReadInt(&type));
  5902. + CHECK(iter->ReadString(&id));
  5903. + *host_id = HostID(static_cast<HostID::HostType>(type), id);
  5904. +}
  5905. +
  5906. +void UserScript::UnpickleURLPatternSet(const base::Pickle& pickle,
  5907. + base::PickleIterator* iter,
  5908. + URLPatternSet* pattern_list) {
  5909. + uint32_t num_patterns = 0;
  5910. + CHECK(iter->ReadUInt32(&num_patterns));
  5911. +
  5912. + pattern_list->ClearPatterns();
  5913. + for (uint32_t i = 0; i < num_patterns; ++i) {
  5914. + int valid_schemes;
  5915. + CHECK(iter->ReadInt(&valid_schemes));
  5916. +
  5917. + std::string pattern_str;
  5918. + CHECK(iter->ReadString(&pattern_str));
  5919. +
  5920. + URLPattern pattern(kValidUserScriptSchemes);
  5921. + URLPattern::ParseResult result = pattern.Parse(pattern_str);
  5922. + CHECK(URLPattern::ParseResult::kSuccess == result)
  5923. + << URLPattern::GetParseResultString(result) << " "
  5924. + << pattern_str.c_str();
  5925. +
  5926. + pattern.SetValidSchemes(valid_schemes);
  5927. + pattern_list->AddPattern(pattern);
  5928. + }
  5929. +}
  5930. +
  5931. +void UserScript::UnpickleScripts(const base::Pickle& pickle,
  5932. + base::PickleIterator* iter,
  5933. + FileList* scripts) {
  5934. + uint32_t num_files = 0;
  5935. + CHECK(iter->ReadUInt32(&num_files));
  5936. + scripts->clear();
  5937. + for (uint32_t i = 0; i < num_files; ++i) {
  5938. + std::unique_ptr<File> file(new File());
  5939. + file->Unpickle(pickle, iter);
  5940. + scripts->push_back(std::move(file));
  5941. + }
  5942. +}
  5943. +
  5944. +UserScriptIDPair::UserScriptIDPair(int id, const HostID& host_id)
  5945. + : id(id), host_id(host_id) {}
  5946. +
  5947. +UserScriptIDPair::UserScriptIDPair(int id) : id(id), host_id(HostID()) {}
  5948. +
  5949. +bool operator<(const UserScriptIDPair& a, const UserScriptIDPair& b) {
  5950. + return a.id < b.id;
  5951. +}
  5952. +
  5953. +} // namespace extensions
  5954. diff --git a/components/user_scripts/common/user_script.h b/components/user_scripts/common/user_script.h
  5955. new file mode 100755
  5956. --- /dev/null
  5957. +++ b/components/user_scripts/common/user_script.h
  5958. @@ -0,0 +1,371 @@
  5959. +// Copyright 2013 The Chromium Authors. All rights reserved.
  5960. +// Use of this source code is governed by a BSD-style license that can be
  5961. +// found in the LICENSE file.
  5962. +
  5963. +#ifndef EXTENSIONS_COMMON_USER_SCRIPT_H_
  5964. +#define EXTENSIONS_COMMON_USER_SCRIPT_H_
  5965. +
  5966. +#include <memory>
  5967. +#include <string>
  5968. +#include <vector>
  5969. +
  5970. +#include "base/files/file_path.h"
  5971. +#include "base/strings/string_piece.h"
  5972. +#include "script_constants.h"
  5973. +#include "host_id.h"
  5974. +#include "url_pattern.h"
  5975. +#include "url_pattern_set.h"
  5976. +#include "url/gurl.h"
  5977. +
  5978. +namespace base {
  5979. +class Pickle;
  5980. +class PickleIterator;
  5981. +}
  5982. +
  5983. +namespace user_scripts {
  5984. +
  5985. +// Represents a user script, either a standalone one, or one that is part of an
  5986. +// extension.
  5987. +class UserScript {
  5988. + public:
  5989. + // The file extension for standalone user scripts.
  5990. + static const char kFileExtension[];
  5991. +
  5992. + static int GenerateUserScriptID();
  5993. +
  5994. + // Check if a URL should be treated as a user script and converted to an
  5995. + // extension.
  5996. + static bool IsURLUserScript(const GURL& url, const std::string& mime_type);
  5997. +
  5998. + // Get the valid user script schemes for the current process. If
  5999. + // canExecuteScriptEverywhere is true, this will return ALL_SCHEMES.
  6000. + static int ValidUserScriptSchemes(bool canExecuteScriptEverywhere = false);
  6001. +
  6002. + // TODO(rdevlin.cronin) This and RunLocation don't really belong here, since
  6003. + // they are used for more than UserScripts (e.g., tabs.executeScript()).
  6004. + // The type of injected script.
  6005. + enum InjectionType {
  6006. + // A content script specified in the extension's manifest.
  6007. + CONTENT_SCRIPT,
  6008. + // A script injected via, e.g. tabs.executeScript().
  6009. + //PROGRAMMATIC_SCRIPT
  6010. + };
  6011. + // The last type of injected script; used for enum verification in IPC.
  6012. + // Update this if you add more injected script types!
  6013. + static const InjectionType INJECTION_TYPE_LAST = CONTENT_SCRIPT/*PROGRAMMATIC_SCRIPT*/;
  6014. +
  6015. + // Locations that user scripts can be run inside the document.
  6016. + // The three run locations must strictly follow each other in both load order
  6017. + // (i.e., start *always* comes before end) and numerically, as we use
  6018. + // arithmetic checking (e.g., curr == last + 1). So, no bitmasks here!!
  6019. + enum RunLocation {
  6020. + UNDEFINED,
  6021. + DOCUMENT_START, // After the documentElement is created, but before
  6022. + // anything else happens.
  6023. + DOCUMENT_END, // After the entire document is parsed. Same as
  6024. + // DOMContentLoaded.
  6025. + DOCUMENT_IDLE, // Sometime after DOMContentLoaded, as soon as the document
  6026. + // is "idle". Currently this uses the simple heuristic of:
  6027. + // min(DOM_CONTENT_LOADED + TIMEOUT, ONLOAD), but no
  6028. + // particular injection point is guaranteed.
  6029. + RUN_DEFERRED, // The user script's injection was deferred for permissions
  6030. + // reasons, and was executed at a later time.
  6031. + BROWSER_DRIVEN, // The user script will be injected when triggered by an
  6032. + // IPC in the browser process.
  6033. + RUN_LOCATION_LAST // Leave this as the last item.
  6034. + };
  6035. +
  6036. + // Holds script file info.
  6037. + class File {
  6038. + public:
  6039. + File(const base::FilePath& extension_root,
  6040. + const base::FilePath& relative_path,
  6041. + const GURL& url);
  6042. + File();
  6043. + File(const File& other);
  6044. + ~File();
  6045. +
  6046. + const base::FilePath& extension_root() const { return extension_root_; }
  6047. + const base::FilePath& relative_path() const { return relative_path_; }
  6048. +
  6049. + const GURL& url() const { return url_; }
  6050. + void set_url(const GURL& url) { url_ = url; }
  6051. +
  6052. + // If external_content_ is set returns it as content otherwise it returns
  6053. + // content_
  6054. + const base::StringPiece GetContent() const {
  6055. + if (external_content_.data())
  6056. + return external_content_;
  6057. + else
  6058. + return content_;
  6059. + }
  6060. + void set_external_content(const base::StringPiece& content) {
  6061. + external_content_ = content;
  6062. + }
  6063. + void set_content(const base::StringPiece& content) {
  6064. + content_.assign(content.begin(), content.end());
  6065. + }
  6066. +
  6067. + const std::string& key() const { return key_; }
  6068. + void set_key(const std::string& key) {
  6069. + key_ = key;
  6070. + }
  6071. +
  6072. + // Serialization support. The content and FilePath members will not be
  6073. + // serialized!
  6074. + void Pickle(base::Pickle* pickle) const;
  6075. + void Unpickle(const base::Pickle& pickle, base::PickleIterator* iter);
  6076. +
  6077. + private:
  6078. + // Where the script file lives on the disk. We keep the path split so that
  6079. + // it can be localized at will.
  6080. + base::FilePath extension_root_;
  6081. + base::FilePath relative_path_;
  6082. +
  6083. + // The url to this script file.
  6084. + GURL url_;
  6085. +
  6086. + // The script content. It can be set to either loaded_content_ or
  6087. + // externally allocated string.
  6088. + base::StringPiece external_content_;
  6089. +
  6090. + // Set when the content is loaded by LoadContent
  6091. + std::string content_;
  6092. +
  6093. + std::string key_;
  6094. + };
  6095. +
  6096. + using FileList = std::vector<std::unique_ptr<File>>;
  6097. +
  6098. + // Type of a API consumer instance that user scripts will be injected on.
  6099. + enum ConsumerInstanceType { TAB, WEBVIEW };
  6100. +
  6101. + // Constructor. Default the run location to document end, which is like
  6102. + // Greasemonkey and probably more useful for typical scripts.
  6103. + UserScript();
  6104. + ~UserScript();
  6105. +
  6106. + // Performs a copy of all fields except file contents.
  6107. + // static std::unique_ptr<UserScript> CopyMetadataFrom(const UserScript& other);
  6108. +
  6109. + const std::string& name_space() const { return name_space_; }
  6110. + void set_name_space(const std::string& name_space) {
  6111. + name_space_ = name_space;
  6112. + }
  6113. +
  6114. + const std::string& name() const { return name_; }
  6115. + void set_name(const std::string& name) { name_ = name; }
  6116. +
  6117. + const std::string& version() const { return version_; }
  6118. + void set_version(const std::string& version) {
  6119. + version_ = version;
  6120. + }
  6121. +
  6122. + const std::string& key() const { return key_; }
  6123. + void set_key(const std::string& key) {
  6124. + key_ = key;
  6125. + }
  6126. +
  6127. + const std::string& description() const { return description_; }
  6128. + void set_description(const std::string& description) {
  6129. + description_ = description;
  6130. + }
  6131. +
  6132. + // The place in the document to run the script.
  6133. + RunLocation run_location() const { return run_location_; }
  6134. + void set_run_location(RunLocation location) { run_location_ = location; }
  6135. +
  6136. + // Whether to emulate greasemonkey when running this script.
  6137. + bool emulate_greasemonkey() const { return emulate_greasemonkey_; }
  6138. + void set_emulate_greasemonkey(bool val) { emulate_greasemonkey_ = val; }
  6139. +
  6140. + // Whether to match all frames, or only the top one.
  6141. + bool match_all_frames() const { return match_all_frames_; }
  6142. + void set_match_all_frames(bool val) { match_all_frames_ = val; }
  6143. +
  6144. + // Whether to match the origin as a fallback if the URL cannot be used
  6145. + // directly.
  6146. + MatchOriginAsFallbackBehavior match_origin_as_fallback() const {
  6147. + return match_origin_as_fallback_;
  6148. + }
  6149. + void set_match_origin_as_fallback(MatchOriginAsFallbackBehavior val) {
  6150. + match_origin_as_fallback_ = val;
  6151. + }
  6152. +
  6153. + // The globs, if any, that determine which pages this script runs against.
  6154. + // These are only used with "standalone" Greasemonkey-like user scripts.
  6155. + const std::vector<std::string>& globs() const { return globs_; }
  6156. + void add_glob(const std::string& glob) { globs_.push_back(glob); }
  6157. + void clear_globs() { globs_.clear(); }
  6158. + const std::vector<std::string>& exclude_globs() const {
  6159. + return exclude_globs_;
  6160. + }
  6161. + void add_exclude_glob(const std::string& glob) {
  6162. + exclude_globs_.push_back(glob);
  6163. + }
  6164. + void clear_exclude_globs() { exclude_globs_.clear(); }
  6165. +
  6166. + // The URLPatterns, if any, that determine which pages this script runs
  6167. + // against.
  6168. + const URLPatternSet& url_patterns() const { return url_set_; }
  6169. + void add_url_pattern(const URLPattern& pattern);
  6170. + const URLPatternSet& exclude_url_patterns() const {
  6171. + return exclude_url_set_;
  6172. + }
  6173. + void add_exclude_url_pattern(const URLPattern& pattern);
  6174. +
  6175. + // List of js scripts for this user script
  6176. + FileList& js_scripts() { return js_scripts_; }
  6177. + const FileList& js_scripts() const { return js_scripts_; }
  6178. +
  6179. + // List of css scripts for this user script
  6180. + FileList& css_scripts() { return css_scripts_; }
  6181. + const FileList& css_scripts() const { return css_scripts_; }
  6182. +
  6183. + const std::string& extension_id() const { return host_id_.id(); }
  6184. +
  6185. + const HostID& host_id() const { return host_id_; }
  6186. + void set_host_id(const HostID& host_id) { host_id_ = host_id; }
  6187. +
  6188. + const ConsumerInstanceType& consumer_instance_type() const {
  6189. + return consumer_instance_type_;
  6190. + }
  6191. + void set_consumer_instance_type(
  6192. + const ConsumerInstanceType& consumer_instance_type) {
  6193. + consumer_instance_type_ = consumer_instance_type;
  6194. + }
  6195. +
  6196. + int id() const { return user_script_id_; }
  6197. + void set_id(int id) { user_script_id_ = id; }
  6198. +
  6199. + // TODO(lazyboy): Incognito information is extension specific, it doesn't
  6200. + // belong here. We should be able to determine this in the renderer/ where it
  6201. + // is used.
  6202. + bool is_incognito_enabled() const { return incognito_enabled_; }
  6203. + void set_incognito_enabled(bool enabled) { incognito_enabled_ = enabled; }
  6204. +
  6205. + // Returns true if the script should be applied to the specified URL, false
  6206. + // otherwise.
  6207. + bool MatchesURL(const GURL& url) const;
  6208. +
  6209. + // Returns true if the script should be applied to the given
  6210. + // |effective_document_url|. It is the caller's responsibility to calculate
  6211. + // |effective_document_url| based on match_origin_as_fallback().
  6212. + bool MatchesDocument(const GURL& effective_document_url,
  6213. + bool is_subframe) const;
  6214. +
  6215. + // Serializes the UserScript into a pickle. The content of the scripts and
  6216. + // paths to UserScript::Files will not be serialized!
  6217. + void Pickle(base::Pickle* pickle) const;
  6218. +
  6219. + // Deserializes the script from a pickle. Note that this always succeeds
  6220. + // because presumably we were the one that pickled it, and we did it
  6221. + // correctly.
  6222. + void Unpickle(const base::Pickle& pickle, base::PickleIterator* iter);
  6223. +
  6224. + private:
  6225. + // base::Pickle helper functions used to pickle the individual types of
  6226. + // components.
  6227. + void PickleGlobs(base::Pickle* pickle,
  6228. + const std::vector<std::string>& globs) const;
  6229. + void PickleHostID(base::Pickle* pickle, const HostID& host_id) const;
  6230. + void PickleURLPatternSet(base::Pickle* pickle,
  6231. + const URLPatternSet& pattern_list) const;
  6232. + void PickleScripts(base::Pickle* pickle, const FileList& scripts) const;
  6233. +
  6234. + // Unpickle helper functions used to unpickle individual types of components.
  6235. + void UnpickleGlobs(const base::Pickle& pickle,
  6236. + base::PickleIterator* iter,
  6237. + std::vector<std::string>* globs);
  6238. + void UnpickleHostID(const base::Pickle& pickle,
  6239. + base::PickleIterator* iter,
  6240. + HostID* host_id);
  6241. + void UnpickleURLPatternSet(const base::Pickle& pickle,
  6242. + base::PickleIterator* iter,
  6243. + URLPatternSet* pattern_list);
  6244. + void UnpickleScripts(const base::Pickle& pickle,
  6245. + base::PickleIterator* iter,
  6246. + FileList* scripts);
  6247. +
  6248. + // The location to run the script inside the document.
  6249. + RunLocation run_location_ = DOCUMENT_IDLE;
  6250. +
  6251. + // The namespace of the script. This is used by Greasemonkey in the same way
  6252. + // as XML namespaces. Only used when parsing Greasemonkey-style scripts.
  6253. + std::string name_space_;
  6254. +
  6255. + // The script's name. Only used when parsing Greasemonkey-style scripts.
  6256. + std::string name_;
  6257. +
  6258. + // A longer description. Only used when parsing Greasemonkey-style scripts.
  6259. + std::string description_;
  6260. +
  6261. + // A version number of the script. Only used when parsing Greasemonkey-style
  6262. + // scripts.
  6263. + std::string version_;
  6264. +
  6265. + // Greasemonkey-style globs that determine pages to inject the script into.
  6266. + // These are only used with standalone scripts.
  6267. + std::vector<std::string> globs_;
  6268. + std::vector<std::string> exclude_globs_;
  6269. +
  6270. + // URLPatterns that determine pages to inject the script into. These are
  6271. + // only used with scripts that are part of extensions.
  6272. + URLPatternSet url_set_;
  6273. + URLPatternSet exclude_url_set_;
  6274. +
  6275. + // List of js scripts defined in content_scripts
  6276. + FileList js_scripts_;
  6277. +
  6278. + // List of css scripts defined in content_scripts
  6279. + FileList css_scripts_;
  6280. +
  6281. + std::string key_;
  6282. +
  6283. + // The ID of the host this script is a part of. The |ID| of the
  6284. + // |host_id| can be empty if the script is a "standlone" user script.
  6285. + HostID host_id_;
  6286. +
  6287. + // The type of the consumer instance that the script will be injected.
  6288. + ConsumerInstanceType consumer_instance_type_ = TAB;
  6289. +
  6290. + // The globally-unique id associated with this user script. -1 indicates
  6291. + // "invalid".
  6292. + int user_script_id_ = -1;
  6293. +
  6294. + // Whether we should try to emulate Greasemonkey's APIs when running this
  6295. + // script.
  6296. + bool emulate_greasemonkey_ = false;
  6297. +
  6298. + // Whether the user script should run in all frames, or only just the top one.
  6299. + bool match_all_frames_ = false;
  6300. +
  6301. + // Whether the user script should run in frames whose initiator / precursor
  6302. + // origin matches a match pattern, if an appropriate URL cannot be found for
  6303. + // the frame for matching purposes, such as in the case of about:, data:, and
  6304. + // other schemes.
  6305. + MatchOriginAsFallbackBehavior match_origin_as_fallback_ =
  6306. + MatchOriginAsFallbackBehavior::kNever;
  6307. +
  6308. + // True if the script should be injected into an incognito tab.
  6309. + bool incognito_enabled_ = false;
  6310. +
  6311. + DISALLOW_COPY_AND_ASSIGN(UserScript);
  6312. +};
  6313. +
  6314. +// Information we need while removing scripts from a UserScriptLoader.
  6315. +struct UserScriptIDPair {
  6316. + UserScriptIDPair(int id, const HostID& host_id);
  6317. + explicit UserScriptIDPair(int id);
  6318. +
  6319. + int id;
  6320. + HostID host_id;
  6321. +};
  6322. +
  6323. +bool operator<(const UserScriptIDPair& a, const UserScriptIDPair& b);
  6324. +
  6325. +using UserScriptList = std::vector<std::unique_ptr<UserScript>>;
  6326. +
  6327. +} // namespace extensions
  6328. +
  6329. +#endif // EXTENSIONS_COMMON_USER_SCRIPT_H_
  6330. diff --git a/components/user_scripts/common/user_scripts_features.cc b/components/user_scripts/common/user_scripts_features.cc
  6331. new file mode 100644
  6332. --- /dev/null
  6333. +++ b/components/user_scripts/common/user_scripts_features.cc
  6334. @@ -0,0 +1,34 @@
  6335. +/*
  6336. + This file is part of Bromite.
  6337. +
  6338. + Bromite is free software: you can redistribute it and/or modify
  6339. + it under the terms of the GNU General Public License as published by
  6340. + the Free Software Foundation, either version 3 of the License, or
  6341. + (at your option) any later version.
  6342. +
  6343. + Bromite is distributed in the hope that it will be useful,
  6344. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  6345. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  6346. + GNU General Public License for more details.
  6347. +
  6348. + You should have received a copy of the GNU General Public License
  6349. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  6350. +*/
  6351. +
  6352. +#include "user_scripts_features.h"
  6353. +
  6354. +#include "build/build_config.h"
  6355. +
  6356. +namespace user_scripts {
  6357. +
  6358. +namespace features {
  6359. +
  6360. +const base::Feature kEnableUserScripts = {"EnableUserScripts",
  6361. + base::FEATURE_DISABLED_BY_DEFAULT};
  6362. +const base::Feature kEnableLoggingUserScripts =
  6363. + {"EnableLoggingUserScripts",
  6364. + base::FEATURE_DISABLED_BY_DEFAULT};
  6365. +
  6366. +}
  6367. +
  6368. +}
  6369. \ No newline at end of file
  6370. diff --git a/components/user_scripts/common/user_scripts_features.h b/components/user_scripts/common/user_scripts_features.h
  6371. new file mode 100644
  6372. --- /dev/null
  6373. +++ b/components/user_scripts/common/user_scripts_features.h
  6374. @@ -0,0 +1,35 @@
  6375. +/*
  6376. + This file is part of Bromite.
  6377. +
  6378. + Bromite is free software: you can redistribute it and/or modify
  6379. + it under the terms of the GNU General Public License as published by
  6380. + the Free Software Foundation, either version 3 of the License, or
  6381. + (at your option) any later version.
  6382. +
  6383. + Bromite is distributed in the hope that it will be useful,
  6384. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  6385. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  6386. + GNU General Public License for more details.
  6387. +
  6388. + You should have received a copy of the GNU General Public License
  6389. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  6390. +*/
  6391. +
  6392. +#ifndef COMPONENTS_USERSCRIPTS_COMMON_USERSCRIPTS_FEATURES_H_
  6393. +#define COMPONENTS_USERSCRIPTS_COMMON_USERSCRIPTS_FEATURES_H_
  6394. +
  6395. +// This file defines all the base::FeatureList features for the Password Manager
  6396. +// module.
  6397. +
  6398. +#include "base/feature_list.h"
  6399. +
  6400. +namespace user_scripts {
  6401. +
  6402. +namespace features {
  6403. + extern const base::Feature kEnableUserScripts;
  6404. + extern const base::Feature kEnableLoggingUserScripts;
  6405. +}
  6406. +
  6407. +}
  6408. +
  6409. +#endif
  6410. \ No newline at end of file
  6411. diff --git a/components/user_scripts/common/view_type.cc b/components/user_scripts/common/view_type.cc
  6412. new file mode 100755
  6413. --- /dev/null
  6414. +++ b/components/user_scripts/common/view_type.cc
  6415. @@ -0,0 +1,39 @@
  6416. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  6417. +// Use of this source code is governed by a BSD-style license that can be
  6418. +// found in the LICENSE file.
  6419. +
  6420. +#include "view_type.h"
  6421. +
  6422. +#include "base/strings/string_piece.h"
  6423. +
  6424. +namespace user_scripts {
  6425. +
  6426. +bool GetViewTypeFromString(const std::string& view_type,
  6427. + ViewType* view_type_out) {
  6428. + // TODO(devlin): This map doesn't contain the following values:
  6429. + // - VIEW_TYPE_BACKGROUND_CONTENTS
  6430. + // - VIEW_TYPE_COMPONENT
  6431. + // - VIEW_TYPE_EXTENSION_GUEST
  6432. + // Why? Is it just because we don't expose those types to JS?
  6433. + static const struct {
  6434. + ViewType type;
  6435. + base::StringPiece name;
  6436. + } constexpr kTypeMap[] = {
  6437. + // {VIEW_TYPE_APP_WINDOW, "APP_WINDOW"},
  6438. + // {VIEW_TYPE_EXTENSION_BACKGROUND_PAGE, "BACKGROUND"},
  6439. + // {VIEW_TYPE_EXTENSION_DIALOG, "EXTENSION_DIALOG"},
  6440. + // {VIEW_TYPE_EXTENSION_POPUP, "POPUP"},
  6441. + {VIEW_TYPE_TAB_CONTENTS, "TAB"},
  6442. + };
  6443. +
  6444. + for (const auto& entry : kTypeMap) {
  6445. + if (entry.name == view_type) {
  6446. + *view_type_out = entry.type;
  6447. + return true;
  6448. + }
  6449. + }
  6450. +
  6451. + return false;
  6452. +}
  6453. +
  6454. +} // namespace extensions
  6455. diff --git a/components/user_scripts/common/view_type.h b/components/user_scripts/common/view_type.h
  6456. new file mode 100755
  6457. --- /dev/null
  6458. +++ b/components/user_scripts/common/view_type.h
  6459. @@ -0,0 +1,48 @@
  6460. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  6461. +// Use of this source code is governed by a BSD-style license that can be
  6462. +// found in the LICENSE file.
  6463. +
  6464. +#ifndef USERSCRIPTS_COMMON_VIEW_TYPE_H_
  6465. +#define USERSCRIPTS_COMMON_VIEW_TYPE_H_
  6466. +
  6467. +#include <string>
  6468. +
  6469. +namespace user_scripts {
  6470. +
  6471. +// Icky RTTI used by a few systems to distinguish the host type of a given
  6472. +// WebContents.
  6473. +//
  6474. +// Do not change or reuse the the entry values in this list as this is used in
  6475. +// ExtensionViewType enum in tools/metrics/histograms/enums.xml.
  6476. +//
  6477. +// TODO(aa): Remove this and teach those systems to keep track of their own
  6478. +// data.
  6479. +enum ViewType {
  6480. + VIEW_TYPE_INVALID = 0,
  6481. + // VIEW_TYPE_APP_WINDOW = 1,
  6482. + // VIEW_TYPE_BACKGROUND_CONTENTS = 2,
  6483. +
  6484. + // // For custom parts of Chrome if no other type applies.
  6485. + // VIEW_TYPE_COMPONENT = 3,
  6486. +
  6487. + // VIEW_TYPE_EXTENSION_BACKGROUND_PAGE = 4,
  6488. + // VIEW_TYPE_EXTENSION_DIALOG = 5,
  6489. + // VIEW_TYPE_EXTENSION_GUEST = 6,
  6490. + // VIEW_TYPE_EXTENSION_POPUP = 7,
  6491. +
  6492. + // Panels were removed in https://crbug.com/571511.
  6493. + // DEPRECATED_VIEW_TYPE_PANEL = 8,
  6494. +
  6495. + VIEW_TYPE_TAB_CONTENTS = 9,
  6496. +
  6497. + VIEW_TYPE_LAST = VIEW_TYPE_TAB_CONTENTS
  6498. +};
  6499. +
  6500. +// Matches the |view_type| to the corresponding ViewType, and populates
  6501. +// |view_type_out|. Returns true if a match is found.
  6502. +bool GetViewTypeFromString(const std::string& view_type,
  6503. + ViewType* view_type_out);
  6504. +
  6505. +} // namespace extensions
  6506. +
  6507. +#endif // USERSCRIPTS_COMMON_VIEW_TYPE_H_
  6508. diff --git a/components/user_scripts/renderer/BUILD.gn b/components/user_scripts/renderer/BUILD.gn
  6509. new file mode 100755
  6510. --- /dev/null
  6511. +++ b/components/user_scripts/renderer/BUILD.gn
  6512. @@ -0,0 +1,67 @@
  6513. +# Copyright 2015 The Chromium Authors. All rights reserved.
  6514. +# Use of this source code is governed by a BSD-style license that can be
  6515. +# found in the LICENSE file.
  6516. +
  6517. +import("//tools/grit/grit_rule.gni")
  6518. +import("//tools/grit/repack.gni")
  6519. +
  6520. +group("user_scripts_resources") {
  6521. + public_deps = [
  6522. + ":user_scripts_renderer_resources",
  6523. + ]
  6524. +}
  6525. +
  6526. +grit("user_scripts_renderer_resources") {
  6527. + source = "resources/user_scripts_renderer_resources.grd"
  6528. + outputs = [
  6529. + "grit/user_scripts_renderer_resources.h",
  6530. + "user_scripts_renderer_resources.pak",
  6531. + ]
  6532. + grit_flags = [
  6533. + "-E",
  6534. + "mojom_root=" + rebase_path(root_gen_dir, root_build_dir),
  6535. + ]
  6536. +}
  6537. +
  6538. +static_library("renderer") {
  6539. + sources = [
  6540. + "extension_frame_helper.cc",
  6541. + "extension_frame_helper.h",
  6542. + "injection_host.cc",
  6543. + "injection_host.h",
  6544. + "script_injection_manager.cc",
  6545. + "script_injection_manager.h",
  6546. + "script_injection_callback.cc",
  6547. + "script_injection_callback.h",
  6548. + "script_injection.cc",
  6549. + "script_injection.h",
  6550. + "script_injector.h",
  6551. + "script_context.cc",
  6552. + "script_context.h",
  6553. + "scripts_run_info.cc",
  6554. + "scripts_run_info.h",
  6555. + "user_script_injector.cc",
  6556. + "user_script_injector.h",
  6557. + "user_script_set_manager.cc",
  6558. + "user_script_set_manager.h",
  6559. + "user_script_set.cc",
  6560. + "user_script_set.h",
  6561. + "user_scripts_dispatcher.cc",
  6562. + "user_scripts_dispatcher.h",
  6563. + "user_scripts_renderer_client.cc",
  6564. + "user_scripts_renderer_client.h",
  6565. + "web_ui_injection_host.cc",
  6566. + "web_ui_injection_host.h",
  6567. + ]
  6568. +
  6569. + deps = [
  6570. + ":user_scripts_resources",
  6571. + "//base",
  6572. + "//content/public/common",
  6573. + "//content/public/renderer",
  6574. + "//components/user_scripts/common",
  6575. + "//mojo/public/cpp/bindings",
  6576. + "//third_party/blink/public:blink_headers",
  6577. + "//v8",
  6578. + ]
  6579. +}
  6580. diff --git a/components/user_scripts/renderer/extension_frame_helper.cc b/components/user_scripts/renderer/extension_frame_helper.cc
  6581. new file mode 100755
  6582. --- /dev/null
  6583. +++ b/components/user_scripts/renderer/extension_frame_helper.cc
  6584. @@ -0,0 +1,96 @@
  6585. +// Copyright 2013 The Chromium Authors. All rights reserved.
  6586. +// Use of this source code is governed by a BSD-style license that can be
  6587. +// found in the LICENSE file.
  6588. +
  6589. +#include "extension_frame_helper.h"
  6590. +
  6591. +#include <set>
  6592. +
  6593. +#include "base/metrics/histogram_macros.h"
  6594. +#include "base/strings/string_util.h"
  6595. +#include "base/timer/elapsed_timer.h"
  6596. +#include "content/public/renderer/render_frame.h"
  6597. +#include "content/public/renderer/render_view.h"
  6598. +#include "../common/constants.h"
  6599. +#include "third_party/blink/public/platform/web_security_origin.h"
  6600. +#include "third_party/blink/public/web/web_console_message.h"
  6601. +#include "third_party/blink/public/web/web_document.h"
  6602. +#include "third_party/blink/public/web/web_document_loader.h"
  6603. +#include "third_party/blink/public/web/web_local_frame.h"
  6604. +#include "third_party/blink/public/web/web_settings.h"
  6605. +#include "third_party/blink/public/web/web_view.h"
  6606. +
  6607. +namespace user_scripts {
  6608. +
  6609. +namespace {
  6610. +
  6611. +base::LazyInstance<std::set<const ExtensionFrameHelper*>>::DestructorAtExit
  6612. + g_frame_helpers = LAZY_INSTANCE_INITIALIZER;
  6613. +
  6614. +// Runs every callback in |callbacks_to_be_run_and_cleared| while |frame_helper|
  6615. +// is valid, and clears |callbacks_to_be_run_and_cleared|.
  6616. +void RunCallbacksWhileFrameIsValid(
  6617. + base::WeakPtr<ExtensionFrameHelper> frame_helper,
  6618. + std::vector<base::Closure>* callbacks_to_be_run_and_cleared) {
  6619. + // The JavaScript code can cause re-entrancy. To avoid a deadlock, don't run
  6620. + // callbacks that are added during the iteration.
  6621. + std::vector<base::Closure> callbacks;
  6622. + callbacks_to_be_run_and_cleared->swap(callbacks);
  6623. + for (auto& callback : callbacks) {
  6624. + callback.Run();
  6625. + if (!frame_helper.get())
  6626. + return; // Frame and ExtensionFrameHelper invalidated by callback.
  6627. + }
  6628. +}
  6629. +
  6630. +} // namespace
  6631. +
  6632. +ExtensionFrameHelper::ExtensionFrameHelper(content::RenderFrame* render_frame)
  6633. + : content::RenderFrameObserver(render_frame),
  6634. + content::RenderFrameObserverTracker<ExtensionFrameHelper>(render_frame),
  6635. + tab_id_(-1) {
  6636. + g_frame_helpers.Get().insert(this);
  6637. +}
  6638. +
  6639. +ExtensionFrameHelper::~ExtensionFrameHelper() {
  6640. + g_frame_helpers.Get().erase(this);
  6641. +}
  6642. +
  6643. +void ExtensionFrameHelper::ScheduleAtDocumentStart(
  6644. + const base::Closure& callback) {
  6645. + document_element_created_callbacks_.push_back(callback);
  6646. +}
  6647. +
  6648. +void ExtensionFrameHelper::ScheduleAtDocumentEnd(
  6649. + const base::Closure& callback) {
  6650. + document_load_finished_callbacks_.push_back(callback);
  6651. +}
  6652. +
  6653. +void ExtensionFrameHelper::ScheduleAtDocumentIdle(
  6654. + const base::Closure& callback) {
  6655. + document_idle_callbacks_.push_back(callback);
  6656. +}
  6657. +
  6658. +void ExtensionFrameHelper::RunScriptsAtDocumentStart() {
  6659. + RunCallbacksWhileFrameIsValid(weak_ptr_factory_.GetWeakPtr(),
  6660. + &document_element_created_callbacks_);
  6661. + // |this| might be dead by now.
  6662. +}
  6663. +
  6664. +void ExtensionFrameHelper::RunScriptsAtDocumentEnd() {
  6665. + RunCallbacksWhileFrameIsValid(weak_ptr_factory_.GetWeakPtr(),
  6666. + &document_load_finished_callbacks_);
  6667. + // |this| might be dead by now.
  6668. +}
  6669. +
  6670. +void ExtensionFrameHelper::RunScriptsAtDocumentIdle() {
  6671. + RunCallbacksWhileFrameIsValid(weak_ptr_factory_.GetWeakPtr(),
  6672. + &document_idle_callbacks_);
  6673. + // |this| might be dead by now.
  6674. +}
  6675. +
  6676. +void ExtensionFrameHelper::OnDestruct() {
  6677. + delete this;
  6678. +}
  6679. +
  6680. +} // namespace user_scripts
  6681. diff --git a/components/user_scripts/renderer/extension_frame_helper.h b/components/user_scripts/renderer/extension_frame_helper.h
  6682. new file mode 100755
  6683. --- /dev/null
  6684. +++ b/components/user_scripts/renderer/extension_frame_helper.h
  6685. @@ -0,0 +1,92 @@
  6686. +// Copyright 2013 The Chromium Authors. All rights reserved.
  6687. +// Use of this source code is governed by a BSD-style license that can be
  6688. +// found in the LICENSE file.
  6689. +
  6690. +#ifndef EXTENSIONS_RENDERER_EXTENSION_FRAME_HELPER_H_
  6691. +#define EXTENSIONS_RENDERER_EXTENSION_FRAME_HELPER_H_
  6692. +
  6693. +#include <string>
  6694. +#include <vector>
  6695. +
  6696. +#include "base/callback_forward.h"
  6697. +#include "base/macros.h"
  6698. +#include "base/memory/weak_ptr.h"
  6699. +#include "content/public/renderer/render_frame_observer.h"
  6700. +#include "content/public/renderer/render_frame_observer_tracker.h"
  6701. +#include "../common/view_type.h"
  6702. +#include "third_party/blink/public/mojom/devtools/console_message.mojom.h"
  6703. +#include "v8/include/v8.h"
  6704. +
  6705. +struct ExtensionMsg_ExternalConnectionInfo;
  6706. +struct ExtensionMsg_TabConnectionInfo;
  6707. +
  6708. +namespace base {
  6709. +class ListValue;
  6710. +}
  6711. +
  6712. +namespace user_scripts {
  6713. +
  6714. +class Dispatcher;
  6715. +struct Message;
  6716. +struct PortId;
  6717. +class ScriptContext;
  6718. +
  6719. +// RenderFrame-level plumbing for extension features.
  6720. +class ExtensionFrameHelper
  6721. + : public content::RenderFrameObserver,
  6722. + public content::RenderFrameObserverTracker<ExtensionFrameHelper> {
  6723. + public:
  6724. + ExtensionFrameHelper(content::RenderFrame* render_frame /*,
  6725. + Dispatcher* extension_dispatcher*/);
  6726. + ~ExtensionFrameHelper() override;
  6727. +
  6728. + int tab_id() const { return tab_id_; }
  6729. +
  6730. + // Called when the document element has been inserted in this frame. This
  6731. + // method may invoke untrusted JavaScript code that invalidate the frame and
  6732. + // this ExtensionFrameHelper.
  6733. + void RunScriptsAtDocumentStart();
  6734. +
  6735. + // Called after the DOMContentLoaded event has fired.
  6736. + void RunScriptsAtDocumentEnd();
  6737. +
  6738. + // Called before the window.onload event is fired.
  6739. + void RunScriptsAtDocumentIdle();
  6740. +
  6741. + // Schedule a callback, to be run at the next RunScriptsAtDocumentStart
  6742. + // notification. Only call this when you are certain that there will be such a
  6743. + // notification, e.g. from RenderFrameObserver::DidCreateDocumentElement.
  6744. + // Otherwise the callback is never invoked, or invoked for a document that you
  6745. + // were not expecting.
  6746. + void ScheduleAtDocumentStart(const base::Closure& callback);
  6747. +
  6748. + // Schedule a callback, to be run at the next RunScriptsAtDocumentEnd call.
  6749. + void ScheduleAtDocumentEnd(const base::Closure& callback);
  6750. +
  6751. + // Schedule a callback, to be run at the next RunScriptsAtDocumentIdle call.
  6752. + void ScheduleAtDocumentIdle(const base::Closure& callback);
  6753. +
  6754. + private:
  6755. +
  6756. + void OnDestruct() override;
  6757. +
  6758. + // The id of the tab the render frame is attached to.
  6759. + int tab_id_;
  6760. +
  6761. + // Callbacks to be run at the next RunScriptsAtDocumentStart notification.
  6762. + std::vector<base::Closure> document_element_created_callbacks_;
  6763. +
  6764. + // Callbacks to be run at the next RunScriptsAtDocumentEnd notification.
  6765. + std::vector<base::Closure> document_load_finished_callbacks_;
  6766. +
  6767. + // Callbacks to be run at the next RunScriptsAtDocumentIdle notification.
  6768. + std::vector<base::Closure> document_idle_callbacks_;
  6769. +
  6770. + base::WeakPtrFactory<ExtensionFrameHelper> weak_ptr_factory_{this};
  6771. +
  6772. + DISALLOW_COPY_AND_ASSIGN(ExtensionFrameHelper);
  6773. +};
  6774. +
  6775. +} // namespace extensions
  6776. +
  6777. +#endif // EXTENSIONS_RENDERER_EXTENSION_FRAME_HELPER_H_
  6778. diff --git a/components/user_scripts/renderer/injection_host.cc b/components/user_scripts/renderer/injection_host.cc
  6779. new file mode 100755
  6780. --- /dev/null
  6781. +++ b/components/user_scripts/renderer/injection_host.cc
  6782. @@ -0,0 +1,12 @@
  6783. +// Copyright 2015 The Chromium Authors. All rights reserved.
  6784. +// Use of this source code is governed by a BSD-style license that can be
  6785. +// found in the LICENSE file.
  6786. +
  6787. +#include "injection_host.h"
  6788. +
  6789. +InjectionHost::InjectionHost(const HostID& host_id) :
  6790. + id_(host_id) {
  6791. +}
  6792. +
  6793. +InjectionHost::~InjectionHost() {
  6794. +}
  6795. diff --git a/components/user_scripts/renderer/injection_host.h b/components/user_scripts/renderer/injection_host.h
  6796. new file mode 100755
  6797. --- /dev/null
  6798. +++ b/components/user_scripts/renderer/injection_host.h
  6799. @@ -0,0 +1,42 @@
  6800. +// Copyright 2015 The Chromium Authors. All rights reserved.
  6801. +// Use of this source code is governed by a BSD-style license that can be
  6802. +// found in the LICENSE file.
  6803. +
  6804. +#ifndef EXTENSIONS_RENDERER_INJECTION_HOST_H_
  6805. +#define EXTENSIONS_RENDERER_INJECTION_HOST_H_
  6806. +
  6807. +#include "base/macros.h"
  6808. +#include "../common/host_id.h"
  6809. +#include "url/gurl.h"
  6810. +
  6811. +namespace content {
  6812. +class RenderFrame;
  6813. +}
  6814. +
  6815. +// An interface for all kinds of hosts who own user scripts.
  6816. +class InjectionHost {
  6817. + public:
  6818. + InjectionHost(const HostID& host_id);
  6819. + virtual ~InjectionHost();
  6820. +
  6821. + // Returns the CSP to be used for the isolated world. Currently this only
  6822. + // bypasses the main world CSP. If null is returned, the main world CSP is not
  6823. + // bypassed.
  6824. + virtual const std::string* GetContentSecurityPolicy() const = 0;
  6825. +
  6826. + // The base url for the host.
  6827. + virtual const GURL& url() const = 0;
  6828. +
  6829. + // The human-readable name of the host.
  6830. + virtual const std::string& name() const = 0;
  6831. +
  6832. + const HostID& id() const { return id_; }
  6833. +
  6834. + private:
  6835. + // The ID of the host.
  6836. + HostID id_;
  6837. +
  6838. + DISALLOW_COPY_AND_ASSIGN(InjectionHost);
  6839. +};
  6840. +
  6841. +#endif // EXTENSIONS_RENDERER_INJECTION_HOST_H_
  6842. diff --git a/components/user_scripts/renderer/resources/greasemonkey_api.js b/components/user_scripts/renderer/resources/greasemonkey_api.js
  6843. new file mode 100755
  6844. --- /dev/null
  6845. +++ b/components/user_scripts/renderer/resources/greasemonkey_api.js
  6846. @@ -0,0 +1,82 @@
  6847. +// Copyright 2014 The Chromium Authors. All rights reserved.
  6848. +// Use of this source code is governed by a BSD-style license that can be
  6849. +// found in the LICENSE file.
  6850. +
  6851. +// -----------------------------------------------------------------------------
  6852. +// NOTE: If you change this file you need to touch renderer_resources.grd to
  6853. +// have your change take effect.
  6854. +// -----------------------------------------------------------------------------
  6855. +
  6856. +// Partial implementation of the Greasemonkey API, see:
  6857. +// http://wiki.greasespot.net/Greasemonkey_Manual:APIs
  6858. +
  6859. +function GM_addStyle(css) {
  6860. + var parent = document.getElementsByTagName("head")[0];
  6861. + if (!parent) {
  6862. + parent = document.documentElement;
  6863. + }
  6864. + var style = document.createElement("style");
  6865. + style.type = "text/css";
  6866. + var textNode = document.createTextNode(css);
  6867. + style.appendChild(textNode);
  6868. + parent.appendChild(style);
  6869. +}
  6870. +
  6871. +function GM_xmlhttpRequest(details) {
  6872. + function setupEvent(xhr, url, eventName, callback) {
  6873. + xhr[eventName] = function () {
  6874. + var isComplete = xhr.readyState == 4;
  6875. + var responseState = {
  6876. + responseText: xhr.responseText,
  6877. + readyState: xhr.readyState,
  6878. + responseHeaders: isComplete ? xhr.getAllResponseHeaders() : "",
  6879. + status: isComplete ? xhr.status : 0,
  6880. + statusText: isComplete ? xhr.statusText : "",
  6881. + finalUrl: isComplete ? url : ""
  6882. + };
  6883. + callback(responseState);
  6884. + };
  6885. + }
  6886. +
  6887. + var xhr = new XMLHttpRequest();
  6888. + var eventNames = ["onload", "onerror", "onreadystatechange"];
  6889. + for (var i = 0; i < eventNames.length; i++ ) {
  6890. + var eventName = eventNames[i];
  6891. + if (eventName in details) {
  6892. + setupEvent(xhr, details.url, eventName, details[eventName]);
  6893. + }
  6894. + }
  6895. +
  6896. + xhr.open(details.method, details.url);
  6897. +
  6898. + if (details.overrideMimeType) {
  6899. + xhr.overrideMimeType(details.overrideMimeType);
  6900. + }
  6901. + if (details.headers) {
  6902. + for (var header in details.headers) {
  6903. + xhr.setRequestHeader(header, details.headers[header]);
  6904. + }
  6905. + }
  6906. + xhr.send(details.data ? details.data : null);
  6907. +}
  6908. +
  6909. +function GM_openInTab(url) {
  6910. + window.open(url, "");
  6911. +}
  6912. +
  6913. +function GM_log(message) {
  6914. + window.console.log(message);
  6915. +}
  6916. +
  6917. +(function() {
  6918. + function generateGreasemonkeyStub(name) {
  6919. + return function() {
  6920. + console.log("%s is not supported.", name);
  6921. + };
  6922. + }
  6923. +
  6924. + var apis = ["GM_getValue", "GM_setValue", "GM_registerMenuCommand"];
  6925. + for (var i = 0, api; api = apis[i]; i++) {
  6926. + window[api] = generateGreasemonkeyStub(api);
  6927. + }
  6928. +})();
  6929. diff --git a/components/user_scripts/renderer/resources/user_scripts_renderer_resources.grd b/components/user_scripts/renderer/resources/user_scripts_renderer_resources.grd
  6930. new file mode 100755
  6931. --- /dev/null
  6932. +++ b/components/user_scripts/renderer/resources/user_scripts_renderer_resources.grd
  6933. @@ -0,0 +1,14 @@
  6934. +<?xml version="1.0" encoding="UTF-8"?>
  6935. +<grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
  6936. + <outputs>
  6937. + <output filename="grit/user_scripts_renderer_resources.h" type="rc_header">
  6938. + <emit emit_type='prepend'></emit>
  6939. + </output>
  6940. + <output filename="user_scripts_renderer_resources.pak" type="data_package" />
  6941. + </outputs>
  6942. + <release seq="1">
  6943. + <includes>
  6944. + <include name="IDR_GREASEMONKEY_API_JS" file="greasemonkey_api.js" type="BINDATA" />
  6945. + </includes>
  6946. + </release>
  6947. +</grit>
  6948. diff --git a/components/user_scripts/renderer/script_context.cc b/components/user_scripts/renderer/script_context.cc
  6949. new file mode 100755
  6950. --- /dev/null
  6951. +++ b/components/user_scripts/renderer/script_context.cc
  6952. @@ -0,0 +1,213 @@
  6953. +// Copyright 2014 The Chromium Authors. All rights reserved.
  6954. +// Use of this source code is governed by a BSD-style license that can be
  6955. +// found in the LICENSE file.
  6956. +
  6957. +#include "script_context.h"
  6958. +
  6959. +#include "base/command_line.h"
  6960. +#include "base/containers/flat_set.h"
  6961. +#include "base/logging.h"
  6962. +#include "base/stl_util.h"
  6963. +#include "base/strings/string_util.h"
  6964. +#include "base/strings/stringprintf.h"
  6965. +#include "base/values.h"
  6966. +#include "content/public/common/content_switches.h"
  6967. +#include "content/public/common/url_constants.h"
  6968. +#include "content/public/renderer/render_frame.h"
  6969. +#include "../common/constants.h"
  6970. +#include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h"
  6971. +#include "third_party/blink/public/platform/web_security_origin.h"
  6972. +#include "third_party/blink/public/web/web_document.h"
  6973. +#include "third_party/blink/public/web/web_document_loader.h"
  6974. +#include "third_party/blink/public/web/web_local_frame.h"
  6975. +#include "third_party/blink/public/web/web_navigation_params.h"
  6976. +#include "v8/include/v8.h"
  6977. +
  6978. +namespace user_scripts {
  6979. +
  6980. +namespace {
  6981. +
  6982. +GURL GetEffectiveDocumentURL(
  6983. + blink::WebLocalFrame* frame,
  6984. + const GURL& document_url,
  6985. + MatchOriginAsFallbackBehavior match_origin_as_fallback,
  6986. + bool allow_inaccessible_parents) {
  6987. + auto should_consider_origin = [document_url, match_origin_as_fallback]() {
  6988. + switch (match_origin_as_fallback) {
  6989. + case MatchOriginAsFallbackBehavior::kNever:
  6990. + return false;
  6991. + case MatchOriginAsFallbackBehavior::kMatchForAboutSchemeAndClimbTree:
  6992. + return document_url.SchemeIs(url::kAboutScheme);
  6993. + case MatchOriginAsFallbackBehavior::kAlways:
  6994. + // TODO(devlin): Add more schemes here - blob, filesystem, etc.
  6995. + return document_url.SchemeIs(url::kAboutScheme) ||
  6996. + document_url.SchemeIs(url::kDataScheme);
  6997. + }
  6998. +
  6999. + NOTREACHED();
  7000. + };
  7001. +
  7002. + // If we don't need to consider the origin, we're done.
  7003. + if (!should_consider_origin())
  7004. + return document_url;
  7005. +
  7006. + // Get the "security origin" for the frame. For about: frames, this is the
  7007. + // origin of that of the controlling frame - e.g., an about:blank frame on
  7008. + // https://example.com will have the security origin of https://example.com.
  7009. + // Other frames, like data: frames, will have an opaque origin. For these,
  7010. + // we can get the precursor origin.
  7011. + const blink::WebSecurityOrigin web_frame_origin = frame->GetSecurityOrigin();
  7012. + const url::Origin frame_origin = web_frame_origin;
  7013. + const url::SchemeHostPort& tuple_or_precursor_tuple =
  7014. + frame_origin.GetTupleOrPrecursorTupleIfOpaque();
  7015. +
  7016. + // When there's no valid tuple (which can happen in the case of e.g. a
  7017. + // browser-initiated navigation to an opaque URL), there's no origin to
  7018. + // fallback to. Bail.
  7019. + if (!tuple_or_precursor_tuple.IsValid())
  7020. + return document_url;
  7021. +
  7022. + const url::Origin origin_or_precursor_origin =
  7023. + url::Origin::Create(tuple_or_precursor_tuple.GetURL());
  7024. +
  7025. + if (!allow_inaccessible_parents &&
  7026. + !web_frame_origin.CanAccess(
  7027. + blink::WebSecurityOrigin(origin_or_precursor_origin))) {
  7028. + // The frame can't access its precursor. Bail.
  7029. + return document_url;
  7030. + }
  7031. +
  7032. + // Looks like the initiator origin is an appropriate fallback!
  7033. +
  7034. + if (match_origin_as_fallback == MatchOriginAsFallbackBehavior::kAlways) {
  7035. + // The easy case! We use the origin directly. We're done.
  7036. + return origin_or_precursor_origin.GetURL();
  7037. + }
  7038. +
  7039. + DCHECK_EQ(MatchOriginAsFallbackBehavior::kMatchForAboutSchemeAndClimbTree,
  7040. + match_origin_as_fallback);
  7041. +
  7042. + // Unfortunately, in this case, we have to climb the frame tree. This is for
  7043. + // match patterns that are associated with paths as well, not just origins.
  7044. + // For instance, if an extension wants to run on google.com/maps/* with
  7045. + // match_about_blank true, then it should run on about:-scheme frames created
  7046. + // by google.com/maps, but not about:-scheme frames created by google.com
  7047. + // (which is what the precursor tuple origin would be).
  7048. +
  7049. + // Traverse the frame/window hierarchy to find the closest non-about:-page
  7050. + // with the same origin as the precursor and return its URL.
  7051. + // Note: This can return the incorrect result, e.g. if a parent frame
  7052. + // navigates a grandchild frame.
  7053. + blink::WebFrame* parent = frame;
  7054. + GURL parent_url;
  7055. + blink::WebDocument parent_document;
  7056. + base::flat_set<blink::WebFrame*> already_visited_frames;
  7057. + do {
  7058. + already_visited_frames.insert(parent);
  7059. + if (parent->Parent())
  7060. + parent = parent->Parent();
  7061. + else
  7062. + parent = parent->Opener();
  7063. +
  7064. + // Avoid an infinite loop - see https://crbug.com/568432 and
  7065. + // https://crbug.com/883526.
  7066. + if (base::Contains(already_visited_frames, parent))
  7067. + return document_url;
  7068. +
  7069. + parent_document = parent && parent->IsWebLocalFrame()
  7070. + ? parent->ToWebLocalFrame()->GetDocument()
  7071. + : blink::WebDocument();
  7072. +
  7073. + // We reached the end of the ancestral chain without finding a valid parent,
  7074. + // or found a remote web frame (in which case, it's a different origin).
  7075. + // Bail and use the original URL.
  7076. + if (parent_document.IsNull())
  7077. + return document_url;
  7078. +
  7079. + url::SchemeHostPort parent_tuple_or_precursor_tuple =
  7080. + url::Origin(parent->GetSecurityOrigin())
  7081. + .GetTupleOrPrecursorTupleIfOpaque();
  7082. + if (!parent_tuple_or_precursor_tuple.IsValid() ||
  7083. + parent_tuple_or_precursor_tuple != tuple_or_precursor_tuple) {
  7084. + // The parent has a different tuple origin than frame; this could happen
  7085. + // in edge cases where a parent navigates an iframe or popup of a child
  7086. + // frame at a different origin. [1] In this case, bail, since we can't
  7087. + // find a full URL (i.e., one including the path) with the same security
  7088. + // origin to use for the frame in question.
  7089. + // [1] Consider a frame tree like:
  7090. + // <html> <!--example.com-->
  7091. + // <iframe id="a" src="a.com">
  7092. + // <iframe id="b" src="b.com"></iframe>
  7093. + // </iframe>
  7094. + // </html>
  7095. + // Frame "a" is cross-origin from the top-level frame, and so the
  7096. + // example.com top-level frame can't directly access frame "b". However,
  7097. + // it can navigate it through
  7098. + // window.frames[0].frames[0].location.href = 'about:blank';
  7099. + // In that case, the precursor origin tuple origin of frame "b" would be
  7100. + // example.com, but the parent tuple origin is a.com.
  7101. + // Note that usually, this would have bailed earlier with a remote frame,
  7102. + // but it may not if we're at the process limit.
  7103. + return document_url;
  7104. + }
  7105. +
  7106. + parent_url = GURL(parent_document.Url());
  7107. + } while (parent_url.SchemeIs(url::kAboutScheme));
  7108. +
  7109. + DCHECK(!parent_url.is_empty());
  7110. + DCHECK(!parent_document.IsNull());
  7111. +
  7112. + // We should know that the frame can access the parent document (unless we
  7113. + // explicitly allow it not to), since it has the same tuple origin as the
  7114. + // frame, and we checked the frame access above.
  7115. + DCHECK(allow_inaccessible_parents ||
  7116. + web_frame_origin.CanAccess(parent_document.GetSecurityOrigin()));
  7117. + return parent_url;
  7118. +}
  7119. +
  7120. +using FrameToDocumentLoader =
  7121. + base::flat_map<blink::WebLocalFrame*, blink::WebDocumentLoader*>;
  7122. +
  7123. +FrameToDocumentLoader& FrameDocumentLoaderMap() {
  7124. + static base::NoDestructor<FrameToDocumentLoader> map;
  7125. + return *map;
  7126. +}
  7127. +
  7128. +blink::WebDocumentLoader* CurrentDocumentLoader(
  7129. + const blink::WebLocalFrame* frame) {
  7130. + auto& map = FrameDocumentLoaderMap();
  7131. + auto it = map.find(frame);
  7132. + return it == map.end() ? frame->GetDocumentLoader() : it->second;
  7133. +}
  7134. +
  7135. +} // namespace
  7136. +
  7137. +// static
  7138. +GURL ScriptContext::GetDocumentLoaderURLForFrame(
  7139. + const blink::WebLocalFrame* frame) {
  7140. + // Normally we would use frame->document().url() to determine the document's
  7141. + // URL, but to decide whether to inject a content script, we use the URL from
  7142. + // the data source. This "quirk" helps prevents content scripts from
  7143. + // inadvertently adding DOM elements to the compose iframe in Gmail because
  7144. + // the compose iframe's dataSource URL is about:blank, but the document URL
  7145. + // changes to match the parent document after Gmail document.writes into
  7146. + // it to create the editor.
  7147. + // http://code.google.com/p/chromium/issues/detail?id=86742
  7148. + blink::WebDocumentLoader* document_loader = CurrentDocumentLoader(frame);
  7149. + return document_loader ? GURL(document_loader->GetUrl()) : GURL();
  7150. +}
  7151. +
  7152. +// static
  7153. +GURL ScriptContext::GetEffectiveDocumentURLForInjection(
  7154. + blink::WebLocalFrame* frame,
  7155. + const GURL& document_url,
  7156. + MatchOriginAsFallbackBehavior match_origin_as_fallback) {
  7157. + // We explicitly allow inaccessible parents here. Extensions should still be
  7158. + // able to inject into a sandboxed iframe if it has access to the embedding
  7159. + // origin.
  7160. + constexpr bool allow_inaccessible_parents = true;
  7161. + return GetEffectiveDocumentURL(frame, document_url, match_origin_as_fallback,
  7162. + allow_inaccessible_parents);
  7163. +}
  7164. +
  7165. +} // namespace extensions
  7166. diff --git a/components/user_scripts/renderer/script_context.h b/components/user_scripts/renderer/script_context.h
  7167. new file mode 100755
  7168. --- /dev/null
  7169. +++ b/components/user_scripts/renderer/script_context.h
  7170. @@ -0,0 +1,70 @@
  7171. +// Copyright 2014 The Chromium Authors. All rights reserved.
  7172. +// Use of this source code is governed by a BSD-style license that can be
  7173. +// found in the LICENSE file.
  7174. +
  7175. +#ifndef EXTENSIONS_RENDERER_SCRIPT_CONTEXT_H_
  7176. +#define EXTENSIONS_RENDERER_SCRIPT_CONTEXT_H_
  7177. +
  7178. +#include <memory>
  7179. +#include <string>
  7180. +#include <utility>
  7181. +#include <vector>
  7182. +
  7183. +#include "base/callback.h"
  7184. +#include "base/compiler_specific.h"
  7185. +#include "base/macros.h"
  7186. +#include "base/threading/thread_checker.h"
  7187. +#include "base/unguessable_token.h"
  7188. +#include "../common/script_constants.h"
  7189. +#include "script_injection_callback.h"
  7190. +#include "url/gurl.h"
  7191. +#include "v8/include/v8.h"
  7192. +
  7193. +namespace blink {
  7194. +class WebDocumentLoader;
  7195. +class WebLocalFrame;
  7196. +}
  7197. +
  7198. +namespace content {
  7199. +class RenderFrame;
  7200. +}
  7201. +
  7202. +namespace user_scripts {
  7203. +
  7204. +// Extensions wrapper for a v8::Context.
  7205. +//
  7206. +// v8::Contexts can be constructed on any thread, and must only be accessed or
  7207. +// destroyed that thread.
  7208. +//
  7209. +// Note that ScriptContexts bound to worker threads will not have the full
  7210. +// functionality as those bound to the main RenderThread.
  7211. +class ScriptContext {
  7212. + public:
  7213. + // TODO(devlin): Move all these Get*URL*() methods out of here? While they are
  7214. + // vaguely ScriptContext related, there's enough here that they probably
  7215. + // warrant another class or utility file.
  7216. +
  7217. + // Utility to get the URL we will match against for a frame. If the frame has
  7218. + // committed, this is the commited URL. Otherwise it is the provisional URL.
  7219. + // The returned URL may be invalid.
  7220. + static GURL GetDocumentLoaderURLForFrame(const blink::WebLocalFrame* frame);
  7221. +
  7222. + // Used to determine the "effective" URL for extension script injection.
  7223. + // If |document_url| is an about: or data: URL, returns the URL of the first
  7224. + // frame without an about: or data: URL that matches the initiator origin.
  7225. + // This may not be the immediate parent. Returns |document_url| if it is not
  7226. + // an about: or data: URL, if |match_origin_as_fallback| is set to not match,
  7227. + // or if a suitable parent cannot be found.
  7228. + // Considers parent contexts that cannot be accessed (as is the case for
  7229. + // sandboxed frames).
  7230. + static GURL GetEffectiveDocumentURLForInjection(
  7231. + blink::WebLocalFrame* frame,
  7232. + const GURL& document_url,
  7233. + MatchOriginAsFallbackBehavior match_origin_as_fallback);
  7234. +
  7235. +// DISALLOW_COPY_AND_ASSIGN(ScriptContext);
  7236. +};
  7237. +
  7238. +} // namespace extensions
  7239. +
  7240. +#endif // EXTENSIONS_RENDERER_SCRIPT_CONTEXT_H_
  7241. diff --git a/components/user_scripts/renderer/script_injection.cc b/components/user_scripts/renderer/script_injection.cc
  7242. new file mode 100755
  7243. --- /dev/null
  7244. +++ b/components/user_scripts/renderer/script_injection.cc
  7245. @@ -0,0 +1,350 @@
  7246. +// Copyright 2014 The Chromium Authors. All rights reserved.
  7247. +// Use of this source code is governed by a BSD-style license that can be
  7248. +// found in the LICENSE file.
  7249. +
  7250. +#include "script_injection.h"
  7251. +
  7252. +#include <map>
  7253. +#include <utility>
  7254. +
  7255. +#include "base/bind.h"
  7256. +#include "base/feature_list.h"
  7257. +#include "base/lazy_instance.h"
  7258. +#include "base/macros.h"
  7259. +#include "base/metrics/histogram_macros.h"
  7260. +#include "base/timer/elapsed_timer.h"
  7261. +#include "base/values.h"
  7262. +#include "base/logging.h"
  7263. +#include "content/public/renderer/render_frame.h"
  7264. +#include "content/public/renderer/render_frame_observer.h"
  7265. +#include "content/public/renderer/v8_value_converter.h"
  7266. +#include "../common/host_id.h"
  7267. +#include "script_injection_callback.h"
  7268. +#include "scripts_run_info.h"
  7269. +#include "third_party/blink/public/platform/web_isolated_world_info.h"
  7270. +#include "third_party/blink/public/platform/web_security_origin.h"
  7271. +#include "third_party/blink/public/platform/web_string.h"
  7272. +#include "third_party/blink/public/web/web_document.h"
  7273. +#include "third_party/blink/public/web/web_local_frame.h"
  7274. +#include "third_party/blink/public/web/web_script_source.h"
  7275. +#include "url/gurl.h"
  7276. +
  7277. +namespace user_scripts {
  7278. +
  7279. +namespace {
  7280. +
  7281. +using IsolatedWorldMap = std::map<std::string, int>;
  7282. +base::LazyInstance<IsolatedWorldMap>::DestructorAtExit g_isolated_worlds =
  7283. + LAZY_INSTANCE_INITIALIZER;
  7284. +
  7285. +const int64_t kInvalidRequestId = -1;
  7286. +
  7287. +// Gets the isolated world ID to use for the given |injection_host|. If no
  7288. +// isolated world has been created for that |injection_host| one will be created
  7289. +// and initialized.
  7290. +int GetIsolatedWorldIdForInstance(const InjectionHost* injection_host) {
  7291. + static int g_next_isolated_world_id = 1; // Embedder isolated worlds can use IDs in [1, 1<<29).
  7292. +
  7293. + IsolatedWorldMap& isolated_worlds = g_isolated_worlds.Get();
  7294. +
  7295. + int id = 0;
  7296. + const std::string& key = injection_host->id().id();
  7297. + auto iter = isolated_worlds.find(key);
  7298. + if (iter != isolated_worlds.end()) {
  7299. + id = iter->second;
  7300. + } else {
  7301. + id = g_next_isolated_world_id++;
  7302. + // This map will tend to pile up over time, but realistically, you're never
  7303. + // going to have enough injection hosts for it to matter.
  7304. + isolated_worlds[key] = id;
  7305. + }
  7306. +
  7307. + blink::WebIsolatedWorldInfo info;
  7308. + info.security_origin =
  7309. + blink::WebSecurityOrigin::Create(injection_host->url());
  7310. + info.human_readable_name = blink::WebString::FromUTF8(injection_host->name());
  7311. + info.stable_id = blink::WebString::FromUTF8(key);
  7312. +
  7313. + const std::string* csp = injection_host->GetContentSecurityPolicy();
  7314. + if (csp)
  7315. + info.content_security_policy = blink::WebString::FromUTF8(*csp);
  7316. +
  7317. + // Even though there may be an existing world for this |injection_host|'s key,
  7318. + // the properties may have changed (e.g. due to an extension update).
  7319. + // Overwrite any existing entries.
  7320. + blink::SetIsolatedWorldInfo(id, info);
  7321. +
  7322. + return id;
  7323. +}
  7324. +
  7325. +// This class manages its own lifetime.
  7326. +class TimedScriptInjectionCallback : public ScriptInjectionCallback {
  7327. + public:
  7328. + TimedScriptInjectionCallback(base::WeakPtr<ScriptInjection> injection)
  7329. + : ScriptInjectionCallback(
  7330. + base::Bind(&TimedScriptInjectionCallback::OnCompleted,
  7331. + base::Unretained(this))),
  7332. + injection_(injection) {}
  7333. + ~TimedScriptInjectionCallback() override {}
  7334. +
  7335. + void OnCompleted(const std::vector<v8::Local<v8::Value>>& result) {
  7336. + if (injection_) {
  7337. + base::TimeTicks timestamp(base::TimeTicks::Now());
  7338. + base::Optional<base::TimeDelta> elapsed;
  7339. + // If the script will never execute (such as if the context is destroyed),
  7340. + // willExecute() will not be called, but OnCompleted() will. Only log a
  7341. + // time for execution if the script, in fact, executed.
  7342. + if (!start_time_.is_null())
  7343. + elapsed = timestamp - start_time_;
  7344. + injection_->OnJsInjectionCompleted(result, elapsed);
  7345. + }
  7346. + }
  7347. +
  7348. + void WillExecute() override {
  7349. + start_time_ = base::TimeTicks::Now();
  7350. + }
  7351. +
  7352. + private:
  7353. + base::WeakPtr<ScriptInjection> injection_;
  7354. + base::TimeTicks start_time_;
  7355. +};
  7356. +
  7357. +} // namespace
  7358. +
  7359. +// Watches for the deletion of a RenderFrame, after which is_valid will return
  7360. +// false.
  7361. +class ScriptInjection::FrameWatcher : public content::RenderFrameObserver {
  7362. + public:
  7363. + FrameWatcher(content::RenderFrame* render_frame,
  7364. + ScriptInjection* injection)
  7365. + : content::RenderFrameObserver(render_frame),
  7366. + injection_(injection) {}
  7367. + ~FrameWatcher() override {}
  7368. +
  7369. + private:
  7370. + void WillDetach() override { injection_->invalidate_render_frame(); }
  7371. + void OnDestruct() override { injection_->invalidate_render_frame(); }
  7372. +
  7373. + ScriptInjection* injection_;
  7374. +
  7375. + DISALLOW_COPY_AND_ASSIGN(FrameWatcher);
  7376. +};
  7377. +
  7378. +// static
  7379. +std::string ScriptInjection::GetHostIdForIsolatedWorld(int isolated_world_id) {
  7380. + const IsolatedWorldMap& isolated_worlds = g_isolated_worlds.Get();
  7381. +
  7382. + for (const auto& iter : isolated_worlds) {
  7383. + if (iter.second == isolated_world_id)
  7384. + return iter.first;
  7385. + }
  7386. + return std::string();
  7387. +}
  7388. +
  7389. +// static
  7390. +void ScriptInjection::RemoveIsolatedWorld(const std::string& host_id) {
  7391. + g_isolated_worlds.Get().erase(host_id);
  7392. +}
  7393. +
  7394. +ScriptInjection::ScriptInjection(
  7395. + std::unique_ptr<ScriptInjector> injector,
  7396. + content::RenderFrame* render_frame,
  7397. + std::unique_ptr<const InjectionHost> injection_host,
  7398. + UserScript::RunLocation run_location,
  7399. + bool log_activity)
  7400. + : injector_(std::move(injector)),
  7401. + render_frame_(render_frame),
  7402. + injection_host_(std::move(injection_host)),
  7403. + run_location_(run_location),
  7404. + request_id_(kInvalidRequestId),
  7405. + ukm_source_id_(base::UkmSourceId::FromInt64(
  7406. + render_frame_->GetWebFrame()->GetDocument().GetUkmSourceId())),
  7407. + complete_(false),
  7408. + did_inject_js_(false),
  7409. + log_activity_(log_activity),
  7410. + frame_watcher_(new FrameWatcher(render_frame, this)) {
  7411. + CHECK(injection_host_.get());
  7412. +}
  7413. +
  7414. +ScriptInjection::~ScriptInjection() {
  7415. + if (!complete_)
  7416. + NotifyWillNotInject(ScriptInjector::WONT_INJECT);
  7417. +}
  7418. +
  7419. +ScriptInjection::InjectionResult ScriptInjection::TryToInject(
  7420. + UserScript::RunLocation current_location,
  7421. + ScriptsRunInfo* scripts_run_info,
  7422. + const CompletionCallback& async_completion_callback) {
  7423. + if (current_location < run_location_)
  7424. + return INJECTION_WAITING; // Wait for the right location.
  7425. +
  7426. + if (request_id_ != kInvalidRequestId) {
  7427. + // We're waiting for permission right now, try again later.
  7428. + return INJECTION_WAITING;
  7429. + }
  7430. +
  7431. + if (!injection_host_) {
  7432. + NotifyWillNotInject(ScriptInjector::EXTENSION_REMOVED);
  7433. + return INJECTION_FINISHED; // We're done.
  7434. + }
  7435. +
  7436. + InjectionResult result = Inject(scripts_run_info);
  7437. + // If the injection is blocked, we need to set the manager so we can
  7438. + // notify it upon completion.
  7439. + if (result == INJECTION_BLOCKED)
  7440. + async_completion_callback_ = async_completion_callback;
  7441. + return result;
  7442. +}
  7443. +
  7444. +ScriptInjection::InjectionResult ScriptInjection::OnPermissionGranted(
  7445. + ScriptsRunInfo* scripts_run_info) {
  7446. + if (!injection_host_) {
  7447. + NotifyWillNotInject(ScriptInjector::EXTENSION_REMOVED);
  7448. + return INJECTION_FINISHED;
  7449. + }
  7450. +
  7451. + return Inject(scripts_run_info);
  7452. +}
  7453. +
  7454. +void ScriptInjection::OnHostRemoved() {
  7455. + injection_host_.reset(nullptr);
  7456. +}
  7457. +
  7458. +void ScriptInjection::NotifyWillNotInject(
  7459. + ScriptInjector::InjectFailureReason reason) {
  7460. + complete_ = true;
  7461. + injector_->OnWillNotInject(reason, render_frame_);
  7462. +}
  7463. +
  7464. +ScriptInjection::InjectionResult ScriptInjection::Inject(
  7465. + ScriptsRunInfo* scripts_run_info) {
  7466. + DCHECK(injection_host_);
  7467. + //DCHECK(scripts_run_info);
  7468. + DCHECK(!complete_);
  7469. + bool should_inject_js = injector_->ShouldInjectJs(
  7470. + run_location_, scripts_run_info->executing_scripts[host_id().id()]);
  7471. + bool should_inject_css = injector_->ShouldInjectCss(
  7472. + run_location_, scripts_run_info->injected_stylesheets[host_id().id()]);
  7473. +
  7474. + // This can happen if the extension specified a script to
  7475. + // be run in multiple rules, and the script has already run.
  7476. + // See crbug.com/631247.
  7477. + if (!should_inject_js && !should_inject_css) {
  7478. + return INJECTION_FINISHED;
  7479. + }
  7480. +
  7481. + if (should_inject_js)
  7482. + InjectJs(&(scripts_run_info->executing_scripts[host_id().id()]),
  7483. + &(scripts_run_info->num_js));
  7484. + if (should_inject_css)
  7485. + InjectCss(&(scripts_run_info->injected_stylesheets[host_id().id()]),
  7486. + &(scripts_run_info->num_css));
  7487. +
  7488. + complete_ = did_inject_js_ || !should_inject_js;
  7489. +
  7490. + if (complete_) {
  7491. + LOG(INFO) << "---ScriptInjection::Inject complete";
  7492. + injector_->OnInjectionComplete(std::move(execution_result_), run_location_,
  7493. + render_frame_);
  7494. + } else {
  7495. + LOG(INFO) << "---ScriptInjection::Inject INcomplete";
  7496. + ++scripts_run_info->num_blocking_js;
  7497. + }
  7498. +
  7499. + return complete_ ? INJECTION_FINISHED : INJECTION_BLOCKED;
  7500. +}
  7501. +
  7502. +void ScriptInjection::InjectJs(std::set<std::string>* executing_scripts,
  7503. + size_t* num_injected_js_scripts) {
  7504. + // LOG(INFO) << "---ScriptInjection::InjectJs";
  7505. + DCHECK(!did_inject_js_);
  7506. + std::vector<blink::WebScriptSource> sources = injector_->GetJsSources(
  7507. + run_location_, executing_scripts, num_injected_js_scripts);
  7508. + DCHECK(!sources.empty());
  7509. + int world_id = GetIsolatedWorldIdForInstance(injection_host_.get());
  7510. + bool is_user_gesture = injector_->IsUserGesture();
  7511. +
  7512. + std::unique_ptr<blink::WebScriptExecutionCallback> callback(
  7513. + new TimedScriptInjectionCallback(weak_ptr_factory_.GetWeakPtr()));
  7514. +
  7515. + base::ElapsedTimer exec_timer;
  7516. +
  7517. + // For content scripts executing during page load, we run them asynchronously
  7518. + // in order to reduce UI jank experienced by the user. (We don't do this for
  7519. + // DOCUMENT_START scripts, because there's no UI to jank until after those
  7520. + // run, so we run them as soon as we can.)
  7521. + // Note: We could potentially also run deferred and browser-driven scripts
  7522. + // asynchronously; however, these are rare enough that there probably isn't
  7523. + // UI jank. If this changes, we can update this.
  7524. + bool should_execute_asynchronously =
  7525. + injector_->script_type() == UserScript::CONTENT_SCRIPT &&
  7526. + (run_location_ == UserScript::DOCUMENT_END ||
  7527. + run_location_ == UserScript::DOCUMENT_IDLE);
  7528. + blink::WebLocalFrame::ScriptExecutionType execution_option =
  7529. + should_execute_asynchronously
  7530. + ? blink::WebLocalFrame::kAsynchronousBlockingOnload
  7531. + : blink::WebLocalFrame::kSynchronous;
  7532. +
  7533. + render_frame_->GetWebFrame()->RequestExecuteScriptInIsolatedWorld(
  7534. + world_id, &sources.front(), sources.size(), is_user_gesture,
  7535. + execution_option, callback.release());
  7536. + // LOG(INFO) << "---ScriptInjection::InjectJs end " << world_id;
  7537. +}
  7538. +
  7539. +void ScriptInjection::OnJsInjectionCompleted(
  7540. + const std::vector<v8::Local<v8::Value>>& results,
  7541. + base::Optional<base::TimeDelta> elapsed) {
  7542. + // LOG(INFO) << "---ScriptInjection::OnJsInjectionCompleted end";
  7543. + DCHECK(!did_inject_js_);
  7544. +
  7545. + bool expects_results = injector_->ExpectsResults();
  7546. + if (expects_results) {
  7547. + if (!results.empty() && !results[0].IsEmpty()) {
  7548. + // Right now, we only support returning single results (per frame).
  7549. + // It's safe to always use the main world context when converting
  7550. + // here. V8ValueConverterImpl shouldn't actually care about the
  7551. + // context scope, and it switches to v8::Object's creation context
  7552. + // when encountered.
  7553. + v8::Local<v8::Context> context =
  7554. + render_frame_->GetWebFrame()->MainWorldScriptContext();
  7555. + execution_result_ =
  7556. + content::V8ValueConverter::Create()->FromV8Value(results[0], context);
  7557. + }
  7558. + if (!execution_result_.get())
  7559. + execution_result_ = std::make_unique<base::Value>();
  7560. + }
  7561. + did_inject_js_ = true;
  7562. +
  7563. + // If |async_completion_callback_| is set, it means the script finished
  7564. + // asynchronously, and we should run it.
  7565. + if (!async_completion_callback_.is_null()) {
  7566. + complete_ = true;
  7567. + injector_->OnInjectionComplete(std::move(execution_result_), run_location_,
  7568. + render_frame_);
  7569. + // Warning: this object can be destroyed after this line!
  7570. + async_completion_callback_.Run(this);
  7571. + }
  7572. + // LOG(INFO) << "---ScriptInjection::OnJsInjectionCompleted end "<< execution_result_;
  7573. +}
  7574. +
  7575. +void ScriptInjection::InjectCss(std::set<std::string>* injected_stylesheets,
  7576. + size_t* num_injected_stylesheets) {
  7577. + std::vector<blink::WebString> css_sources = injector_->GetCssSources(
  7578. + run_location_, injected_stylesheets, num_injected_stylesheets);
  7579. + blink::WebLocalFrame* web_frame = render_frame_->GetWebFrame();
  7580. + // Default CSS origin is "author", but can be overridden to "user" by scripts.
  7581. + base::Optional<CSSOrigin> css_origin = injector_->GetCssOrigin();
  7582. + blink::WebDocument::CSSOrigin blink_css_origin =
  7583. + css_origin && *css_origin == CSS_ORIGIN_USER
  7584. + ? blink::WebDocument::kUserOrigin
  7585. + : blink::WebDocument::kAuthorOrigin;
  7586. + blink::WebStyleSheetKey style_sheet_key;
  7587. + if (const base::Optional<std::string>& injection_key =
  7588. + injector_->GetInjectionKey())
  7589. + style_sheet_key = blink::WebString::FromASCII(*injection_key);
  7590. + for (const blink::WebString& css : css_sources)
  7591. + web_frame->GetDocument().InsertStyleSheet(css, &style_sheet_key,
  7592. + blink_css_origin);
  7593. +}
  7594. +
  7595. +} // namespace extensions
  7596. diff --git a/components/user_scripts/renderer/script_injection.h b/components/user_scripts/renderer/script_injection.h
  7597. new file mode 100755
  7598. --- /dev/null
  7599. +++ b/components/user_scripts/renderer/script_injection.h
  7600. @@ -0,0 +1,160 @@
  7601. +// Copyright 2014 The Chromium Authors. All rights reserved.
  7602. +// Use of this source code is governed by a BSD-style license that can be
  7603. +// found in the LICENSE file.
  7604. +
  7605. +#ifndef EXTENSIONS_RENDERER_SCRIPT_INJECTION_H_
  7606. +#define EXTENSIONS_RENDERER_SCRIPT_INJECTION_H_
  7607. +
  7608. +#include <stdint.h>
  7609. +
  7610. +#include <memory>
  7611. +#include <vector>
  7612. +
  7613. +#include "base/callback.h"
  7614. +#include "base/macros.h"
  7615. +#include "base/memory/weak_ptr.h"
  7616. +#include "base/metrics/ukm_source_id.h"
  7617. +#include "base/optional.h"
  7618. +#include "../common/user_script.h"
  7619. +#include "injection_host.h"
  7620. +#include "script_injector.h"
  7621. +
  7622. +struct HostID;
  7623. +
  7624. +namespace content {
  7625. +class RenderFrame;
  7626. +}
  7627. +
  7628. +namespace v8 {
  7629. +class Value;
  7630. +template <class T> class Local;
  7631. +}
  7632. +
  7633. +namespace user_scripts {
  7634. +struct ScriptsRunInfo;
  7635. +
  7636. +// A script wrapper which is aware of whether or not it is allowed to execute,
  7637. +// and contains the implementation to do so.
  7638. +class ScriptInjection {
  7639. + public:
  7640. + enum InjectionResult {
  7641. + INJECTION_FINISHED,
  7642. + INJECTION_BLOCKED,
  7643. + INJECTION_WAITING
  7644. + };
  7645. +
  7646. + using CompletionCallback = base::Callback<void(ScriptInjection*)>;
  7647. +
  7648. + // Return the id of the injection host associated with the given world.
  7649. + static std::string GetHostIdForIsolatedWorld(int world_id);
  7650. +
  7651. + // Remove the isolated world associated with the given injection host.
  7652. + static void RemoveIsolatedWorld(const std::string& host_id);
  7653. +
  7654. + ScriptInjection(std::unique_ptr<ScriptInjector> injector,
  7655. + content::RenderFrame* render_frame,
  7656. + std::unique_ptr<const InjectionHost> injection_host,
  7657. + UserScript::RunLocation run_location,
  7658. + bool log_activity);
  7659. + ~ScriptInjection();
  7660. +
  7661. + // Try to inject the script at the |current_location|. This returns
  7662. + // INJECTION_FINISHED if injection has injected or will never inject, returns
  7663. + // INJECTION_BLOCKED if injection is running asynchronously and has not
  7664. + // finished yet, returns INJECTION_WAITING if injections is delayed (either
  7665. + // for permission purposes or because |current_location| is not the designated
  7666. + // |run_location_|).
  7667. + // If INJECTION_BLOCKED is returned, |async_completion_callback| will be
  7668. + // called upon completion.
  7669. + InjectionResult TryToInject(
  7670. + UserScript::RunLocation current_location,
  7671. + ScriptsRunInfo* scripts_run_info,
  7672. + const CompletionCallback& async_completion_callback);
  7673. +
  7674. + // Called when permission for the given injection has been granted.
  7675. + // Returns INJECTION_FINISHED if injection has injected or will never inject,
  7676. + // returns INJECTION_BLOCKED if injection is ran asynchronously.
  7677. + InjectionResult OnPermissionGranted(ScriptsRunInfo* scripts_run_info);
  7678. +
  7679. + // Resets the pointer of the injection host when the host is gone.
  7680. + void OnHostRemoved();
  7681. +
  7682. + void invalidate_render_frame() { render_frame_ = nullptr; }
  7683. +
  7684. + // Accessors.
  7685. + content::RenderFrame* render_frame() const { return render_frame_; }
  7686. + const HostID& host_id() const { return injection_host_->id(); }
  7687. + int64_t request_id() const { return request_id_; }
  7688. +
  7689. + // Called when JS injection for the given frame has been completed or
  7690. + // cancelled.
  7691. + void OnJsInjectionCompleted(const std::vector<v8::Local<v8::Value>>& results,
  7692. + base::Optional<base::TimeDelta> elapsed);
  7693. +
  7694. + private:
  7695. + class FrameWatcher;
  7696. +
  7697. + // Sends a message to the browser to request permission to inject.
  7698. + void RequestPermissionFromBrowser();
  7699. +
  7700. + // Injects the script. Returns INJECTION_FINISHED if injection has finished,
  7701. + // otherwise INJECTION_BLOCKED.
  7702. + InjectionResult Inject(ScriptsRunInfo* scripts_run_info);
  7703. +
  7704. + // Inject any JS scripts into the frame for the injection.
  7705. + void InjectJs(std::set<std::string>* executing_scripts,
  7706. + size_t* num_injected_js_scripts);
  7707. +
  7708. + // Inject any CSS source into the frame for the injection.
  7709. + void InjectCss(std::set<std::string>* injected_stylesheets,
  7710. + size_t* num_injected_stylesheets);
  7711. +
  7712. + // Notify that we will not inject, and mark it as acknowledged.
  7713. + void NotifyWillNotInject(ScriptInjector::InjectFailureReason reason);
  7714. +
  7715. + // The injector for this injection.
  7716. + std::unique_ptr<ScriptInjector> injector_;
  7717. +
  7718. + // The RenderFrame into which this should inject the script.
  7719. + content::RenderFrame* render_frame_;
  7720. +
  7721. + // The associated injection host.
  7722. + std::unique_ptr<const InjectionHost> injection_host_;
  7723. +
  7724. + // The location in the document load at which we inject the script.
  7725. + UserScript::RunLocation run_location_;
  7726. +
  7727. + // This injection's request id. This will be -1 unless the injection is
  7728. + // currently waiting on permission.
  7729. + int64_t request_id_;
  7730. +
  7731. + // Identifies the frame we're injecting into.
  7732. + base::UkmSourceId ukm_source_id_;
  7733. +
  7734. + // Whether or not the injection is complete, either via injecting the script
  7735. + // or because it will never complete.
  7736. + bool complete_;
  7737. +
  7738. + // Whether or not the injection successfully injected JS.
  7739. + bool did_inject_js_;
  7740. +
  7741. + // Whether or not we should log dom activity for this injection.
  7742. + bool log_activity_;
  7743. +
  7744. + // Results storage.
  7745. + std::unique_ptr<base::Value> execution_result_;
  7746. +
  7747. + // The callback to run upon completing asynchronously.
  7748. + CompletionCallback async_completion_callback_;
  7749. +
  7750. + // A helper class to hold the render frame and watch for its deletion.
  7751. + std::unique_ptr<FrameWatcher> frame_watcher_;
  7752. +
  7753. + base::WeakPtrFactory<ScriptInjection> weak_ptr_factory_{this};
  7754. +
  7755. + DISALLOW_COPY_AND_ASSIGN(ScriptInjection);
  7756. +};
  7757. +
  7758. +} // namespace extensions
  7759. +
  7760. +#endif // EXTENSIONS_RENDERER_SCRIPT_INJECTION_H_
  7761. diff --git a/components/user_scripts/renderer/script_injection_callback.cc b/components/user_scripts/renderer/script_injection_callback.cc
  7762. new file mode 100755
  7763. --- /dev/null
  7764. +++ b/components/user_scripts/renderer/script_injection_callback.cc
  7765. @@ -0,0 +1,26 @@
  7766. +// Copyright 2015 The Chromium Authors. All rights reserved.
  7767. +// Use of this source code is governed by a BSD-style license that can be
  7768. +// found in the LICENSE file.
  7769. +
  7770. +#include "script_injection_callback.h"
  7771. +
  7772. +#include "third_party/blink/public/platform/web_vector.h"
  7773. +
  7774. +namespace user_scripts {
  7775. +
  7776. +ScriptInjectionCallback::ScriptInjectionCallback(
  7777. + const CompleteCallback& injection_completed_callback)
  7778. + : injection_completed_callback_(injection_completed_callback) {
  7779. +}
  7780. +
  7781. +ScriptInjectionCallback::~ScriptInjectionCallback() {
  7782. +}
  7783. +
  7784. +void ScriptInjectionCallback::Completed(
  7785. + const blink::WebVector<v8::Local<v8::Value>>& result) {
  7786. + std::vector<v8::Local<v8::Value>> stl_result(result.begin(), result.end());
  7787. + injection_completed_callback_.Run(stl_result);
  7788. + delete this;
  7789. +}
  7790. +
  7791. +} // namespace extensions
  7792. diff --git a/components/user_scripts/renderer/script_injection_callback.h b/components/user_scripts/renderer/script_injection_callback.h
  7793. new file mode 100755
  7794. --- /dev/null
  7795. +++ b/components/user_scripts/renderer/script_injection_callback.h
  7796. @@ -0,0 +1,38 @@
  7797. +// Copyright 2015 The Chromium Authors. All rights reserved.
  7798. +// Use of this source code is governed by a BSD-style license that can be
  7799. +// found in the LICENSE file.
  7800. +
  7801. +#ifndef EXTENSIONS_RENDERER_SCRIPT_INJECTION_CALLBACK_H_
  7802. +#define EXTENSIONS_RENDERER_SCRIPT_INJECTION_CALLBACK_H_
  7803. +
  7804. +#include <vector>
  7805. +
  7806. +#include "base/callback.h"
  7807. +#include "base/macros.h"
  7808. +#include "third_party/blink/public/web/web_script_execution_callback.h"
  7809. +#include "v8/include/v8.h"
  7810. +
  7811. +namespace user_scripts {
  7812. +
  7813. +// A wrapper around a callback to notify a script injection when injection
  7814. +// completes.
  7815. +// This class manages its own lifetime.
  7816. +class ScriptInjectionCallback : public blink::WebScriptExecutionCallback {
  7817. + public:
  7818. + using CompleteCallback =
  7819. + base::Callback<void(const std::vector<v8::Local<v8::Value>>& result)>;
  7820. +
  7821. + ScriptInjectionCallback(const CompleteCallback& injection_completed_callback);
  7822. + ~ScriptInjectionCallback() override;
  7823. +
  7824. + void Completed(const blink::WebVector<v8::Local<v8::Value>>& result) override;
  7825. +
  7826. + private:
  7827. + CompleteCallback injection_completed_callback_;
  7828. +
  7829. + DISALLOW_COPY_AND_ASSIGN(ScriptInjectionCallback);
  7830. +};
  7831. +
  7832. +} // namespace extensions
  7833. +
  7834. +#endif // EXTENSIONS_RENDERER_SCRIPT_INJECTION_CALLBACK_H_
  7835. diff --git a/components/user_scripts/renderer/script_injection_manager.cc b/components/user_scripts/renderer/script_injection_manager.cc
  7836. new file mode 100755
  7837. --- /dev/null
  7838. +++ b/components/user_scripts/renderer/script_injection_manager.cc
  7839. @@ -0,0 +1,407 @@
  7840. +// Copyright 2014 The Chromium Authors. All rights reserved.
  7841. +// Use of this source code is governed by a BSD-style license that can be
  7842. +// found in the LICENSE file.
  7843. +
  7844. +#include "script_injection_manager.h"
  7845. +
  7846. +#include <memory>
  7847. +#include <utility>
  7848. +
  7849. +#include "base/auto_reset.h"
  7850. +#include "base/bind.h"
  7851. +#include "base/feature_list.h"
  7852. +#include "base/memory/weak_ptr.h"
  7853. +#include "base/threading/thread_task_runner_handle.h"
  7854. +#include "base/values.h"
  7855. +#include "base/logging.h"
  7856. +#include "content/public/renderer/render_frame.h"
  7857. +#include "content/public/renderer/render_frame_observer.h"
  7858. +#include "content/public/renderer/render_thread.h"
  7859. +#include "extension_frame_helper.h"
  7860. +#include "../common/host_id.h"
  7861. +#include "script_injection.h"
  7862. +#include "scripts_run_info.h"
  7863. +#include "web_ui_injection_host.h"
  7864. +#include "ipc/ipc_message_macros.h"
  7865. +#include "third_party/blink/public/platform/web_url_error.h"
  7866. +#include "third_party/blink/public/web/web_document.h"
  7867. +#include "third_party/blink/public/web/web_frame.h"
  7868. +#include "third_party/blink/public/web/web_local_frame.h"
  7869. +#include "third_party/blink/public/web/web_view.h"
  7870. +#include "url/gurl.h"
  7871. +#include "../common/user_scripts_features.h"
  7872. +
  7873. +namespace user_scripts {
  7874. +
  7875. +namespace {
  7876. +
  7877. +// The length of time to wait after the DOM is complete to try and run user
  7878. +// scripts.
  7879. +const int kScriptIdleTimeoutInMs = 200;
  7880. +
  7881. +// Returns the RunLocation that follows |run_location|.
  7882. +UserScript::RunLocation NextRunLocation(UserScript::RunLocation run_location) {
  7883. + switch (run_location) {
  7884. + case UserScript::DOCUMENT_START:
  7885. + return UserScript::DOCUMENT_END;
  7886. + case UserScript::DOCUMENT_END:
  7887. + return UserScript::DOCUMENT_IDLE;
  7888. + case UserScript::DOCUMENT_IDLE:
  7889. + return UserScript::RUN_LOCATION_LAST;
  7890. + case UserScript::UNDEFINED:
  7891. + case UserScript::RUN_DEFERRED:
  7892. + case UserScript::BROWSER_DRIVEN:
  7893. + case UserScript::RUN_LOCATION_LAST:
  7894. + break;
  7895. + }
  7896. + NOTREACHED();
  7897. + return UserScript::RUN_LOCATION_LAST;
  7898. +}
  7899. +
  7900. +} // namespace
  7901. +
  7902. +class ScriptInjectionManager::RFOHelper : public content::RenderFrameObserver {
  7903. + public:
  7904. + RFOHelper(content::RenderFrame* render_frame,
  7905. + ScriptInjectionManager* manager);
  7906. + ~RFOHelper() override;
  7907. +
  7908. + private:
  7909. + // RenderFrameObserver implementation.
  7910. + void DidCreateNewDocument() override;
  7911. + void DidCreateDocumentElement() override;
  7912. + void DidFailProvisionalLoad() override;
  7913. + void DidFinishDocumentLoad() override;
  7914. + void WillDetach() override;
  7915. + void OnDestruct() override;
  7916. + void OnStop() override;
  7917. +
  7918. + // Tells the ScriptInjectionManager to run tasks associated with
  7919. + // document_idle.
  7920. + void RunIdle();
  7921. +
  7922. + void StartInjectScripts(UserScript::RunLocation run_location);
  7923. +
  7924. + // Indicate that the frame is no longer valid because it is starting
  7925. + // a new load or closing.
  7926. + void InvalidateAndResetFrame(bool force_reset);
  7927. +
  7928. + // The owning ScriptInjectionManager.
  7929. + ScriptInjectionManager* manager_;
  7930. +
  7931. + bool should_run_idle_;
  7932. +
  7933. + base::WeakPtrFactory<RFOHelper> weak_factory_{this};
  7934. +};
  7935. +
  7936. +ScriptInjectionManager::RFOHelper::RFOHelper(content::RenderFrame* render_frame,
  7937. + ScriptInjectionManager* manager)
  7938. + : content::RenderFrameObserver(render_frame),
  7939. + manager_(manager),
  7940. + should_run_idle_(true) {}
  7941. +
  7942. +ScriptInjectionManager::RFOHelper::~RFOHelper() {
  7943. +}
  7944. +
  7945. +void ScriptInjectionManager::RFOHelper::DidCreateNewDocument() {
  7946. + // LOG(INFO) << "---ScriptInjectionManager::RFOHelper::DidCreateNewDocument";
  7947. +
  7948. + // A new document is going to be shown, so invalidate the old document state.
  7949. + // Don't force-reset the frame, because it is possible that a script injection
  7950. + // was scheduled before the page was loaded, e.g. by navigating to a
  7951. + // javascript: URL before the page has loaded.
  7952. + constexpr bool kForceReset = false;
  7953. + InvalidateAndResetFrame(kForceReset);
  7954. +
  7955. + // LOG(INFO) << "---ScriptInjectionManager::RFOHelper::DidCreateNewDocument exit";
  7956. +}
  7957. +
  7958. +void ScriptInjectionManager::RFOHelper::DidCreateDocumentElement() {
  7959. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  7960. + LOG(INFO) << "UserScripts: DidCreateDocumentElement -> DOCUMENT_START";
  7961. +
  7962. + ExtensionFrameHelper::Get(render_frame())
  7963. + ->ScheduleAtDocumentStart(
  7964. + base::Bind(&ScriptInjectionManager::RFOHelper::StartInjectScripts,
  7965. + weak_factory_.GetWeakPtr(), UserScript::DOCUMENT_START));
  7966. +
  7967. + // LOG(INFO) << "---ScriptInjectionManager::RFOHelper::DidCreateDocumentElement exit";
  7968. +}
  7969. +
  7970. +void ScriptInjectionManager::RFOHelper::DidFailProvisionalLoad() {
  7971. + // LOG(INFO) << "---ScriptInjectionManager::RFOHelper::DidFailProvisionalLoad";
  7972. + auto it = manager_->frame_statuses_.find(render_frame());
  7973. + if (it != manager_->frame_statuses_.end() &&
  7974. + it->second == UserScript::DOCUMENT_START) {
  7975. + // Since the provisional load failed, the frame stays at its previous loaded
  7976. + // state and origin (or the parent's origin for new/about:blank frames).
  7977. + // Reset the frame to DOCUMENT_IDLE in order to reflect that the frame is
  7978. + // done loading, and avoid any deadlock in the system.
  7979. + //
  7980. + // We skip injection of DOCUMENT_END and DOCUMENT_IDLE scripts, because the
  7981. + // injections closely follow the DOMContentLoaded (and onload) events, which
  7982. + // are not triggered after a failed provisional load.
  7983. + // This assumption is verified in the checkDOMContentLoadedEvent subtest of
  7984. + // ExecuteScriptApiTest.FrameWithHttp204 (browser_tests).
  7985. + constexpr bool kForceReset = true;
  7986. + InvalidateAndResetFrame(kForceReset);
  7987. + should_run_idle_ = false;
  7988. + manager_->frame_statuses_[render_frame()] = UserScript::DOCUMENT_IDLE;
  7989. + }
  7990. + // LOG(INFO) << "---ScriptInjectionManager::RFOHelper::DidFailProvisionalLoad exit";
  7991. +}
  7992. +
  7993. +void ScriptInjectionManager::RFOHelper::DidFinishDocumentLoad() {
  7994. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  7995. + LOG(INFO) << "UserScripts: DidFinishDocumentLoad -> DOCUMENT_END";
  7996. +
  7997. + DCHECK(content::RenderThread::Get());
  7998. + ExtensionFrameHelper::Get(render_frame())
  7999. + ->ScheduleAtDocumentEnd(
  8000. + base::Bind(&ScriptInjectionManager::RFOHelper::StartInjectScripts,
  8001. + weak_factory_.GetWeakPtr(), UserScript::DOCUMENT_END));
  8002. +
  8003. + // We try to run idle in two places: a delayed task here and in response to
  8004. + // ContentRendererClient::RunScriptsAtDocumentIdle(). DidFinishDocumentLoad()
  8005. + // corresponds to completing the document's load, whereas
  8006. + // RunScriptsAtDocumentIdle() corresponds to completing the document and all
  8007. + // subresources' load (but before the window.onload event). We don't want to
  8008. + // hold up script injection for a particularly slow subresource, so we set a
  8009. + // delayed task from here - but if we finish everything before that point
  8010. + // (i.e., RunScriptsAtDocumentIdle() is triggered), then there's no reason to
  8011. + // keep waiting.
  8012. + render_frame()
  8013. + ->GetTaskRunner(blink::TaskType::kInternalDefault)
  8014. + ->PostDelayedTask(
  8015. + FROM_HERE,
  8016. + base::BindOnce(&ScriptInjectionManager::RFOHelper::RunIdle,
  8017. + weak_factory_.GetWeakPtr()),
  8018. + base::TimeDelta::FromMilliseconds(kScriptIdleTimeoutInMs));
  8019. +
  8020. + ExtensionFrameHelper::Get(render_frame())
  8021. + ->ScheduleAtDocumentIdle(
  8022. + base::Bind(&ScriptInjectionManager::RFOHelper::RunIdle,
  8023. + weak_factory_.GetWeakPtr()));
  8024. +}
  8025. +
  8026. +void ScriptInjectionManager::RFOHelper::WillDetach() {
  8027. + // LOG(INFO) << "---ScriptInjectionManager::RFOHelper::WillDetach";
  8028. + // The frame is closing - invalidate.
  8029. + constexpr bool kForceReset = true;
  8030. + InvalidateAndResetFrame(kForceReset);
  8031. + // LOG(INFO) << "---ScriptInjectionManager::RFOHelper::WillDetach exit";
  8032. +}
  8033. +
  8034. +void ScriptInjectionManager::RFOHelper::OnDestruct() {
  8035. + // LOG(INFO) << "---ScriptInjectionManager::RFOHelper::OnDestruct";
  8036. + manager_->RemoveObserver(this);
  8037. +}
  8038. +
  8039. +void ScriptInjectionManager::RFOHelper::OnStop() {
  8040. + // If the navigation request fails (e.g. 204/205/downloads), notify the
  8041. + // extension to avoid keeping the frame in a START state indefinitely which
  8042. + // leads to deadlocks.
  8043. + DidFailProvisionalLoad();
  8044. +}
  8045. +
  8046. +void ScriptInjectionManager::RFOHelper::RunIdle() {
  8047. + // Only notify the manager if the frame hasn't already had idle run since the
  8048. + // task to RunIdle() was posted.
  8049. + if (should_run_idle_) {
  8050. + should_run_idle_ = false;
  8051. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  8052. + LOG(INFO) << "UserScripts: RunIdle -> DOCUMENT_IDLE";
  8053. + manager_->StartInjectScripts(render_frame(), UserScript::DOCUMENT_IDLE);
  8054. + }
  8055. +}
  8056. +
  8057. +void ScriptInjectionManager::RFOHelper::StartInjectScripts(
  8058. + UserScript::RunLocation run_location) {
  8059. + manager_->StartInjectScripts(render_frame(), run_location);
  8060. +}
  8061. +
  8062. +void ScriptInjectionManager::RFOHelper::InvalidateAndResetFrame(
  8063. + bool force_reset) {
  8064. + // Invalidate any pending idle injections, and reset the frame inject on idle.
  8065. + weak_factory_.InvalidateWeakPtrs();
  8066. + // We reset to inject on idle, because the frame can be reused (in the case of
  8067. + // navigation).
  8068. + should_run_idle_ = true;
  8069. +
  8070. + // Reset the frame if either |force_reset| is true, or if the manager is
  8071. + // keeping track of the state of the frame (in which case we need to clean it
  8072. + // up).
  8073. + if (force_reset || manager_->frame_statuses_.count(render_frame()) != 0)
  8074. + manager_->InvalidateForFrame(render_frame());
  8075. +}
  8076. +
  8077. +ScriptInjectionManager::ScriptInjectionManager(
  8078. + UserScriptSetManager* user_script_set_manager)
  8079. + : user_script_set_manager_(user_script_set_manager),
  8080. + user_script_set_manager_observer_(this) {
  8081. + user_script_set_manager_observer_.Add(user_script_set_manager_);
  8082. +}
  8083. +
  8084. +ScriptInjectionManager::~ScriptInjectionManager() {
  8085. + for (const auto& injection : pending_injections_)
  8086. + injection->invalidate_render_frame();
  8087. + for (const auto& injection : running_injections_)
  8088. + injection->invalidate_render_frame();
  8089. +}
  8090. +
  8091. +void ScriptInjectionManager::OnRenderFrameCreated(
  8092. + content::RenderFrame* render_frame) {
  8093. + rfo_helpers_.push_back(std::make_unique<RFOHelper>(render_frame, this));
  8094. + // LOG(INFO) << "---ScriptInjectionManager::OnRenderFrameCreated";
  8095. +}
  8096. +
  8097. +void ScriptInjectionManager::OnInjectionFinished(
  8098. + ScriptInjection* injection) {
  8099. + auto iter =
  8100. + std::find_if(running_injections_.begin(), running_injections_.end(),
  8101. + [injection](const std::unique_ptr<ScriptInjection>& mode) {
  8102. + return injection == mode.get();
  8103. + });
  8104. + if (iter != running_injections_.end())
  8105. + running_injections_.erase(iter);
  8106. +}
  8107. +
  8108. +void ScriptInjectionManager::OnUserScriptsUpdated(
  8109. + const std::set<HostID>& changed_hosts) {
  8110. + for (auto iter = pending_injections_.begin();
  8111. + iter != pending_injections_.end();) {
  8112. + if (changed_hosts.count((*iter)->host_id()) > 0)
  8113. + iter = pending_injections_.erase(iter);
  8114. + else
  8115. + ++iter;
  8116. + }
  8117. +}
  8118. +
  8119. +void ScriptInjectionManager::RemoveObserver(RFOHelper* helper) {
  8120. + for (auto iter = rfo_helpers_.begin(); iter != rfo_helpers_.end(); ++iter) {
  8121. + if (iter->get() == helper) {
  8122. + rfo_helpers_.erase(iter);
  8123. + break;
  8124. + }
  8125. + }
  8126. +}
  8127. +
  8128. +void ScriptInjectionManager::InvalidateForFrame(content::RenderFrame* frame) {
  8129. + // If the frame invalidated is the frame being injected into, we need to
  8130. + // note it.
  8131. + active_injection_frames_.erase(frame);
  8132. +
  8133. + for (auto iter = pending_injections_.begin();
  8134. + iter != pending_injections_.end();) {
  8135. + if ((*iter)->render_frame() == frame)
  8136. + iter = pending_injections_.erase(iter);
  8137. + else
  8138. + ++iter;
  8139. + }
  8140. +
  8141. + frame_statuses_.erase(frame);
  8142. +}
  8143. +
  8144. +void ScriptInjectionManager::StartInjectScripts(
  8145. + content::RenderFrame* frame,
  8146. + UserScript::RunLocation run_location) {
  8147. + auto iter = frame_statuses_.find(frame);
  8148. + // We also don't execute if we detect that the run location is somehow out of
  8149. + // order. This can happen if:
  8150. + // - The first run location reported for the frame isn't DOCUMENT_START, or
  8151. + // - The run location reported doesn't immediately follow the previous
  8152. + // reported run location.
  8153. + // We don't want to run because extensions may have requirements that scripts
  8154. + // running in an earlier run location have run by the time a later script
  8155. + // runs. Better to just not run.
  8156. + // Note that we check run_location > NextRunLocation() in the second clause
  8157. + // (as opposed to !=) because earlier signals (like DidCreateDocumentElement)
  8158. + // can happen multiple times, so we can receive earlier/equal run locations.
  8159. + if ((iter == frame_statuses_.end() &&
  8160. + run_location != UserScript::DOCUMENT_START) ||
  8161. + (iter != frame_statuses_.end() &&
  8162. + run_location > NextRunLocation(iter->second))) {
  8163. + // We also invalidate the frame, because the run order of pending injections
  8164. + // may also be bad.
  8165. + InvalidateForFrame(frame);
  8166. + return;
  8167. + } else if (iter != frame_statuses_.end() && iter->second >= run_location) {
  8168. + // Certain run location signals (like DidCreateDocumentElement) can happen
  8169. + // multiple times. Ignore the subsequent signals.
  8170. + return;
  8171. + }
  8172. +
  8173. + // Otherwise, all is right in the world, and we can get on with the
  8174. + // injections!
  8175. + frame_statuses_[frame] = run_location;
  8176. + InjectScripts(frame, run_location);
  8177. +}
  8178. +
  8179. +void ScriptInjectionManager::InjectScripts(
  8180. + content::RenderFrame* frame,
  8181. + UserScript::RunLocation run_location) {
  8182. + // LOG(INFO) << "---ScriptInjectionManager::InjectScripts";
  8183. +
  8184. + // Find any injections that want to run on the given frame.
  8185. + ScriptInjectionVector frame_injections;
  8186. + for (auto iter = pending_injections_.begin();
  8187. + iter != pending_injections_.end();) {
  8188. + if ((*iter)->render_frame() == frame) {
  8189. + frame_injections.push_back(std::move(*iter));
  8190. + iter = pending_injections_.erase(iter);
  8191. + } else {
  8192. + ++iter;
  8193. + }
  8194. + }
  8195. +
  8196. + // Add any injections for user scripts.
  8197. + int tab_id = ExtensionFrameHelper::Get(frame)->tab_id();
  8198. + user_script_set_manager_->GetAllInjections(&frame_injections, frame, tab_id,
  8199. + run_location);
  8200. +
  8201. + // Note that we are running in |frame|.
  8202. + active_injection_frames_.insert(frame);
  8203. +
  8204. + ScriptsRunInfo scripts_run_info(frame, run_location);
  8205. +
  8206. + for (auto iter = frame_injections.begin(); iter != frame_injections.end();) {
  8207. + // It's possible for thScriptsRunInfoe frame to be invalidated in the course of injection
  8208. + // (if a script removes its own frame, for example). If this happens, abort.
  8209. + if (!active_injection_frames_.count(frame))
  8210. + break;
  8211. + std::unique_ptr<ScriptInjection> injection(std::move(*iter));
  8212. + iter = frame_injections.erase(iter);
  8213. + TryToInject(std::move(injection), run_location, &scripts_run_info);
  8214. + }
  8215. +
  8216. + // We are done running in the frame.
  8217. + active_injection_frames_.erase(frame);
  8218. +
  8219. + scripts_run_info.LogRun(activity_logging_enabled_);
  8220. +}
  8221. +
  8222. +void ScriptInjectionManager::TryToInject(
  8223. + std::unique_ptr<ScriptInjection> injection,
  8224. + UserScript::RunLocation run_location,
  8225. + ScriptsRunInfo* scripts_run_info) {
  8226. + // Try to inject the script. If the injection is waiting (i.e., for
  8227. + // permission), add it to the list of pending injections. If the injection
  8228. + // has blocked, add it to the list of running injections.
  8229. + // The Unretained below is safe because this object owns all the
  8230. + // ScriptInjections, so is guaranteed to outlive them.
  8231. + switch (injection->TryToInject(
  8232. + run_location, scripts_run_info,
  8233. + base::Bind(&ScriptInjectionManager::OnInjectionFinished,
  8234. + base::Unretained(this)))) {
  8235. + case ScriptInjection::INJECTION_WAITING:
  8236. + pending_injections_.push_back(std::move(injection));
  8237. + break;
  8238. + case ScriptInjection::INJECTION_BLOCKED:
  8239. + running_injections_.push_back(std::move(injection));
  8240. + break;
  8241. + case ScriptInjection::INJECTION_FINISHED:
  8242. + break;
  8243. + }
  8244. +}
  8245. +
  8246. +} // namespace extensions
  8247. diff --git a/components/user_scripts/renderer/script_injection_manager.h b/components/user_scripts/renderer/script_injection_manager.h
  8248. new file mode 100755
  8249. --- /dev/null
  8250. +++ b/components/user_scripts/renderer/script_injection_manager.h
  8251. @@ -0,0 +1,102 @@
  8252. +#include <stdint.h>
  8253. +
  8254. +#include <map>
  8255. +#include <set>
  8256. +#include <string>
  8257. +#include <vector>
  8258. +
  8259. +#include "base/callback.h"
  8260. +#include "base/macros.h"
  8261. +#include "base/scoped_observer.h"
  8262. +#include "../common/user_script.h"
  8263. +#include "script_injection.h"
  8264. +#include "user_script_set_manager.h"
  8265. +
  8266. +namespace user_scripts {
  8267. +
  8268. +// The ScriptInjectionManager manages extensions injecting scripts into frames
  8269. +// via both content/user scripts and tabs.executeScript(). It is responsible for
  8270. +// maintaining any pending injections awaiting permission or the appropriate
  8271. +// load point, and injecting them when ready.
  8272. +class ScriptInjectionManager : public UserScriptSetManager::Observer {
  8273. + public:
  8274. + explicit ScriptInjectionManager(
  8275. + UserScriptSetManager* user_script_set_manager);
  8276. + virtual ~ScriptInjectionManager();
  8277. +
  8278. + // Notifies that a new render view has been created.
  8279. + void OnRenderFrameCreated(content::RenderFrame* render_frame);
  8280. +
  8281. + // Removes pending injections of the unloaded extension.
  8282. + //void OnExtensionUnloaded(const std::string& extension_id);
  8283. +
  8284. + void set_activity_logging_enabled(bool enabled) {
  8285. + activity_logging_enabled_ = enabled;
  8286. + }
  8287. +
  8288. + private:
  8289. + // A RenderFrameObserver implementation which watches the various render
  8290. + // frames in order to notify the ScriptInjectionManager of different
  8291. + // document load states and IPCs.
  8292. + class RFOHelper;
  8293. +
  8294. + using FrameStatusMap =
  8295. + std::map<content::RenderFrame*, UserScript::RunLocation>;
  8296. +
  8297. + using ScriptInjectionVector = std::vector<std::unique_ptr<ScriptInjection>>;
  8298. +
  8299. + // Notifies that an injection has been finished.
  8300. + void OnInjectionFinished(ScriptInjection* injection);
  8301. +
  8302. + // UserScriptSetManager::Observer implementation.
  8303. + void OnUserScriptsUpdated(const std::set<HostID>& changed_hosts) override;
  8304. +
  8305. + // Notifies that an RFOHelper should be removed.
  8306. + void RemoveObserver(RFOHelper* helper);
  8307. +
  8308. + // Invalidate any pending tasks associated with |frame|.
  8309. + void InvalidateForFrame(content::RenderFrame* frame);
  8310. +
  8311. + // Starts the process to inject appropriate scripts into |frame|.
  8312. + void StartInjectScripts(content::RenderFrame* frame,
  8313. + UserScript::RunLocation run_location);
  8314. +
  8315. + // Actually injects the scripts into |frame|.
  8316. + void InjectScripts(content::RenderFrame* frame,
  8317. + UserScript::RunLocation run_location);
  8318. +
  8319. + // Try to inject and store injection if it has not finished.
  8320. + void TryToInject(std::unique_ptr<ScriptInjection> injection,
  8321. + UserScript::RunLocation run_location,
  8322. + ScriptsRunInfo* scripts_run_info);
  8323. +
  8324. + // The map of active web frames to their corresponding statuses. The
  8325. + // RunLocation of the frame corresponds to the last location that has ran.
  8326. + FrameStatusMap frame_statuses_;
  8327. +
  8328. + // The frames currently being injected into, so long as that frame is valid.
  8329. + std::set<content::RenderFrame*> active_injection_frames_;
  8330. +
  8331. + // The collection of RFOHelpers.
  8332. + std::vector<std::unique_ptr<RFOHelper>> rfo_helpers_;
  8333. +
  8334. + // The set of UserScripts associated with extensions. Owned by the Dispatcher.
  8335. + UserScriptSetManager* user_script_set_manager_;
  8336. +
  8337. + // Pending injections which are waiting for either the proper run location or
  8338. + // user consent.
  8339. + ScriptInjectionVector pending_injections_;
  8340. +
  8341. + // Running injections which are waiting for async callbacks from blink.
  8342. + ScriptInjectionVector running_injections_;
  8343. +
  8344. + // Whether or not dom activity should be logged for scripts injected.
  8345. + bool activity_logging_enabled_ = false;
  8346. +
  8347. + ScopedObserver<UserScriptSetManager, UserScriptSetManager::Observer>
  8348. + user_script_set_manager_observer_;
  8349. +
  8350. + DISALLOW_COPY_AND_ASSIGN(ScriptInjectionManager);
  8351. +};
  8352. +
  8353. +}
  8354. diff --git a/components/user_scripts/renderer/script_injector.h b/components/user_scripts/renderer/script_injector.h
  8355. new file mode 100755
  8356. --- /dev/null
  8357. +++ b/components/user_scripts/renderer/script_injector.h
  8358. @@ -0,0 +1,96 @@
  8359. +// Copyright 2014 The Chromium Authors. All rights reserved.
  8360. +// Use of this source code is governed by a BSD-style license that can be
  8361. +// found in the LICENSE file.
  8362. +
  8363. +#ifndef EXTENSIONS_RENDERER_SCRIPT_INJECTOR_H_
  8364. +#define EXTENSIONS_RENDERER_SCRIPT_INJECTOR_H_
  8365. +
  8366. +#include <memory>
  8367. +#include <vector>
  8368. +
  8369. +#include "../common/constants.h"
  8370. +#include "../common/user_script.h"
  8371. +#include "third_party/blink/public/web/web_script_source.h"
  8372. +
  8373. +class InjectionHost;
  8374. +
  8375. +namespace blink {
  8376. +class WebLocalFrame;
  8377. +}
  8378. +
  8379. +namespace user_scripts {
  8380. +
  8381. +// The pseudo-delegate class for a ScriptInjection that provides all necessary
  8382. +// information about how to inject the script, including what code to inject and
  8383. +// when (run location), but without any injection logic.
  8384. +class ScriptInjector {
  8385. + public:
  8386. + // The possible reasons for not injecting the script.
  8387. + enum InjectFailureReason {
  8388. + EXTENSION_REMOVED, // The extension was removed before injection.
  8389. + NOT_ALLOWED, // The script is not allowed to inject.
  8390. + WONT_INJECT // The injection won't inject because the user rejected
  8391. + // (or just did not accept) the injection.
  8392. + };
  8393. +
  8394. + virtual ~ScriptInjector() {}
  8395. +
  8396. + // Returns the script type of this particular injection.
  8397. + virtual UserScript::InjectionType script_type() const = 0;
  8398. +
  8399. + // Returns true if the script is running inside a user gesture.
  8400. + virtual bool IsUserGesture() const = 0;
  8401. +
  8402. + // Returns the CSS origin of this injection.
  8403. + virtual base::Optional<CSSOrigin> GetCssOrigin() const = 0;
  8404. +
  8405. + // Returns the key for this injection, if it's a CSS injection.
  8406. + virtual const base::Optional<std::string> GetInjectionKey() const = 0;
  8407. +
  8408. + // Returns true if the script expects results.
  8409. + virtual bool ExpectsResults() const = 0;
  8410. +
  8411. + // Returns true if the script should inject JS source at the given
  8412. + // |run_location|.
  8413. + virtual bool ShouldInjectJs(
  8414. + UserScript::RunLocation run_location,
  8415. + const std::set<std::string>& executing_scripts) const = 0;
  8416. +
  8417. + // Returns true if the script should inject CSS at the given |run_location|.
  8418. + virtual bool ShouldInjectCss(
  8419. + UserScript::RunLocation run_location,
  8420. + const std::set<std::string>& injected_stylesheets) const = 0;
  8421. +
  8422. + // Returns the javascript sources to inject at the given |run_location|.
  8423. + // Only called if ShouldInjectJs() is true.
  8424. + virtual std::vector<blink::WebScriptSource> GetJsSources(
  8425. + UserScript::RunLocation run_location,
  8426. + std::set<std::string>* executing_scripts,
  8427. + size_t* num_injected_js_scripts) const = 0;
  8428. +
  8429. + // Returns the css to inject at the given |run_location|.
  8430. + // Only called if ShouldInjectCss() is true.
  8431. + virtual std::vector<blink::WebString> GetCssSources(
  8432. + UserScript::RunLocation run_location,
  8433. + std::set<std::string>* injected_stylesheets,
  8434. + size_t* num_injected_stylesheets) const = 0;
  8435. +
  8436. + // Notifies the script that injection has completed, with a possibly-populated
  8437. + // list of results (depending on whether or not ExpectsResults() was true).
  8438. + // |render_frame| contains the render frame, or null if the frame was
  8439. + // invalidated.
  8440. + virtual void OnInjectionComplete(
  8441. + std::unique_ptr<base::Value> execution_result,
  8442. + UserScript::RunLocation run_location,
  8443. + content::RenderFrame* render_frame) = 0;
  8444. +
  8445. + // Notifies the script that injection will never occur.
  8446. + // |render_frame| contains the render frame, or null if the frame was
  8447. + // invalidated.
  8448. + virtual void OnWillNotInject(InjectFailureReason reason,
  8449. + content::RenderFrame* render_frame) = 0;
  8450. +};
  8451. +
  8452. +} // namespace extensions
  8453. +
  8454. +#endif // EXTENSIONS_RENDERER_SCRIPT_INJECTOR_H_
  8455. diff --git a/components/user_scripts/renderer/scripts_run_info.cc b/components/user_scripts/renderer/scripts_run_info.cc
  8456. new file mode 100755
  8457. --- /dev/null
  8458. +++ b/components/user_scripts/renderer/scripts_run_info.cc
  8459. @@ -0,0 +1,31 @@
  8460. +// Copyright 2014 The Chromium Authors. All rights reserved.
  8461. +// Use of this source code is governed by a BSD-style license that can be
  8462. +// found in the LICENSE file.
  8463. +
  8464. +#include "scripts_run_info.h"
  8465. +
  8466. +#include "base/metrics/histogram_macros.h"
  8467. +#include "content/public/renderer/render_frame.h"
  8468. +#include "content/public/renderer/render_thread.h"
  8469. +#include "script_context.h"
  8470. +#include "third_party/blink/public/web/web_local_frame.h"
  8471. +
  8472. +namespace user_scripts {
  8473. +
  8474. +ScriptsRunInfo::ScriptsRunInfo(content::RenderFrame* render_frame,
  8475. + UserScript::RunLocation location)
  8476. + : num_css(0u),
  8477. + num_js(0u),
  8478. + num_blocking_js(0u),
  8479. + routing_id_(render_frame->GetRoutingID()),
  8480. + run_location_(location),
  8481. + frame_url_(ScriptContext::GetDocumentLoaderURLForFrame(
  8482. + render_frame->GetWebFrame())) {}
  8483. +
  8484. +ScriptsRunInfo::~ScriptsRunInfo() {
  8485. +}
  8486. +
  8487. +void ScriptsRunInfo::LogRun(bool send_script_activity) {
  8488. +}
  8489. +
  8490. +} // namespace extensions
  8491. diff --git a/components/user_scripts/renderer/scripts_run_info.h b/components/user_scripts/renderer/scripts_run_info.h
  8492. new file mode 100755
  8493. --- /dev/null
  8494. +++ b/components/user_scripts/renderer/scripts_run_info.h
  8495. @@ -0,0 +1,70 @@
  8496. +// Copyright 2014 The Chromium Authors. All rights reserved.
  8497. +// Use of this source code is governed by a BSD-style license that can be
  8498. +// found in the LICENSE file.
  8499. +
  8500. +#ifndef EXTENSIONS_RENDERER_SCRIPTS_RUN_INFO_H_
  8501. +#define EXTENSIONS_RENDERER_SCRIPTS_RUN_INFO_H_
  8502. +
  8503. +#include <stddef.h>
  8504. +
  8505. +#include <map>
  8506. +#include <set>
  8507. +#include <string>
  8508. +
  8509. +#include "base/macros.h"
  8510. +#include "base/timer/elapsed_timer.h"
  8511. +#include "../common/user_script.h"
  8512. +
  8513. +namespace content {
  8514. +class RenderFrame;
  8515. +}
  8516. +
  8517. +namespace user_scripts {
  8518. +
  8519. +// A struct containing information about a script run.
  8520. +struct ScriptsRunInfo {
  8521. + // Map of extensions IDs to the executing script paths.
  8522. + typedef std::map<std::string, std::set<std::string> > ExecutingScriptsMap;
  8523. +
  8524. + ScriptsRunInfo(content::RenderFrame* render_frame,
  8525. + UserScript::RunLocation location);
  8526. + ~ScriptsRunInfo();
  8527. +
  8528. + // The number of CSS scripts injected.
  8529. + size_t num_css;
  8530. + // The number of JS scripts injected.
  8531. + size_t num_js;
  8532. + // The number of blocked JS scripts injected.
  8533. + size_t num_blocking_js;
  8534. + // A map of extension ids to executing script paths.
  8535. + ExecutingScriptsMap executing_scripts;
  8536. + // A map of extension ids to injected stylesheet paths.
  8537. + ExecutingScriptsMap injected_stylesheets;
  8538. + // The elapsed time since the ScriptsRunInfo was constructed.
  8539. + base::ElapsedTimer timer;
  8540. +
  8541. + // Log information about a given script run. If |send_script_activity| is
  8542. + // true, this also informs the browser of the script run.
  8543. + void LogRun(bool send_script_activity);
  8544. +
  8545. + static void LogLongInjectionTaskTime(UserScript::RunLocation run_location,
  8546. + const base::TimeDelta& elapsed);
  8547. +
  8548. + private:
  8549. + // The routinig id to use to notify the browser of any injections. Since the
  8550. + // frame may be deleted in injection, we don't hold on to a reference to it
  8551. + // directly.
  8552. + int routing_id_;
  8553. +
  8554. + // The run location at which injection is happening.
  8555. + UserScript::RunLocation run_location_;
  8556. +
  8557. + // The url of the frame, preserved for the same reason as the routing id.
  8558. + GURL frame_url_;
  8559. +
  8560. + DISALLOW_COPY_AND_ASSIGN(ScriptsRunInfo);
  8561. +};
  8562. +
  8563. +} // namespace extensions
  8564. +
  8565. +#endif // EXTENSIONS_RENDERER_SCRIPTS_RUN_INFO_H_
  8566. diff --git a/components/user_scripts/renderer/user_script_injector.cc b/components/user_scripts/renderer/user_script_injector.cc
  8567. new file mode 100755
  8568. --- /dev/null
  8569. +++ b/components/user_scripts/renderer/user_script_injector.cc
  8570. @@ -0,0 +1,229 @@
  8571. +// Copyright 2014 The Chromium Authors. All rights reserved.
  8572. +// Use of this source code is governed by a BSD-style license that can be
  8573. +// found in the LICENSE file.
  8574. +
  8575. +#include "user_script_injector.h"
  8576. +
  8577. +#include <tuple>
  8578. +#include <vector>
  8579. +
  8580. +#include "base/logging.h"
  8581. +#include "base/lazy_instance.h"
  8582. +#include "content/public/common/url_constants.h"
  8583. +#include "content/public/renderer/render_frame.h"
  8584. +#include "content/public/renderer/render_thread.h"
  8585. +#include "content/public/renderer/render_view.h"
  8586. +#include "components/user_scripts/renderer/grit/user_scripts_renderer_resources.h"
  8587. +#include "injection_host.h"
  8588. +#include "script_context.h"
  8589. +#include "scripts_run_info.h"
  8590. +#include "third_party/blink/public/web/web_document.h"
  8591. +#include "third_party/blink/public/web/web_local_frame.h"
  8592. +#include "third_party/blink/public/web/web_script_source.h"
  8593. +#include "ui/base/resource/resource_bundle.h"
  8594. +#include "url/gurl.h"
  8595. +
  8596. +namespace user_scripts {
  8597. +
  8598. +namespace {
  8599. +
  8600. +struct RoutingInfoKey {
  8601. + int routing_id;
  8602. + int script_id;
  8603. +
  8604. + RoutingInfoKey(int routing_id, int script_id)
  8605. + : routing_id(routing_id), script_id(script_id) {}
  8606. +
  8607. + bool operator<(const RoutingInfoKey& other) const {
  8608. + return std::tie(routing_id, script_id) <
  8609. + std::tie(other.routing_id, other.script_id);
  8610. + }
  8611. +};
  8612. +
  8613. +using RoutingInfoMap = std::map<RoutingInfoKey, bool>;
  8614. +
  8615. +// A map records whether a given |script_id| from a webview-added user script
  8616. +// is allowed to inject on the render of given |routing_id|.
  8617. +// Once a script is added, the decision of whether or not allowed to inject
  8618. +// won't be changed.
  8619. +// After removed by the webview, the user scipt will also be removed
  8620. +// from the render. Therefore, there won't be any query from the same
  8621. +// |script_id| and |routing_id| pair.
  8622. +// base::LazyInstance<RoutingInfoMap>::DestructorAtExit g_routing_info_map =
  8623. +// LAZY_INSTANCE_INITIALIZER;
  8624. +
  8625. +// Greasemonkey API source that is injected with the scripts.
  8626. +struct GreasemonkeyApiJsString {
  8627. + GreasemonkeyApiJsString();
  8628. + blink::WebScriptSource GetSource() const;
  8629. +
  8630. + private:
  8631. + blink::WebString source_;
  8632. +};
  8633. +
  8634. +// The below constructor, monstrous as it is, just makes a WebScriptSource from
  8635. +// the GreasemonkeyApiJs resource.
  8636. +GreasemonkeyApiJsString::GreasemonkeyApiJsString() {
  8637. + std::string greasemonky_api_js(
  8638. + ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(
  8639. + IDR_GREASEMONKEY_API_JS));
  8640. + source_ = blink::WebString::FromUTF8(greasemonky_api_js);
  8641. +}
  8642. +
  8643. +blink::WebScriptSource GreasemonkeyApiJsString::GetSource() const {
  8644. + return blink::WebScriptSource(source_);
  8645. +}
  8646. +
  8647. +base::LazyInstance<GreasemonkeyApiJsString>::Leaky g_greasemonkey_api =
  8648. + LAZY_INSTANCE_INITIALIZER;
  8649. +
  8650. +bool ShouldInjectScripts(const UserScript::FileList& scripts,
  8651. + const std::set<std::string>& injected_files) {
  8652. + for (const std::unique_ptr<UserScript::File>& file : scripts) {
  8653. + // Check if the script is already injected.
  8654. + if (injected_files.count(file->url().path()) == 0) {
  8655. + return true;
  8656. + }
  8657. + }
  8658. + return false;
  8659. +}
  8660. +
  8661. +} // namespace
  8662. +
  8663. +UserScriptInjector::UserScriptInjector(const UserScript* script,
  8664. + UserScriptSet* script_list)
  8665. + : script_(script),
  8666. + user_script_set_(script_list),
  8667. + script_id_(script_->id()),
  8668. + user_script_set_observer_(this) {
  8669. + // LOG(INFO) << "---UserScriptInjector::UserScriptInjector";
  8670. + user_script_set_observer_.Add(script_list);
  8671. +}
  8672. +
  8673. +UserScriptInjector::~UserScriptInjector() {
  8674. +}
  8675. +
  8676. +void UserScriptInjector::OnUserScriptsUpdated(
  8677. + const std::set<HostID>& changed_hosts,
  8678. + const UserScriptList& scripts) {
  8679. + // When user scripts are updated, all the old script pointers are invalidated.
  8680. + script_ = nullptr;
  8681. + // If the host causing this injection changed, then this injection
  8682. + // will be removed, and there's no guarantee the backing script still exists.
  8683. + // if (changed_hosts.count(host_id_) > 0)
  8684. + // return;
  8685. +
  8686. + for (const std::unique_ptr<UserScript>& script : scripts) {
  8687. + if (script->id() == script_id_) {
  8688. + script_ = script.get();
  8689. + break;
  8690. + }
  8691. + }
  8692. + // If |host_id_| wasn't in |changed_hosts|, then the script for this injection
  8693. + // should be guaranteed to exist.
  8694. + DCHECK(script_);
  8695. +}
  8696. +
  8697. +UserScript::InjectionType UserScriptInjector::script_type() const {
  8698. + return UserScript::CONTENT_SCRIPT;
  8699. +}
  8700. +
  8701. +bool UserScriptInjector::IsUserGesture() const {
  8702. + return false;
  8703. +}
  8704. +
  8705. +bool UserScriptInjector::ExpectsResults() const {
  8706. + return false;
  8707. +}
  8708. +
  8709. +base::Optional<CSSOrigin> UserScriptInjector::GetCssOrigin() const {
  8710. + return base::nullopt;
  8711. +}
  8712. +
  8713. +const base::Optional<std::string> UserScriptInjector::GetInjectionKey() const {
  8714. + return base::nullopt;
  8715. +}
  8716. +
  8717. +bool UserScriptInjector::ShouldInjectJs(
  8718. + UserScript::RunLocation run_location,
  8719. + const std::set<std::string>& executing_scripts) const {
  8720. + return script_ && script_->run_location() == run_location &&
  8721. + !script_->js_scripts().empty() &&
  8722. + ShouldInjectScripts(script_->js_scripts(), executing_scripts);
  8723. +}
  8724. +
  8725. +bool UserScriptInjector::ShouldInjectCss(
  8726. + UserScript::RunLocation run_location,
  8727. + const std::set<std::string>& injected_stylesheets) const {
  8728. + return script_ && run_location == UserScript::DOCUMENT_START &&
  8729. + !script_->css_scripts().empty() &&
  8730. + ShouldInjectScripts(script_->css_scripts(), injected_stylesheets);
  8731. +}
  8732. +
  8733. +std::vector<blink::WebScriptSource> UserScriptInjector::GetJsSources(
  8734. + UserScript::RunLocation run_location,
  8735. + std::set<std::string>* executing_scripts,
  8736. + size_t* num_injected_js_scripts) const {
  8737. + DCHECK(script_);
  8738. + std::vector<blink::WebScriptSource> sources;
  8739. +
  8740. + DCHECK_EQ(script_->run_location(), run_location);
  8741. +
  8742. + const UserScript::FileList& js_scripts = script_->js_scripts();
  8743. + sources.reserve(js_scripts.size() +
  8744. + (script_->emulate_greasemonkey() ? 1 : 0));
  8745. + // Emulate Greasemonkey API for scripts that were converted to extension
  8746. + // user scripts.
  8747. + if (script_->emulate_greasemonkey())
  8748. + sources.push_back(g_greasemonkey_api.Get().GetSource());
  8749. + for (const std::unique_ptr<UserScript::File>& file : js_scripts) {
  8750. + const GURL& script_url = file->url();
  8751. + // Check if the script is already injected.
  8752. + if (executing_scripts->count(script_url.path()) != 0)
  8753. + continue;
  8754. +
  8755. + sources.push_back(blink::WebScriptSource(
  8756. + user_script_set_->GetJsSource(*file, script_->emulate_greasemonkey()),
  8757. + script_url));
  8758. +
  8759. + (*num_injected_js_scripts) += 1;
  8760. + executing_scripts->insert(script_url.path());
  8761. + }
  8762. +
  8763. + return sources;
  8764. +}
  8765. +
  8766. +std::vector<blink::WebString> UserScriptInjector::GetCssSources(
  8767. + UserScript::RunLocation run_location,
  8768. + std::set<std::string>* injected_stylesheets,
  8769. + size_t* num_injected_stylesheets) const {
  8770. + DCHECK(script_);
  8771. + DCHECK_EQ(UserScript::DOCUMENT_START, run_location);
  8772. +
  8773. + std::vector<blink::WebString> sources;
  8774. +
  8775. + const UserScript::FileList& css_scripts = script_->css_scripts();
  8776. + sources.reserve(css_scripts.size());
  8777. + for (const std::unique_ptr<UserScript::File>& file : script_->css_scripts()) {
  8778. + const std::string& stylesheet_path = file->url().path();
  8779. + // Check if the stylesheet is already injected.
  8780. + if (injected_stylesheets->count(stylesheet_path) != 0)
  8781. + continue;
  8782. +
  8783. + sources.push_back(user_script_set_->GetCssSource(*file));
  8784. + (*num_injected_stylesheets) += 1;
  8785. + injected_stylesheets->insert(stylesheet_path);
  8786. + }
  8787. + return sources;
  8788. +}
  8789. +
  8790. +void UserScriptInjector::OnInjectionComplete(
  8791. + std::unique_ptr<base::Value> execution_result,
  8792. + UserScript::RunLocation run_location,
  8793. + content::RenderFrame* render_frame) {}
  8794. +
  8795. +void UserScriptInjector::OnWillNotInject(InjectFailureReason reason,
  8796. + content::RenderFrame* render_frame) {
  8797. +}
  8798. +
  8799. +} // namespace extensions
  8800. diff --git a/components/user_scripts/renderer/user_script_injector.h b/components/user_scripts/renderer/user_script_injector.h
  8801. new file mode 100755
  8802. --- /dev/null
  8803. +++ b/components/user_scripts/renderer/user_script_injector.h
  8804. @@ -0,0 +1,86 @@
  8805. +// Copyright 2014 The Chromium Authors. All rights reserved.
  8806. +// Use of this source code is governed by a BSD-style license that can be
  8807. +// found in the LICENSE file.
  8808. +
  8809. +#ifndef EXTENSIONS_RENDERER_USER_SCRIPT_INJECTOR_H_
  8810. +#define EXTENSIONS_RENDERER_USER_SCRIPT_INJECTOR_H_
  8811. +
  8812. +#include <memory>
  8813. +#include <string>
  8814. +
  8815. +#include "base/macros.h"
  8816. +#include "base/scoped_observer.h"
  8817. +#include "../common/user_script.h"
  8818. +#include "script_injection.h"
  8819. +#include "user_script_set.h"
  8820. +
  8821. +class InjectionHost;
  8822. +
  8823. +namespace blink {
  8824. +class WebLocalFrame;
  8825. +}
  8826. +
  8827. +namespace user_scripts {
  8828. +
  8829. +// A ScriptInjector for UserScripts.
  8830. +class UserScriptInjector : public ScriptInjector,
  8831. + public UserScriptSet::Observer {
  8832. + public:
  8833. + UserScriptInjector(const UserScript* user_script,
  8834. + UserScriptSet* user_script_set);
  8835. + ~UserScriptInjector() override;
  8836. +
  8837. + private:
  8838. + // UserScriptSet::Observer implementation.
  8839. + void OnUserScriptsUpdated(const std::set<HostID>& changed_hosts,
  8840. + const UserScriptList& scripts) override;
  8841. +
  8842. + // ScriptInjector implementation.
  8843. + UserScript::InjectionType script_type() const override;
  8844. + bool IsUserGesture() const override;
  8845. + base::Optional<CSSOrigin> GetCssOrigin() const override;
  8846. + const base::Optional<std::string> GetInjectionKey() const override;
  8847. + bool ExpectsResults() const override;
  8848. + bool ShouldInjectJs(
  8849. + UserScript::RunLocation run_location,
  8850. + const std::set<std::string>& executing_scripts) const override;
  8851. + bool ShouldInjectCss(
  8852. + UserScript::RunLocation run_location,
  8853. + const std::set<std::string>& injected_stylesheets) const override;
  8854. + std::vector<blink::WebScriptSource> GetJsSources(
  8855. + UserScript::RunLocation run_location,
  8856. + std::set<std::string>* executing_scripts,
  8857. + size_t* num_injected_js_scripts) const override;
  8858. + std::vector<blink::WebString> GetCssSources(
  8859. + UserScript::RunLocation run_location,
  8860. + std::set<std::string>* injected_stylesheets,
  8861. + size_t* num_injected_stylesheets) const override;
  8862. + void OnInjectionComplete(std::unique_ptr<base::Value> execution_result,
  8863. + UserScript::RunLocation run_location,
  8864. + content::RenderFrame* render_frame) override;
  8865. + void OnWillNotInject(InjectFailureReason reason,
  8866. + content::RenderFrame* render_frame) override;
  8867. +
  8868. + // The associated user script. Owned by the UserScriptInjector that created
  8869. + // this object.
  8870. + const UserScript* script_;
  8871. +
  8872. + // The UserScriptSet that eventually owns the UserScript this
  8873. + // UserScriptInjector points to.
  8874. + // Outlives |this|.
  8875. + UserScriptSet* const user_script_set_;
  8876. +
  8877. + // The id of the associated user script. We cache this because when we update
  8878. + // the |script_| associated with this injection, the old referance may be
  8879. + // deleted.
  8880. + int script_id_;
  8881. +
  8882. + ScopedObserver<UserScriptSet, UserScriptSet::Observer>
  8883. + user_script_set_observer_;
  8884. +
  8885. + DISALLOW_COPY_AND_ASSIGN(UserScriptInjector);
  8886. +};
  8887. +
  8888. +} // namespace extensions
  8889. +
  8890. +#endif // EXTENSIONS_RENDERER_USER_SCRIPT_INJECTOR_H_
  8891. diff --git a/components/user_scripts/renderer/user_script_set.cc b/components/user_scripts/renderer/user_script_set.cc
  8892. new file mode 100755
  8893. --- /dev/null
  8894. +++ b/components/user_scripts/renderer/user_script_set.cc
  8895. @@ -0,0 +1,260 @@
  8896. +// Copyright 2014 The Chromium Authors. All rights reserved.
  8897. +// Use of this source code is governed by a BSD-style license that can be
  8898. +// found in the LICENSE file.
  8899. +
  8900. +#include "user_script_set.h"
  8901. +
  8902. +#include <stddef.h>
  8903. +
  8904. +#include <utility>
  8905. +
  8906. +#include "base/logging.h"
  8907. +#include "base/debug/alias.h"
  8908. +#include "base/memory/ref_counted.h"
  8909. +#include "base/strings/strcat.h"
  8910. +#include "content/public/common/url_constants.h"
  8911. +#include "content/public/renderer/render_frame.h"
  8912. +#include "content/public/renderer/render_thread.h"
  8913. +#include "injection_host.h"
  8914. +#include "script_context.h"
  8915. +#include "script_injection.h"
  8916. +#include "user_script_injector.h"
  8917. +#include "web_ui_injection_host.h"
  8918. +#include "third_party/blink/public/web/web_document.h"
  8919. +#include "third_party/blink/public/web/web_local_frame.h"
  8920. +#include "url/gurl.h"
  8921. +#include "../common/user_scripts_features.h"
  8922. +
  8923. +namespace user_scripts {
  8924. +
  8925. +namespace {
  8926. +
  8927. +// These two strings are injected before and after the Greasemonkey API and
  8928. +// user script to wrap it in an anonymous scope.
  8929. +const char kUserScriptHead[] = "(function (unsafeWindow) {\n";
  8930. +const char kUserScriptTail[] = "\n})(window);";
  8931. +// Maximum number of total content scripts we allow (across all extensions).
  8932. +// The limit exists to diagnose https://crbug.com/723381. The number is
  8933. +// arbitrarily chosen.
  8934. +// TODO(lazyboy): Remove when the bug is fixed.
  8935. +const uint32_t kNumScriptsArbitraryMax = 100000u;
  8936. +
  8937. +GURL GetDocumentUrlForFrame(blink::WebLocalFrame* frame) {
  8938. + GURL data_source_url = ScriptContext::GetDocumentLoaderURLForFrame(frame);
  8939. + if (!data_source_url.is_empty() && frame->IsViewSourceModeEnabled()) {
  8940. + data_source_url = GURL(content::kViewSourceScheme + std::string(":") +
  8941. + data_source_url.spec());
  8942. + }
  8943. +
  8944. + return data_source_url;
  8945. +}
  8946. +
  8947. +} // namespace
  8948. +
  8949. +UserScriptSet::UserScriptSet() {}
  8950. +
  8951. +UserScriptSet::~UserScriptSet() {
  8952. +}
  8953. +
  8954. +void UserScriptSet::AddObserver(Observer* observer) {
  8955. + observers_.AddObserver(observer);
  8956. +}
  8957. +
  8958. +void UserScriptSet::RemoveObserver(Observer* observer) {
  8959. + observers_.RemoveObserver(observer);
  8960. +}
  8961. +
  8962. +void UserScriptSet::GetInjections(
  8963. + std::vector<std::unique_ptr<ScriptInjection>>* injections,
  8964. + content::RenderFrame* render_frame,
  8965. + int tab_id,
  8966. + UserScript::RunLocation run_location,
  8967. + bool log_activity) {
  8968. + GURL document_url = GetDocumentUrlForFrame(render_frame->GetWebFrame());
  8969. + for (const std::unique_ptr<UserScript>& script : scripts_) {
  8970. + std::unique_ptr<ScriptInjection> injection = GetInjectionForScript(
  8971. + script.get(), render_frame, tab_id, run_location, document_url,
  8972. + /* is_declarative, */ log_activity);
  8973. + if (injection.get())
  8974. + injections->push_back(std::move(injection));
  8975. + }
  8976. +}
  8977. +
  8978. +bool UserScriptSet::UpdateUserScripts(
  8979. + base::ReadOnlySharedMemoryRegion shared_memory,
  8980. + const std::set<HostID>& changed_hosts,
  8981. + bool whitelisted_only) {
  8982. + bool only_inject_incognito = false;
  8983. + //ExtensionsRendererClient::Get()->IsIncognitoProcess();
  8984. +
  8985. + // Create the shared memory mapping.
  8986. + shared_memory_mapping_ = shared_memory.Map();
  8987. + if (!shared_memory.IsValid())
  8988. + return false;
  8989. +
  8990. + // First get the size of the memory block.
  8991. + const base::Pickle::Header* pickle_header =
  8992. + shared_memory_mapping_.GetMemoryAs<base::Pickle::Header>();
  8993. + if (!pickle_header)
  8994. + return false;
  8995. +
  8996. + // Now read in the rest of the block.
  8997. + size_t pickle_size =
  8998. + sizeof(base::Pickle::Header) + pickle_header->payload_size;
  8999. +
  9000. + // Unpickle scripts.
  9001. + uint32_t num_scripts = 0;
  9002. + auto memory = shared_memory_mapping_.GetMemoryAsSpan<char>(pickle_size);
  9003. + if (!memory.size())
  9004. + return false;
  9005. +
  9006. + base::Pickle pickle(memory.data(), pickle_size);
  9007. + base::PickleIterator iter(pickle);
  9008. + base::debug::Alias(&pickle_size);
  9009. + CHECK(iter.ReadUInt32(&num_scripts));
  9010. +
  9011. + // Sometimes the shared memory contents seem to be corrupted
  9012. + // (https://crbug.com/723381). Set an arbitrary max limit to the number of
  9013. + // scripts so that we don't add OOM noise to crash reports.
  9014. + CHECK_LT(num_scripts, kNumScriptsArbitraryMax);
  9015. +
  9016. + scripts_.clear();
  9017. + script_sources_.clear();
  9018. + scripts_.reserve(num_scripts);
  9019. + for (uint32_t i = 0; i < num_scripts; ++i) {
  9020. + std::unique_ptr<UserScript> script(new UserScript());
  9021. + script->Unpickle(pickle, &iter);
  9022. +
  9023. + // Note that this is a pointer into shared memory. We don't own it. It gets
  9024. + // cleared up when the last renderer or browser process drops their
  9025. + // reference to the shared memory.
  9026. + for (size_t j = 0; j < script->js_scripts().size(); ++j) {
  9027. + const char* body = NULL;
  9028. + int body_length = 0;
  9029. + CHECK(iter.ReadData(&body, &body_length));
  9030. + script->js_scripts()[j]->set_external_content(
  9031. + base::StringPiece(body, body_length));
  9032. + }
  9033. + for (size_t j = 0; j < script->css_scripts().size(); ++j) {
  9034. + const char* body = NULL;
  9035. + int body_length = 0;
  9036. + CHECK(iter.ReadData(&body, &body_length));
  9037. + script->css_scripts()[j]->set_external_content(
  9038. + base::StringPiece(body, body_length));
  9039. + }
  9040. +
  9041. + if (only_inject_incognito && !script->is_incognito_enabled())
  9042. + continue; // This script shouldn't run in an incognito tab.
  9043. +
  9044. + scripts_.push_back(std::move(script));
  9045. + }
  9046. +
  9047. + for (auto& observer : observers_)
  9048. + observer.OnUserScriptsUpdated(changed_hosts, scripts_);
  9049. + return true;
  9050. +}
  9051. +
  9052. +void UserScriptSet::AddScript(std::unique_ptr<UserScript> script) {
  9053. + scripts_.push_back(std::move(script));
  9054. +}
  9055. +
  9056. +std::unique_ptr<ScriptInjection> UserScriptSet::GetInjectionForScript(
  9057. + const UserScript* script,
  9058. + content::RenderFrame* render_frame,
  9059. + int tab_id,
  9060. + UserScript::RunLocation run_location,
  9061. + const GURL& document_url,
  9062. + //bool is_declarative,
  9063. + bool log_activity) {
  9064. + std::unique_ptr<ScriptInjection> injection;
  9065. + std::unique_ptr<const InjectionHost> injection_host;
  9066. + blink::WebLocalFrame* web_frame = render_frame->GetWebFrame();
  9067. +
  9068. + const HostID& host_id = script->host_id();
  9069. + injection_host.reset(new WebUIInjectionHost(host_id));
  9070. +
  9071. + GURL effective_document_url =
  9072. + ScriptContext::GetEffectiveDocumentURLForInjection(
  9073. + web_frame, document_url, script->match_origin_as_fallback());
  9074. +
  9075. + bool is_subframe = web_frame->Parent();
  9076. + if (!script->MatchesDocument(effective_document_url, is_subframe)) {
  9077. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  9078. + LOG(INFO) << "UserScripts: No Match name=" << script->name() << " " <<
  9079. + "url=" << effective_document_url.spec();
  9080. + return injection;
  9081. + }
  9082. +
  9083. + std::unique_ptr<ScriptInjector> injector(
  9084. + new UserScriptInjector(script, this));
  9085. +
  9086. + bool inject_css = !script->css_scripts().empty() &&
  9087. + run_location == UserScript::DOCUMENT_START;
  9088. + bool inject_js =
  9089. + !script->js_scripts().empty() && script->run_location() == run_location;
  9090. + if (inject_css || inject_js) {
  9091. + injection.reset(new ScriptInjection(std::move(injector), render_frame,
  9092. + std::move(injection_host), run_location,
  9093. + log_activity));
  9094. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  9095. + LOG(INFO) << "UserScripts: Match name=" << script->name() << " " <<
  9096. + "url=" << effective_document_url.spec();
  9097. + } else {
  9098. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts)) {
  9099. + if (script->run_location() != run_location)
  9100. + LOG(INFO) << "UserScripts: wrong run location current " << run_location << " " <<
  9101. + "expeted " << script->run_location();
  9102. + else
  9103. + LOG(INFO) << "UserScripts: Match but no script name=" << script->name() << " " <<
  9104. + "url=" << effective_document_url.spec();
  9105. + }
  9106. + }
  9107. + return injection;
  9108. +}
  9109. +
  9110. +blink::WebString UserScriptSet::GetJsSource(const UserScript::File& file,
  9111. + bool emulate_greasemonkey) {
  9112. + const GURL& url = file.url();
  9113. + auto iter = script_sources_.find(url);
  9114. + if (iter != script_sources_.end()) {
  9115. + // LOG(INFO) << "---UserScriptSet::GetJsSource found " << url;
  9116. + return iter->second;
  9117. + }
  9118. +
  9119. + base::StringPiece script_content = file.GetContent();
  9120. + blink::WebString source;
  9121. + if (emulate_greasemonkey) {
  9122. + // We add this dumb function wrapper for user scripts to emulate what
  9123. + // Greasemonkey does. |script_content| becomes:
  9124. + // concat(kUserScriptHead, script_content, kUserScriptTail).
  9125. + std::string content =
  9126. + base::StrCat({kUserScriptHead, script_content, kUserScriptTail});
  9127. + source = blink::WebString::FromUTF8(content);
  9128. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  9129. + LOG(INFO) << "UserScripts: Injecting w/greasemonkey " << file.url();
  9130. + // LOG(INFO) << "---UserScriptSet::GetJsSource emu " << script_content;
  9131. + } else {
  9132. + source = blink::WebString::FromUTF8(script_content.data(),
  9133. + script_content.length());
  9134. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  9135. + LOG(INFO) << "UserScripts: Injecting " << file.url();
  9136. + }
  9137. + script_sources_[url] = source;
  9138. + return source;
  9139. +}
  9140. +
  9141. +blink::WebString UserScriptSet::GetCssSource(const UserScript::File& file) {
  9142. + const GURL& url = file.url();
  9143. + auto iter = script_sources_.find(url);
  9144. + if (iter != script_sources_.end())
  9145. + return iter->second;
  9146. +
  9147. + base::StringPiece script_content = file.GetContent();
  9148. + return script_sources_
  9149. + .insert(std::make_pair(
  9150. + url, blink::WebString::FromUTF8(script_content.data(),
  9151. + script_content.length())))
  9152. + .first->second;
  9153. +}
  9154. +
  9155. +} // namespace extensions
  9156. diff --git a/components/user_scripts/renderer/user_script_set.h b/components/user_scripts/renderer/user_script_set.h
  9157. new file mode 100755
  9158. --- /dev/null
  9159. +++ b/components/user_scripts/renderer/user_script_set.h
  9160. @@ -0,0 +1,102 @@
  9161. +// Copyright 2014 The Chromium Authors. All rights reserved.
  9162. +// Use of this source code is governed by a BSD-style license that can be
  9163. +// found in the LICENSE file.
  9164. +
  9165. +#ifndef EXTENSIONS_RENDERER_USER_SCRIPT_SET_H_
  9166. +#define EXTENSIONS_RENDERER_USER_SCRIPT_SET_H_
  9167. +
  9168. +#include <map>
  9169. +#include <memory>
  9170. +#include <set>
  9171. +#include <string>
  9172. +#include <vector>
  9173. +
  9174. +#include "base/macros.h"
  9175. +#include "base/memory/read_only_shared_memory_region.h"
  9176. +#include "base/observer_list.h"
  9177. +#include "../common/user_script.h"
  9178. +#include "third_party/blink/public/platform/web_string.h"
  9179. +
  9180. +class GURL;
  9181. +
  9182. +namespace content {
  9183. +class RenderFrame;
  9184. +}
  9185. +
  9186. +namespace user_scripts {
  9187. +class ScriptInjection;
  9188. +
  9189. +// The UserScriptSet is a collection of UserScripts which knows how to update
  9190. +// itself from SharedMemory and create ScriptInjections for UserScripts to
  9191. +// inject on a page.
  9192. +class UserScriptSet {
  9193. + public:
  9194. + class Observer {
  9195. + public:
  9196. + // Called when the set of user scripts is updated. |changed_hosts| contains
  9197. + // the hosts whose scripts have been altered. Note that *all* script objects
  9198. + // are invalidated, even if they aren't in |changed_hosts|.
  9199. + virtual void OnUserScriptsUpdated(const std::set<HostID>& changed_hosts,
  9200. + const UserScriptList& scripts) = 0;
  9201. + };
  9202. +
  9203. + UserScriptSet();
  9204. + ~UserScriptSet();
  9205. +
  9206. + // Adds or removes observers.
  9207. + void AddObserver(Observer* observer);
  9208. + void RemoveObserver(Observer* observer);
  9209. + void AddScript(std::unique_ptr<UserScript> script);
  9210. +
  9211. + // Append any ScriptInjections that should run on the given |render_frame| and
  9212. + // |tab_id|, at the given |run_location|, to |injections|.
  9213. + // |extensions| is passed in to verify the corresponding extension is still
  9214. + // valid.
  9215. + void GetInjections(std::vector<std::unique_ptr<ScriptInjection>>* injections,
  9216. + content::RenderFrame* render_frame,
  9217. + int tab_id,
  9218. + UserScript::RunLocation run_location,
  9219. + bool log_activity);
  9220. +
  9221. + // Updates scripts given the shared memory region containing user scripts.
  9222. + // Returns true if the scripts were successfully updated.
  9223. + bool UpdateUserScripts(base::ReadOnlySharedMemoryRegion shared_memory,
  9224. + const std::set<HostID>& changed_hosts,
  9225. + bool whitelisted_only);
  9226. +
  9227. + // Returns the contents of a script file.
  9228. + // Note that copying is cheap as this uses WebString.
  9229. + blink::WebString GetJsSource(const UserScript::File& file,
  9230. + bool emulate_greasemonkey);
  9231. + blink::WebString GetCssSource(const UserScript::File& file);
  9232. +
  9233. + private:
  9234. + // Returns a new ScriptInjection for the given |script| to execute in the
  9235. + // |render_frame|, or NULL if the script should not execute.
  9236. + std::unique_ptr<ScriptInjection> GetInjectionForScript(
  9237. + const UserScript* script,
  9238. + content::RenderFrame* render_frame,
  9239. + int tab_id,
  9240. + UserScript::RunLocation run_location,
  9241. + const GURL& document_url,
  9242. + //bool is_declarative,
  9243. + bool log_activity);
  9244. +
  9245. + // Shared memory mapping containing raw script data.
  9246. + base::ReadOnlySharedMemoryMapping shared_memory_mapping_;
  9247. +
  9248. + // The UserScripts this injector manages.
  9249. + UserScriptList scripts_;
  9250. +
  9251. + // Map of user script file url -> source.
  9252. + std::map<GURL, blink::WebString> script_sources_;
  9253. +
  9254. + // The associated observers.
  9255. + base::ObserverList<Observer>::Unchecked observers_;
  9256. +
  9257. + DISALLOW_COPY_AND_ASSIGN(UserScriptSet);
  9258. +};
  9259. +
  9260. +} // namespace extensions
  9261. +
  9262. +#endif // EXTENSIONS_RENDERER_USER_SCRIPT_SET_H_
  9263. diff --git a/components/user_scripts/renderer/user_script_set_manager.cc b/components/user_scripts/renderer/user_script_set_manager.cc
  9264. new file mode 100755
  9265. --- /dev/null
  9266. +++ b/components/user_scripts/renderer/user_script_set_manager.cc
  9267. @@ -0,0 +1,77 @@
  9268. +#include "user_script_set_manager.h"
  9269. +
  9270. +#include "base/logging.h"
  9271. +#include "content/public/renderer/render_thread.h"
  9272. +#include "../common/host_id.h"
  9273. +#include "../common/extension_messages.h"
  9274. +#include "../common/user_scripts_features.h"
  9275. +#include "user_script_set.h"
  9276. +
  9277. +namespace user_scripts {
  9278. +
  9279. +UserScriptSetManager::UserScriptSetManager() {
  9280. + content::RenderThread::Get()->AddObserver(this);
  9281. +}
  9282. +
  9283. +UserScriptSetManager::~UserScriptSetManager() {
  9284. +}
  9285. +
  9286. +void UserScriptSetManager::AddObserver(Observer* observer) {
  9287. + observers_.AddObserver(observer);
  9288. +}
  9289. +
  9290. +void UserScriptSetManager::RemoveObserver(Observer* observer) {
  9291. + observers_.RemoveObserver(observer);
  9292. +}
  9293. +
  9294. +bool UserScriptSetManager::OnControlMessageReceived(
  9295. + const IPC::Message& message) {
  9296. + bool handled = true;
  9297. + IPC_BEGIN_MESSAGE_MAP(UserScriptSetManager, message)
  9298. + IPC_MESSAGE_HANDLER(ExtensionMsg_UpdateUserScripts, OnUpdateUserScripts)
  9299. + IPC_MESSAGE_UNHANDLED(handled = false)
  9300. + IPC_END_MESSAGE_MAP()
  9301. + return handled;
  9302. +}
  9303. +
  9304. +void UserScriptSetManager::GetAllInjections(
  9305. + std::vector<std::unique_ptr<ScriptInjection>>* injections,
  9306. + content::RenderFrame* render_frame,
  9307. + int tab_id,
  9308. + UserScript::RunLocation run_location) {
  9309. +
  9310. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  9311. + LOG(INFO) << "UserScripts: GetAllInjections";
  9312. +
  9313. + // static_scripts_ is UserScriptSet
  9314. + static_scripts_.GetInjections(injections, render_frame, tab_id, run_location,
  9315. + activity_logging_enabled_);
  9316. +}
  9317. +
  9318. +void UserScriptSetManager::OnUpdateUserScripts(
  9319. + base::ReadOnlySharedMemoryRegion shared_memory) {
  9320. + if (!shared_memory.IsValid()) {
  9321. + NOTREACHED() << "Bad scripts handle";
  9322. + return;
  9323. + }
  9324. +
  9325. + UserScriptSet* scripts = NULL;
  9326. + scripts = &static_scripts_;
  9327. +
  9328. + DCHECK(scripts);
  9329. +
  9330. + // If no hosts are included in the set, that indicates that all
  9331. + // hosts were updated. Add them all to the set so that observers and
  9332. + // individual UserScriptSets don't need to know this detail.
  9333. + //const std::set<HostID>* effective_hosts = &changed_hosts;
  9334. + std::set<HostID> all_hosts;
  9335. + const std::set<HostID>* effective_hosts = &all_hosts;
  9336. +
  9337. + if (scripts->UpdateUserScripts(std::move(shared_memory), *effective_hosts,
  9338. + false /*whitelisted_only*/)) {
  9339. + for (auto& observer : observers_)
  9340. + observer.OnUserScriptsUpdated(all_hosts /* *effective_hosts*/);
  9341. + }
  9342. +}
  9343. +
  9344. +}
  9345. \ No newline at end of file
  9346. diff --git a/components/user_scripts/renderer/user_script_set_manager.h b/components/user_scripts/renderer/user_script_set_manager.h
  9347. new file mode 100755
  9348. --- /dev/null
  9349. +++ b/components/user_scripts/renderer/user_script_set_manager.h
  9350. @@ -0,0 +1,62 @@
  9351. +#ifndef COMPONENTS_USER_SCRIPTS_RENDER_SET_MANAGER_H_
  9352. +#define COMPONENTS_USER_SCRIPTS_RENDER_SET_MANAGER_H_
  9353. +
  9354. +#include <map>
  9355. +#include <set>
  9356. +#include <string>
  9357. +#include <vector>
  9358. +
  9359. +#include "base/macros.h"
  9360. +#include "base/memory/read_only_shared_memory_region.h"
  9361. +#include "base/observer_list.h"
  9362. +#include "content/public/renderer/render_thread_observer.h"
  9363. +#include "../common/host_id.h"
  9364. +#include "user_script_set.h"
  9365. +#include "script_injection.h"
  9366. +
  9367. +namespace user_scripts {
  9368. +
  9369. +class UserScriptSetManager : public content::RenderThreadObserver {
  9370. + public:
  9371. + class Observer {
  9372. + public:
  9373. + virtual void OnUserScriptsUpdated(const std::set<HostID>& changed_hosts) = 0;
  9374. + };
  9375. +
  9376. + UserScriptSetManager();
  9377. +
  9378. + ~UserScriptSetManager() override;
  9379. +
  9380. + void AddObserver(Observer* observer);
  9381. + void RemoveObserver(Observer* observer);
  9382. +
  9383. + // Append all injections from |static_scripts| and each of
  9384. + // |programmatic_scripts_| to |injections|.
  9385. + void GetAllInjections(
  9386. + std::vector<std::unique_ptr<ScriptInjection>>* injections,
  9387. + content::RenderFrame* render_frame,
  9388. + int tab_id,
  9389. + UserScript::RunLocation run_location);
  9390. +
  9391. +private:
  9392. + // content::RenderThreadObserver implementation.
  9393. + bool OnControlMessageReceived(const IPC::Message& message) override;
  9394. +
  9395. + base::ObserverList<Observer>::Unchecked observers_;
  9396. +
  9397. + // Handle the UpdateUserScripts extension message.
  9398. + void OnUpdateUserScripts(base::ReadOnlySharedMemoryRegion shared_memory);
  9399. + //, const HostID& host_id,
  9400. + //const std::set<HostID>& changed_hosts,
  9401. + //bool whitelisted_only);
  9402. +
  9403. + // Scripts statically defined in extension manifests.
  9404. + UserScriptSet static_scripts_;
  9405. +
  9406. + // Whether or not dom activity should be logged for scripts injected.
  9407. + bool activity_logging_enabled_ = false;
  9408. +};
  9409. +
  9410. +}
  9411. +
  9412. +#endif
  9413. \ No newline at end of file
  9414. diff --git a/components/user_scripts/renderer/user_scripts_dispatcher.cc b/components/user_scripts/renderer/user_scripts_dispatcher.cc
  9415. new file mode 100755
  9416. --- /dev/null
  9417. +++ b/components/user_scripts/renderer/user_scripts_dispatcher.cc
  9418. @@ -0,0 +1,36 @@
  9419. +#include "user_scripts_dispatcher.h"
  9420. +
  9421. +#include <stddef.h>
  9422. +
  9423. +#include <algorithm>
  9424. +#include <memory>
  9425. +#include <utility>
  9426. +
  9427. +#include "content/public/renderer/render_thread.h"
  9428. +#include "extension_frame_helper.h"
  9429. +
  9430. +namespace user_scripts {
  9431. +
  9432. +// ex ChromeExtensionsDispatcherDelegate
  9433. +UserScriptsDispatcher::UserScriptsDispatcher()
  9434. + : user_script_set_manager_observer_(this) {
  9435. + user_script_set_manager_.reset(new UserScriptSetManager());
  9436. + script_injection_manager_.reset(
  9437. + new ScriptInjectionManager(user_script_set_manager_.get()));
  9438. + user_script_set_manager_observer_.Add(user_script_set_manager_.get());
  9439. +}
  9440. +
  9441. +UserScriptsDispatcher::~UserScriptsDispatcher() {
  9442. +}
  9443. +
  9444. +void UserScriptsDispatcher::OnRenderThreadStarted(content::RenderThread* thread) {
  9445. +}
  9446. +
  9447. +void UserScriptsDispatcher::OnUserScriptsUpdated(const std::set<HostID>& changed_hosts) {
  9448. +}
  9449. +
  9450. +void UserScriptsDispatcher::OnRenderFrameCreated(content::RenderFrame* render_frame) {
  9451. + script_injection_manager_->OnRenderFrameCreated(render_frame);
  9452. +}
  9453. +
  9454. +}
  9455. \ No newline at end of file
  9456. diff --git a/components/user_scripts/renderer/user_scripts_dispatcher.h b/components/user_scripts/renderer/user_scripts_dispatcher.h
  9457. new file mode 100755
  9458. --- /dev/null
  9459. +++ b/components/user_scripts/renderer/user_scripts_dispatcher.h
  9460. @@ -0,0 +1,48 @@
  9461. +#ifndef COMPONENTS_USER_SCRIPTS_RENDER_DISPATCHER_H_
  9462. +#define COMPONENTS_USER_SCRIPTS_RENDER_DISPATCHER_H_
  9463. +
  9464. +#include "user_script_set_manager.h"
  9465. +#include "script_injection_manager.h"
  9466. +
  9467. +#include <stdint.h>
  9468. +
  9469. +#include <map>
  9470. +#include <memory>
  9471. +#include <set>
  9472. +#include <string>
  9473. +#include <utility>
  9474. +#include <vector>
  9475. +
  9476. +#include "base/macros.h"
  9477. +#include "base/scoped_observer.h"
  9478. +#include "content/public/renderer/render_thread_observer.h"
  9479. +#include "content/public/renderer/render_thread.h"
  9480. +#include "../common/host_id.h"
  9481. +#include "user_script_set_manager.h"
  9482. +#include "script_injection.h"
  9483. +
  9484. +namespace user_scripts {
  9485. +
  9486. +class UserScriptsDispatcher : public content::RenderThreadObserver,
  9487. + public UserScriptSetManager::Observer {
  9488. +
  9489. + public:
  9490. + explicit UserScriptsDispatcher();
  9491. + ~UserScriptsDispatcher() override;
  9492. +
  9493. + void OnRenderThreadStarted(content::RenderThread* thread);
  9494. + void OnUserScriptsUpdated(const std::set<HostID>& changed_hosts) override;
  9495. + void OnRenderFrameCreated(content::RenderFrame* render_frame);
  9496. +
  9497. + private:
  9498. + std::unique_ptr<UserScriptSetManager> user_script_set_manager_;
  9499. +
  9500. + std::unique_ptr<ScriptInjectionManager> script_injection_manager_;
  9501. +
  9502. + ScopedObserver<UserScriptSetManager, UserScriptSetManager::Observer>
  9503. + user_script_set_manager_observer_;
  9504. +};
  9505. +
  9506. +}
  9507. +
  9508. +#endif
  9509. \ No newline at end of file
  9510. diff --git a/components/user_scripts/renderer/user_scripts_renderer_client.cc b/components/user_scripts/renderer/user_scripts_renderer_client.cc
  9511. new file mode 100755
  9512. --- /dev/null
  9513. +++ b/components/user_scripts/renderer/user_scripts_renderer_client.cc
  9514. @@ -0,0 +1,76 @@
  9515. +#include "user_scripts_renderer_client.h"
  9516. +
  9517. +#include <memory>
  9518. +#include <utility>
  9519. +
  9520. +#include "base/logging.h"
  9521. +#include "base/lazy_instance.h"
  9522. +#include "content/public/renderer/render_thread.h"
  9523. +
  9524. +#include "../common/user_scripts_features.h"
  9525. +#include "user_scripts_dispatcher.h"
  9526. +#include "extension_frame_helper.h"
  9527. +
  9528. +namespace user_scripts {
  9529. +
  9530. +// was ChromeExtensionsRendererClient
  9531. +UserScriptsRendererClient::UserScriptsRendererClient() {}
  9532. +
  9533. +UserScriptsRendererClient::~UserScriptsRendererClient() {}
  9534. +
  9535. +// static
  9536. +UserScriptsRendererClient* UserScriptsRendererClient::GetInstance() {
  9537. + if (base::FeatureList::IsEnabled(features::kEnableUserScripts) == false)
  9538. + return NULL;
  9539. +
  9540. + static base::LazyInstance<UserScriptsRendererClient>::Leaky client =
  9541. + LAZY_INSTANCE_INITIALIZER;
  9542. + return client.Pointer();
  9543. +}
  9544. +
  9545. +void UserScriptsRendererClient::RenderThreadStarted() {
  9546. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  9547. + LOG(INFO) << "UserScripts: RenderThreadStarted";
  9548. + content::RenderThread* thread = content::RenderThread::Get();
  9549. +
  9550. + dispatcher_ = std::make_unique<UserScriptsDispatcher>();
  9551. +
  9552. + dispatcher_->OnRenderThreadStarted(thread);
  9553. + thread->AddObserver(dispatcher_.get());
  9554. +}
  9555. +
  9556. +void UserScriptsRendererClient::RenderFrameCreated(
  9557. + content::RenderFrame* render_frame,
  9558. + service_manager::BinderRegistry* registry) {
  9559. + new user_scripts::ExtensionFrameHelper(render_frame);
  9560. + dispatcher_->OnRenderFrameCreated(render_frame);
  9561. +}
  9562. +
  9563. +void UserScriptsRendererClient::RunScriptsAtDocumentStart(content::RenderFrame* render_frame) {
  9564. + ExtensionFrameHelper* frame_helper = ExtensionFrameHelper::Get(render_frame);
  9565. + if (!frame_helper)
  9566. + return; // The frame is invisible to extensions.
  9567. +
  9568. + frame_helper->RunScriptsAtDocumentStart();
  9569. + // |frame_helper| and |render_frame| might be dead by now.
  9570. +}
  9571. +
  9572. +void UserScriptsRendererClient::RunScriptsAtDocumentEnd(content::RenderFrame* render_frame) {
  9573. + ExtensionFrameHelper* frame_helper = ExtensionFrameHelper::Get(render_frame);
  9574. + if (!frame_helper)
  9575. + return; // The frame is invisible to extensions.
  9576. +
  9577. + frame_helper->RunScriptsAtDocumentEnd();
  9578. + // |frame_helper| and |render_frame| might be dead by now.
  9579. +}
  9580. +
  9581. +void UserScriptsRendererClient::RunScriptsAtDocumentIdle(content::RenderFrame* render_frame) {
  9582. + ExtensionFrameHelper* frame_helper = ExtensionFrameHelper::Get(render_frame);
  9583. + if (!frame_helper)
  9584. + return; // The frame is invisible to extensions.
  9585. +
  9586. + frame_helper->RunScriptsAtDocumentIdle();
  9587. + // |frame_helper| and |render_frame| might be dead by now.
  9588. +}
  9589. +
  9590. +}
  9591. \ No newline at end of file
  9592. diff --git a/components/user_scripts/renderer/user_scripts_renderer_client.h b/components/user_scripts/renderer/user_scripts_renderer_client.h
  9593. new file mode 100755
  9594. --- /dev/null
  9595. +++ b/components/user_scripts/renderer/user_scripts_renderer_client.h
  9596. @@ -0,0 +1,33 @@
  9597. +#ifndef COMPONENTS_USER_SCRIPTS_RENDER_CLIENT_H_
  9598. +#define COMPONENTS_USER_SCRIPTS_RENDER_CLIENT_H_
  9599. +
  9600. +#include <memory>
  9601. +#include <string>
  9602. +
  9603. +#include "base/macros.h"
  9604. +#include "user_scripts_dispatcher.h"
  9605. +#include "services/service_manager/public/cpp/binder_registry.h"
  9606. +
  9607. +namespace user_scripts {
  9608. +
  9609. +class UserScriptsRendererClient {
  9610. + public:
  9611. + UserScriptsRendererClient();
  9612. + ~UserScriptsRendererClient();
  9613. +
  9614. + static UserScriptsRendererClient* GetInstance();
  9615. +
  9616. + void RenderThreadStarted();
  9617. + void RenderFrameCreated(content::RenderFrame* render_frame,
  9618. + service_manager::BinderRegistry* registry);
  9619. + void RunScriptsAtDocumentStart(content::RenderFrame* render_frame);
  9620. + void RunScriptsAtDocumentEnd(content::RenderFrame* render_frame);
  9621. + void RunScriptsAtDocumentIdle(content::RenderFrame* render_frame);
  9622. +
  9623. + private:
  9624. + std::unique_ptr<UserScriptsDispatcher> dispatcher_;
  9625. +};
  9626. +
  9627. +}
  9628. +
  9629. +#endif
  9630. \ No newline at end of file
  9631. diff --git a/components/user_scripts/renderer/web_ui_injection_host.cc b/components/user_scripts/renderer/web_ui_injection_host.cc
  9632. new file mode 100755
  9633. --- /dev/null
  9634. +++ b/components/user_scripts/renderer/web_ui_injection_host.cc
  9635. @@ -0,0 +1,40 @@
  9636. +// Copyright 2015 The Chromium Authors. All rights reserved.
  9637. +// Use of this source code is governed by a BSD-style license that can be
  9638. +// found in the LICENSE file.
  9639. +
  9640. +#include "web_ui_injection_host.h"
  9641. +#include "base/no_destructor.h"
  9642. +
  9643. +namespace {
  9644. +
  9645. +// The default secure CSP to be used in order to prevent remote scripts.
  9646. +const char kDefaultSecureCSP[] = "script-src 'self'; object-src 'self';";
  9647. +
  9648. +}
  9649. +
  9650. +WebUIInjectionHost::WebUIInjectionHost(const HostID& host_id)
  9651. + : InjectionHost(host_id),
  9652. + url_(host_id.id()) {
  9653. +}
  9654. +
  9655. +WebUIInjectionHost::~WebUIInjectionHost() {
  9656. +}
  9657. +
  9658. +const std::string* WebUIInjectionHost::GetContentSecurityPolicy() const {
  9659. + // Use the main world CSP.
  9660. + // return nullptr;
  9661. +
  9662. + // The isolated world will use its own CSP which blocks remotely hosted
  9663. + // code.
  9664. + static const base::NoDestructor<std::string> default_isolated_world_csp(
  9665. + kDefaultSecureCSP);
  9666. + return default_isolated_world_csp.get();
  9667. +}
  9668. +
  9669. +const GURL& WebUIInjectionHost::url() const {
  9670. + return url_;
  9671. +}
  9672. +
  9673. +const std::string& WebUIInjectionHost::name() const {
  9674. + return id().id();
  9675. +}
  9676. diff --git a/components/user_scripts/renderer/web_ui_injection_host.h b/components/user_scripts/renderer/web_ui_injection_host.h
  9677. new file mode 100755
  9678. --- /dev/null
  9679. +++ b/components/user_scripts/renderer/web_ui_injection_host.h
  9680. @@ -0,0 +1,28 @@
  9681. +// Copyright 2015 The Chromium Authors. All rights reserved.
  9682. +// Use of this source code is governed by a BSD-style license that can be
  9683. +// found in the LICENSE file.
  9684. +
  9685. +#ifndef EXTENSIONS_RENDERER_WEB_UI_INJECTION_HOST_H_
  9686. +#define EXTENSIONS_RENDERER_WEB_UI_INJECTION_HOST_H_
  9687. +
  9688. +#include "base/macros.h"
  9689. +#include "injection_host.h"
  9690. +
  9691. +class WebUIInjectionHost : public InjectionHost {
  9692. + public:
  9693. + WebUIInjectionHost(const HostID& host_id);
  9694. + ~WebUIInjectionHost() override;
  9695. +
  9696. + private:
  9697. + // InjectionHost:
  9698. + const std::string* GetContentSecurityPolicy() const override;
  9699. + const GURL& url() const override;
  9700. + const std::string& name() const override;
  9701. +
  9702. + private:
  9703. + GURL url_;
  9704. +
  9705. + DISALLOW_COPY_AND_ASSIGN(WebUIInjectionHost);
  9706. +};
  9707. +
  9708. +#endif // EXTENSIONS_RENDERER_WEB_UI_INJECTION_HOST_H_
  9709. diff --git a/components/user_scripts/strings/userscripts_strings.grdp b/components/user_scripts/strings/userscripts_strings.grdp
  9710. new file mode 100755
  9711. --- /dev/null
  9712. +++ b/components/user_scripts/strings/userscripts_strings.grdp
  9713. @@ -0,0 +1,50 @@
  9714. +<?xml version="1.0" encoding="utf-8"?>
  9715. +<grit-part>
  9716. +
  9717. + <!-- Preferences -->
  9718. + <message name="IDS_PREFS_USERSCRIPTS_SETTINGS"
  9719. + desc="Title of the dialog that presents a request for payment for some good or service. Sentence-cased."
  9720. + formatter_data="android_java">
  9721. + User Scripts
  9722. + </message>
  9723. +
  9724. + <message name="IDS_OPTION_USERSCRIPT_FLAG" desc="." formatter_data="android_java">
  9725. + Activate User Scripts
  9726. + </message>
  9727. +
  9728. + <message name="IDS_SCRIPTS_DISABLED_DESCRIPTION" desc="." formatter_data="android_java">
  9729. + Experimental support for userscripts are currently disabled. You can enable them by going to chrome://flags.
  9730. + </message>
  9731. +
  9732. + <message name="IDS_OPTION_USERSCRIPT_FLAG_ON" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  9733. + ON
  9734. + </message>
  9735. + <message name="IDS_OPTION_USERSCRIPT_FLAG_OFF" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  9736. + OFF
  9737. + </message>
  9738. +
  9739. + <message name="IDS_ADD_SCRIPT" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  9740. + Add script
  9741. + </message>
  9742. + <message name="IDS_SCRIPTS_LIST_DESCRIPTION" desc="." formatter_data="android_java">
  9743. + Experimental support for Greasemonkey-style user scripts. Use at your own risk.
  9744. + </message>
  9745. +
  9746. + <message name="IDS_SCRIPTS_MENU_ENABLE" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  9747. + Enable
  9748. + </message>
  9749. + <message name="IDS_SCRIPTS_MENU_DISABLE" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  9750. + Disable
  9751. + </message>
  9752. +
  9753. + <message name="IDS_ASK_TO_INSTALL" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  9754. + Do you want to install
  9755. + </message>
  9756. + <message name="IDS_YES" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  9757. + Yes
  9758. + </message>
  9759. + <message name="IDS_NO" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  9760. + No
  9761. + </message>
  9762. +
  9763. +</grit-part>
  9764. \ No newline at end of file
  9765. diff --git a/tools/gritsettings/resource_ids.spec b/tools/gritsettings/resource_ids.spec
  9766. --- a/tools/gritsettings/resource_ids.spec
  9767. +++ b/tools/gritsettings/resource_ids.spec
  9768. @@ -426,6 +426,9 @@
  9769. "components/autofill/core/browser/autofill_address_rewriter_resources.grd":{
  9770. "includes": [2880]
  9771. },
  9772. + "components/user_scripts/renderer/resources/user_scripts_renderer_resources.grd": {
  9773. + "includes": [3000],
  9774. + },
  9775. # END components/ section.
  9776. # START ios/ section.
  9777. diff --git a/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java b/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java
  9778. --- a/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java
  9779. +++ b/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java
  9780. @@ -749,7 +749,8 @@ public class SelectFileDialog implements WindowAndroid.IntentCallback, PhotoPick
  9781. }
  9782. private int countAcceptTypesFor(String superType) {
  9783. - assert superType.indexOf('/') == -1;
  9784. + //assert removed from upstream
  9785. + //assert superType.indexOf('/') == -1;
  9786. int count = 0;
  9787. for (String type : mFileTypes) {
  9788. if (type.startsWith(superType)) {
  9789. --
  9790. 2.17.1