experimental-user-scripts-support.patch 368 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186
  1. From: uazo <uazo@users.noreply.github.com>
  2. Date: Sat, 20 Mar 2021 09:37:12 +0000
  3. Subject: Experimental user scripts support preview
  4. needs
  5. add-support-for-ISupportHelpAndFeedback.patch
  6. add-support-for-prefs-addon.patch
  7. ---
  8. chrome/android/BUILD.gn | 4 +
  9. .../chrome/browser/AfterStartupTaskUtils.java | 2 +
  10. .../browser/download/DownloadUtils.java | 6 +
  11. chrome/android/java_sources.gni | 3 +
  12. chrome/browser/BUILD.gn | 5 +
  13. chrome/browser/about_flags.cc | 9 +
  14. chrome/browser/flag_descriptions.cc | 10 +
  15. chrome/browser/flag_descriptions.h | 5 +
  16. chrome/browser/prefs/browser_prefs.cc | 2 +
  17. ...hrome_browser_main_extra_parts_profiles.cc | 3 +
  18. chrome/browser/profiles/profile_manager.cc | 9 +
  19. .../webui/chrome_web_ui_controller_factory.cc | 3 +
  20. chrome/chrome_paks.gni | 2 +
  21. chrome/renderer/BUILD.gn | 1 +
  22. .../chrome_content_renderer_client.cc | 33 +
  23. components/components_strings.grd | 1 +
  24. components/user_scripts/android/BUILD.gn | 82 ++
  25. .../java/res/layout/accept_script_item.xml | 74 ++
  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 | 78 ++
  32. .../user_scripts/FragmentWindowAndroid.java | 68 ++
  33. .../user_scripts/IUserScriptsUtils.java | 22 +
  34. .../components/user_scripts/ScriptInfo.java | 33 +
  35. .../user_scripts/ScriptListBaseAdapter.java | 194 +++++
  36. .../user_scripts/ScriptListPreference.java | 169 ++++
  37. .../user_scripts/UserScriptsBridge.java | 178 ++++
  38. .../user_scripts/UserScriptsPreferences.java | 144 ++++
  39. .../user_scripts/android/java_sources.gni | 18 +
  40. .../android/user_scripts_bridge.cc | 179 ++++
  41. .../android/user_scripts_bridge.h | 31 +
  42. components/user_scripts/browser/BUILD.gn | 91 ++
  43. .../user_scripts/browser/file_task_runner.cc | 40 +
  44. .../user_scripts/browser/file_task_runner.h | 34 +
  45. .../browser/resources/browser_resources.grd | 14 +
  46. .../browser/resources/user-script-ui/BUILD.gn | 12 +
  47. .../user-script-ui/user-scripts-ui.html | 14 +
  48. .../user-script-ui/user-scripts-ui.js | 9 +
  49. .../browser/ui/user_scripts_ui.cc | 150 ++++
  50. .../user_scripts/browser/ui/user_scripts_ui.h | 39 +
  51. .../browser/user_script_loader.cc | 657 ++++++++++++++
  52. .../user_scripts/browser/user_script_loader.h | 172 ++++
  53. .../browser/user_script_pref_info.cc | 34 +
  54. .../browser/user_script_pref_info.h | 66 ++
  55. .../user_scripts/browser/user_script_prefs.cc | 262 ++++++
  56. .../user_scripts/browser/user_script_prefs.h | 58 ++
  57. .../browser/userscripts_browser_client.cc | 79 ++
  58. .../browser/userscripts_browser_client.h | 62 ++
  59. components/user_scripts/common/BUILD.gn | 52 ++
  60. components/user_scripts/common/constants.h | 21 +
  61. components/user_scripts/common/error_utils.cc | 54 ++
  62. components/user_scripts/common/error_utils.h | 25 +
  63. .../common/extension_message_generator.cc | 29 +
  64. .../common/extension_message_generator.h | 11 +
  65. .../user_scripts/common/extension_messages.cc | 40 +
  66. .../user_scripts/common/extension_messages.h | 70 ++
  67. components/user_scripts/common/host_id.cc | 31 +
  68. components/user_scripts/common/host_id.h | 35 +
  69. .../user_scripts/common/script_constants.h | 33 +
  70. components/user_scripts/common/url_pattern.cc | 807 ++++++++++++++++++
  71. components/user_scripts/common/url_pattern.h | 301 +++++++
  72. .../user_scripts/common/url_pattern_set.cc | 330 +++++++
  73. .../user_scripts/common/url_pattern_set.h | 161 ++++
  74. components/user_scripts/common/user_script.cc | 317 +++++++
  75. components/user_scripts/common/user_script.h | 387 +++++++++
  76. .../common/user_scripts_features.cc | 34 +
  77. .../common/user_scripts_features.h | 35 +
  78. components/user_scripts/common/view_type.cc | 39 +
  79. components/user_scripts/common/view_type.h | 48 ++
  80. components/user_scripts/renderer/BUILD.gn | 67 ++
  81. .../renderer/extension_frame_helper.cc | 96 +++
  82. .../renderer/extension_frame_helper.h | 92 ++
  83. .../user_scripts/renderer/injection_host.cc | 12 +
  84. .../user_scripts/renderer/injection_host.h | 42 +
  85. .../renderer/resources/greasemonkey_api.js | 82 ++
  86. .../user_scripts_renderer_resources.grd | 14 +
  87. .../user_scripts/renderer/script_context.cc | 213 +++++
  88. .../user_scripts/renderer/script_context.h | 70 ++
  89. .../user_scripts/renderer/script_injection.cc | 342 ++++++++
  90. .../user_scripts/renderer/script_injection.h | 156 ++++
  91. .../renderer/script_injection_callback.cc | 26 +
  92. .../renderer/script_injection_callback.h | 38 +
  93. .../renderer/script_injection_manager.cc | 417 +++++++++
  94. .../renderer/script_injection_manager.h | 102 +++
  95. .../user_scripts/renderer/script_injector.h | 96 +++
  96. .../user_scripts/renderer/scripts_run_info.cc | 31 +
  97. .../user_scripts/renderer/scripts_run_info.h | 70 ++
  98. .../renderer/user_script_injector.cc | 228 +++++
  99. .../renderer/user_script_injector.h | 86 ++
  100. .../user_scripts/renderer/user_script_set.cc | 258 ++++++
  101. .../user_scripts/renderer/user_script_set.h | 102 +++
  102. .../renderer/user_script_set_manager.cc | 77 ++
  103. .../renderer/user_script_set_manager.h | 62 ++
  104. .../renderer/user_scripts_dispatcher.cc | 36 +
  105. .../renderer/user_scripts_dispatcher.h | 48 ++
  106. .../renderer/user_scripts_renderer_client.cc | 76 ++
  107. .../renderer/user_scripts_renderer_client.h | 33 +
  108. .../renderer/web_ui_injection_host.cc | 40 +
  109. .../renderer/web_ui_injection_host.h | 28 +
  110. .../strings/userscripts_strings.grdp | 50 ++
  111. tools/gritsettings/resource_ids.spec | 6 +
  112. 104 files changed, 9247 insertions(+)
  113. create mode 100755 components/user_scripts/android/BUILD.gn
  114. create mode 100644 components/user_scripts/android/java/res/layout/accept_script_item.xml
  115. create mode 100644 components/user_scripts/android/java/res/layout/accept_script_list.xml
  116. create mode 100644 components/user_scripts/android/java/res/layout/scripts_preference.xml
  117. create mode 100755 components/user_scripts/android/java/res/values/dimens.xml
  118. create mode 100755 components/user_scripts/android/java/res/xml/main_preferences_addon_userscripts.xml
  119. create mode 100644 components/user_scripts/android/java/res/xml/userscripts_preferences.xml
  120. create mode 100755 components/user_scripts/android/java/src/org/chromium/chrome/browser/user_scripts/UserScriptsUtils.java
  121. create mode 100644 components/user_scripts/android/java/src/org/chromium/components/user_scripts/FragmentWindowAndroid.java
  122. create mode 100644 components/user_scripts/android/java/src/org/chromium/components/user_scripts/IUserScriptsUtils.java
  123. create mode 100644 components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptInfo.java
  124. create mode 100644 components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptListBaseAdapter.java
  125. create mode 100644 components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptListPreference.java
  126. create mode 100644 components/user_scripts/android/java/src/org/chromium/components/user_scripts/UserScriptsBridge.java
  127. create mode 100755 components/user_scripts/android/java/src/org/chromium/components/user_scripts/UserScriptsPreferences.java
  128. create mode 100644 components/user_scripts/android/java_sources.gni
  129. create mode 100644 components/user_scripts/android/user_scripts_bridge.cc
  130. create mode 100644 components/user_scripts/android/user_scripts_bridge.h
  131. create mode 100755 components/user_scripts/browser/BUILD.gn
  132. create mode 100755 components/user_scripts/browser/file_task_runner.cc
  133. create mode 100755 components/user_scripts/browser/file_task_runner.h
  134. create mode 100644 components/user_scripts/browser/resources/browser_resources.grd
  135. create mode 100644 components/user_scripts/browser/resources/user-script-ui/BUILD.gn
  136. create mode 100644 components/user_scripts/browser/resources/user-script-ui/user-scripts-ui.html
  137. create mode 100644 components/user_scripts/browser/resources/user-script-ui/user-scripts-ui.js
  138. create mode 100644 components/user_scripts/browser/ui/user_scripts_ui.cc
  139. create mode 100644 components/user_scripts/browser/ui/user_scripts_ui.h
  140. create mode 100755 components/user_scripts/browser/user_script_loader.cc
  141. create mode 100755 components/user_scripts/browser/user_script_loader.h
  142. create mode 100644 components/user_scripts/browser/user_script_pref_info.cc
  143. create mode 100644 components/user_scripts/browser/user_script_pref_info.h
  144. create mode 100644 components/user_scripts/browser/user_script_prefs.cc
  145. create mode 100644 components/user_scripts/browser/user_script_prefs.h
  146. create mode 100755 components/user_scripts/browser/userscripts_browser_client.cc
  147. create mode 100755 components/user_scripts/browser/userscripts_browser_client.h
  148. create mode 100755 components/user_scripts/common/BUILD.gn
  149. create mode 100755 components/user_scripts/common/constants.h
  150. create mode 100755 components/user_scripts/common/error_utils.cc
  151. create mode 100755 components/user_scripts/common/error_utils.h
  152. create mode 100755 components/user_scripts/common/extension_message_generator.cc
  153. create mode 100755 components/user_scripts/common/extension_message_generator.h
  154. create mode 100755 components/user_scripts/common/extension_messages.cc
  155. create mode 100755 components/user_scripts/common/extension_messages.h
  156. create mode 100755 components/user_scripts/common/host_id.cc
  157. create mode 100755 components/user_scripts/common/host_id.h
  158. create mode 100755 components/user_scripts/common/script_constants.h
  159. create mode 100755 components/user_scripts/common/url_pattern.cc
  160. create mode 100755 components/user_scripts/common/url_pattern.h
  161. create mode 100755 components/user_scripts/common/url_pattern_set.cc
  162. create mode 100755 components/user_scripts/common/url_pattern_set.h
  163. create mode 100755 components/user_scripts/common/user_script.cc
  164. create mode 100755 components/user_scripts/common/user_script.h
  165. create mode 100644 components/user_scripts/common/user_scripts_features.cc
  166. create mode 100644 components/user_scripts/common/user_scripts_features.h
  167. create mode 100755 components/user_scripts/common/view_type.cc
  168. create mode 100755 components/user_scripts/common/view_type.h
  169. create mode 100755 components/user_scripts/renderer/BUILD.gn
  170. create mode 100755 components/user_scripts/renderer/extension_frame_helper.cc
  171. create mode 100755 components/user_scripts/renderer/extension_frame_helper.h
  172. create mode 100755 components/user_scripts/renderer/injection_host.cc
  173. create mode 100755 components/user_scripts/renderer/injection_host.h
  174. create mode 100755 components/user_scripts/renderer/resources/greasemonkey_api.js
  175. create mode 100755 components/user_scripts/renderer/resources/user_scripts_renderer_resources.grd
  176. create mode 100755 components/user_scripts/renderer/script_context.cc
  177. create mode 100755 components/user_scripts/renderer/script_context.h
  178. create mode 100755 components/user_scripts/renderer/script_injection.cc
  179. create mode 100755 components/user_scripts/renderer/script_injection.h
  180. create mode 100755 components/user_scripts/renderer/script_injection_callback.cc
  181. create mode 100755 components/user_scripts/renderer/script_injection_callback.h
  182. create mode 100755 components/user_scripts/renderer/script_injection_manager.cc
  183. create mode 100755 components/user_scripts/renderer/script_injection_manager.h
  184. create mode 100755 components/user_scripts/renderer/script_injector.h
  185. create mode 100755 components/user_scripts/renderer/scripts_run_info.cc
  186. create mode 100755 components/user_scripts/renderer/scripts_run_info.h
  187. create mode 100755 components/user_scripts/renderer/user_script_injector.cc
  188. create mode 100755 components/user_scripts/renderer/user_script_injector.h
  189. create mode 100755 components/user_scripts/renderer/user_script_set.cc
  190. create mode 100755 components/user_scripts/renderer/user_script_set.h
  191. create mode 100755 components/user_scripts/renderer/user_script_set_manager.cc
  192. create mode 100755 components/user_scripts/renderer/user_script_set_manager.h
  193. create mode 100755 components/user_scripts/renderer/user_scripts_dispatcher.cc
  194. create mode 100755 components/user_scripts/renderer/user_scripts_dispatcher.h
  195. create mode 100755 components/user_scripts/renderer/user_scripts_renderer_client.cc
  196. create mode 100755 components/user_scripts/renderer/user_scripts_renderer_client.h
  197. create mode 100755 components/user_scripts/renderer/web_ui_injection_host.cc
  198. create mode 100755 components/user_scripts/renderer/web_ui_injection_host.h
  199. create mode 100755 components/user_scripts/strings/userscripts_strings.grdp
  200. diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
  201. --- a/chrome/android/BUILD.gn
  202. +++ b/chrome/android/BUILD.gn
  203. @@ -236,6 +236,9 @@ android_resources("chrome_app_java_resources") {
  204. "//third_party/androidx:androidx_preference_preference_java",
  205. "//third_party/androidx:androidx_recyclerview_recyclerview_java",
  206. ]
  207. +
  208. + # insert into chrome_app_java_resources
  209. + deps += [ "//components/user_scripts/android:java_resources" ]
  210. }
  211. if (enable_vr) {
  212. @@ -465,6 +468,7 @@ android_library("chrome_java") {
  213. "//components/translate/core/common:translate_infobar_event_enum_java",
  214. "//components/url_formatter/android:url_formatter_java",
  215. "//components/user_prefs/android:java",
  216. + "//components/user_scripts/android:java",
  217. "//components/variations/android:variations_java",
  218. "//components/version_info/android:version_constants_java",
  219. "//components/viz/common:common_java",
  220. diff --git a/chrome/android/java/src/org/chromium/chrome/browser/AfterStartupTaskUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/AfterStartupTaskUtils.java
  221. --- a/chrome/android/java/src/org/chromium/chrome/browser/AfterStartupTaskUtils.java
  222. +++ b/chrome/android/java/src/org/chromium/chrome/browser/AfterStartupTaskUtils.java
  223. @@ -4,6 +4,7 @@
  224. package org.chromium.chrome.browser;
  225. import org.chromium.base.annotations.NativeMethods;
  226. +import org.chromium.chrome.browser.user_scripts.UserScriptsUtils;
  227. /**
  228. * JNI call glue for AfterStartupTaskUtils in C++.
  229. @@ -17,6 +18,7 @@ public final class AfterStartupTaskUtils {
  230. * to run and newly posted tasks will no longer be deferred.
  231. */
  232. public static void setStartupComplete() {
  233. + UserScriptsUtils.Initialize();
  234. AfterStartupTaskUtilsJni.get().setStartupComplete();
  235. }
  236. 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
  237. --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
  238. +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
  239. @@ -62,6 +62,7 @@ import org.chromium.content_public.browser.BrowserStartupController;
  240. import org.chromium.content_public.browser.LoadUrlParams;
  241. import org.chromium.ui.base.DeviceFormFactor;
  242. import org.chromium.ui.widget.Toast;
  243. +import org.chromium.chrome.browser.user_scripts.UserScriptsUtils;
  244. import java.io.File;
  245. @@ -382,6 +383,11 @@ public class DownloadUtils {
  246. Context context = ContextUtils.getApplicationContext();
  247. DownloadManagerService service = DownloadManagerService.getDownloadManagerService();
  248. + if (UserScriptsUtils.getInstance().openFile(filePath, mimeType, downloadGuid,
  249. + isOffTheRecord, originalUrl, referrer)) {
  250. + return true;
  251. + }
  252. +
  253. // Check if Chrome should open the file itself.
  254. if (service.isDownloadOpenableInBrowser(isOffTheRecord, mimeType)) {
  255. // Share URIs use the content:// scheme when able, which looks bad when displayed
  256. diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
  257. --- a/chrome/android/java_sources.gni
  258. +++ b/chrome/android/java_sources.gni
  259. @@ -20,6 +20,7 @@ import("//components/feed/features.gni")
  260. import("//components/offline_pages/buildflags/features.gni")
  261. import("//components/omnibox/browser/test_java_sources.gni")
  262. import("//device/vr/buildflags/buildflags.gni")
  263. +import("//components/user_scripts/android/java_sources.gni")
  264. chrome_java_sources += public_autofill_assistant_java_sources
  265. @@ -53,3 +54,5 @@ if (enable_arcore) {
  266. "java/src/org/chromium/chrome/browser/vr/ArDelegateImpl.java",
  267. ]
  268. }
  269. +
  270. +chrome_java_sources += userscripts_java_sources
  271. diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
  272. --- a/chrome/browser/BUILD.gn
  273. +++ b/chrome/browser/BUILD.gn
  274. @@ -3377,6 +3377,11 @@ static_library("browser") {
  275. ]
  276. deps += [ "//chrome/android/modules/dev_ui/provider:native" ]
  277. }
  278. + deps += [
  279. + "//components/user_scripts/common",
  280. + "//components/user_scripts/browser",
  281. + "//components/user_scripts/android",
  282. + ]
  283. } else {
  284. #!is_android
  285. sources += [
  286. diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
  287. --- a/chrome/browser/about_flags.cc
  288. +++ b/chrome/browser/about_flags.cc
  289. @@ -138,6 +138,7 @@
  290. #include "components/translate/core/browser/translate_ranker_impl.h"
  291. #include "components/translate/core/common/translate_util.h"
  292. #include "components/ui_devtools/switches.h"
  293. +#include "components/user_scripts/common/user_scripts_features.h"
  294. #include "components/version_info/version_info.h"
  295. #include "components/viz/common/features.h"
  296. #include "components/viz/common/switches.h"
  297. @@ -6502,6 +6503,14 @@ const FeatureEntry kFeatureEntries[] = {
  298. FEATURE_VALUE_TYPE(features::kUserDataSnapshot)},
  299. #endif
  300. + {"enable-userscripts", flag_descriptions::kEnableUserScriptsName,
  301. + flag_descriptions::kEnableUserScriptsDescription, kOsDesktop | kOsAndroid,
  302. + FEATURE_VALUE_TYPE(user_scripts::features::kEnableUserScripts)},
  303. +
  304. + {"enable-userscripts-log", flag_descriptions::kEnableLoggingUserScriptsName,
  305. + flag_descriptions::kEnableLoggingUserScriptsDescription, kOsDesktop | kOsAndroid,
  306. + FEATURE_VALUE_TYPE(user_scripts::features::kEnableLoggingUserScripts)},
  307. +
  308. #if defined(OS_WIN)
  309. {"run-video-capture-service-in-browser",
  310. flag_descriptions::kRunVideoCaptureServiceInBrowserProcessName,
  311. diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
  312. --- a/chrome/browser/flag_descriptions.cc
  313. +++ b/chrome/browser/flag_descriptions.cc
  314. @@ -5094,6 +5094,16 @@ const char kUserDataSnapshotDescription[] =
  315. "update and restoring them after a version rollback.";
  316. #endif // !defined(OS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH)
  317. +const char kEnableUserScriptsName[] = "Enable user scripts";
  318. +const char kEnableUserScriptsDescription[] =
  319. + "Enables experimental support on user scripts. "
  320. + "Please report back any bug.";
  321. +
  322. +const char kEnableLoggingUserScriptsName[] = "Enable logging user scripts component";
  323. +const char kEnableLoggingUserScriptsDescription[] =
  324. + "Enables logging for troubleshooting feature. "
  325. + "Please report back any bug.";
  326. +
  327. #if defined(OS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_MAC)
  328. const char kWebShareName[] = "Web Share";
  329. const char kWebShareDescription[] =
  330. diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
  331. --- a/chrome/browser/flag_descriptions.h
  332. +++ b/chrome/browser/flag_descriptions.h
  333. @@ -2995,6 +2995,11 @@ extern const char kUserDataSnapshotName[];
  334. extern const char kUserDataSnapshotDescription[];
  335. #endif // !defined(OS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH)
  336. +extern const char kEnableUserScriptsName[];
  337. +extern const char kEnableUserScriptsDescription[];
  338. +extern const char kEnableLoggingUserScriptsName[];
  339. +extern const char kEnableLoggingUserScriptsDescription[];
  340. +
  341. #if defined(OS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_MAC)
  342. extern const char kWebShareName[];
  343. extern const char kWebShareDescription[];
  344. diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
  345. --- a/chrome/browser/prefs/browser_prefs.cc
  346. +++ b/chrome/browser/prefs/browser_prefs.cc
  347. @@ -227,6 +227,7 @@
  348. #include "components/ntp_tiles/popular_sites_impl.h"
  349. #include "components/permissions/contexts/geolocation_permission_context_android.h"
  350. #include "components/query_tiles/tile_service_prefs.h"
  351. +#include "components/user_scripts/browser/user_script_prefs.h"
  352. #else // defined(OS_ANDROID)
  353. #include "chrome/browser/accessibility/caption_controller.h"
  354. #include "chrome/browser/cart/cart_service.h"
  355. @@ -969,6 +970,7 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry,
  356. translate::TranslatePrefs::RegisterProfilePrefs(registry);
  357. omnibox::RegisterProfilePrefs(registry);
  358. ZeroSuggestProvider::RegisterProfilePrefs(registry);
  359. + user_scripts::UserScriptsPrefs::RegisterProfilePrefs(registry);
  360. #if BUILDFLAG(ENABLE_SESSION_SERVICE)
  361. RegisterSessionServiceLogProfilePrefs(registry);
  362. diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
  363. --- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
  364. +++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
  365. @@ -200,6 +200,8 @@
  366. #include "chrome/browser/lacros/cert_db_initializer_factory.h"
  367. #endif
  368. +#include "components/user_scripts/browser/userscripts_browser_client.h"
  369. +
  370. namespace chrome {
  371. void AddProfilesExtraParts(ChromeBrowserMainParts* main_parts) {
  372. @@ -460,6 +462,7 @@ void ChromeBrowserMainExtraPartsProfiles::
  373. #endif
  374. WebDataServiceFactory::GetInstance();
  375. webrtc_event_logging::WebRtcEventLogManagerKeyedServiceFactory::GetInstance();
  376. + user_scripts::UserScriptsBrowserClient::GetInstance();
  377. }
  378. void ChromeBrowserMainExtraPartsProfiles::PreProfileInit() {
  379. diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc
  380. --- a/chrome/browser/profiles/profile_manager.cc
  381. +++ b/chrome/browser/profiles/profile_manager.cc
  382. @@ -112,6 +112,8 @@
  383. #include "extensions/common/manifest.h"
  384. #endif
  385. +#include "components/user_scripts/browser/userscripts_browser_client.h"
  386. +
  387. #if BUILDFLAG(ENABLE_SESSION_SERVICE)
  388. #include "chrome/browser/sessions/session_service_factory.h"
  389. #endif
  390. @@ -1465,6 +1467,13 @@ void ProfileManager::DoFinalInitForServices(Profile* profile,
  391. }
  392. #endif
  393. +
  394. + user_scripts::UserScriptsBrowserClient* userscript_client =
  395. + user_scripts::UserScriptsBrowserClient::GetInstance();
  396. + if(userscript_client) {
  397. + userscript_client->SetProfile(profile);
  398. + }
  399. +
  400. #if BUILDFLAG(ENABLE_SUPERVISED_USERS)
  401. // Initialization needs to happen after extension system initialization (for
  402. // extension::ManagementPolicy) and InitProfileUserPrefs (for setting the
  403. diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
  404. --- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
  405. +++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
  406. @@ -84,6 +84,7 @@
  407. #include "components/security_interstitials/content/urls.h"
  408. #include "components/signin/public/base/signin_buildflags.h"
  409. #include "components/site_engagement/content/site_engagement_service.h"
  410. +#include "components/user_scripts/browser/ui/user_scripts_ui.h"
  411. #include "content/public/browser/web_contents.h"
  412. #include "content/public/browser/web_ui.h"
  413. #include "content/public/common/content_client.h"
  414. @@ -588,6 +589,8 @@ WebUIFactoryFunction GetWebUIFactoryFunction(WebUI* web_ui,
  415. return &NewWebUI<UserActionsUI>;
  416. if (url.host_piece() == chrome::kChromeUIVersionHost)
  417. return &NewWebUI<VersionUI>;
  418. + if (url.host_piece() == user_scripts::kChromeUIUserScriptsHost)
  419. + return &NewWebUI<user_scripts::UserScriptsUI>;
  420. #if !defined(OS_ANDROID)
  421. #if !BUILDFLAG(IS_CHROMEOS_ASH)
  422. diff --git a/chrome/chrome_paks.gni b/chrome/chrome_paks.gni
  423. --- a/chrome/chrome_paks.gni
  424. +++ b/chrome/chrome_paks.gni
  425. @@ -104,6 +104,7 @@ template("chrome_extra_paks") {
  426. "$root_gen_dir/third_party/blink/public/resources/inspector_overlay_resources.pak",
  427. "$root_gen_dir/ui/resources/webui_generated_resources.pak",
  428. "$root_gen_dir/ui/resources/webui_resources.pak",
  429. + "$root_gen_dir/chrome/userscripts_browser_resources.pak",
  430. ]
  431. deps = [
  432. "//base/tracing/protos:chrome_track_event_resources",
  433. @@ -119,6 +120,7 @@ template("chrome_extra_paks") {
  434. "//third_party/blink/public:devtools_inspector_resources",
  435. "//third_party/blink/public:resources",
  436. "//ui/resources",
  437. + "//components/user_scripts/browser:userscripts_browser_resources_grit",
  438. ]
  439. if (defined(invoker.deps)) {
  440. deps += invoker.deps
  441. diff --git a/chrome/renderer/BUILD.gn b/chrome/renderer/BUILD.gn
  442. --- a/chrome/renderer/BUILD.gn
  443. +++ b/chrome/renderer/BUILD.gn
  444. @@ -163,6 +163,7 @@ static_library("renderer") {
  445. "//components/contextual_search/content:renderer",
  446. "//components/data_reduction_proxy/core/common",
  447. "//components/dom_distiller/content/renderer",
  448. + "//components/user_scripts/renderer",
  449. "//components/network_hints/renderer",
  450. "//components/no_state_prefetch/common",
  451. "//components/no_state_prefetch/renderer",
  452. diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc
  453. --- a/chrome/renderer/chrome_content_renderer_client.cc
  454. +++ b/chrome/renderer/chrome_content_renderer_client.cc
  455. @@ -168,6 +168,8 @@
  456. #include "chrome/renderer/sandbox_status_extension_android.h"
  457. #include "components/continuous_search/renderer/search_result_extractor_impl.h" // nogncheck
  458. #include "components/embedder_support/android/common/url_constants.h"
  459. +#include "components/user_scripts/common/user_scripts_features.h"
  460. +#include "components/user_scripts/renderer/user_scripts_renderer_client.h"
  461. #else
  462. #include "chrome/renderer/cart/commerce_hint_agent.h"
  463. #include "chrome/renderer/media/chrome_speech_recognition_client.h"
  464. @@ -363,6 +365,12 @@ void ChromeContentRendererClient::RenderThreadStarted() {
  465. ChromeExtensionsRendererClient::GetInstance()->RenderThreadStarted();
  466. #endif
  467. + user_scripts::UserScriptsRendererClient* userscript_client =
  468. + user_scripts::UserScriptsRendererClient::GetInstance();
  469. + if(userscript_client) {
  470. + userscript_client->RenderThreadStarted();
  471. + }
  472. +
  473. #if BUILDFLAG(ENABLE_SPELLCHECK)
  474. if (!spellcheck_)
  475. InitSpellCheck();
  476. @@ -493,6 +501,13 @@ void ChromeContentRendererClient::RenderFrameCreated(
  477. render_frame, registry);
  478. #endif
  479. + user_scripts::UserScriptsRendererClient* userscript_client =
  480. + user_scripts::UserScriptsRendererClient::GetInstance();
  481. + if(userscript_client) {
  482. + userscript_client->RenderFrameCreated(
  483. + render_frame, registry);
  484. + }
  485. +
  486. #if BUILDFLAG(ENABLE_PLUGINS)
  487. new PepperHelper(render_frame);
  488. #endif
  489. @@ -1455,6 +1470,12 @@ void ChromeContentRendererClient::RunScriptsAtDocumentStart(
  490. render_frame);
  491. // |render_frame| might be dead by now.
  492. #endif
  493. + user_scripts::UserScriptsRendererClient* userscript_client =
  494. + user_scripts::UserScriptsRendererClient::GetInstance();
  495. + if(userscript_client) {
  496. + userscript_client->RunScriptsAtDocumentStart(
  497. + render_frame);
  498. + }
  499. }
  500. void ChromeContentRendererClient::RunScriptsAtDocumentEnd(
  501. @@ -1464,6 +1485,12 @@ void ChromeContentRendererClient::RunScriptsAtDocumentEnd(
  502. render_frame);
  503. // |render_frame| might be dead by now.
  504. #endif
  505. + user_scripts::UserScriptsRendererClient* userscript_client =
  506. + user_scripts::UserScriptsRendererClient::GetInstance();
  507. + if(userscript_client) {
  508. + userscript_client->RunScriptsAtDocumentEnd(
  509. + render_frame);
  510. + }
  511. }
  512. void ChromeContentRendererClient::RunScriptsAtDocumentIdle(
  513. @@ -1473,6 +1500,12 @@ void ChromeContentRendererClient::RunScriptsAtDocumentIdle(
  514. render_frame);
  515. // |render_frame| might be dead by now.
  516. #endif
  517. + user_scripts::UserScriptsRendererClient* userscript_client =
  518. + user_scripts::UserScriptsRendererClient::GetInstance();
  519. + if(userscript_client) {
  520. + userscript_client->RunScriptsAtDocumentIdle(
  521. + render_frame);
  522. + }
  523. }
  524. void ChromeContentRendererClient::
  525. diff --git a/components/components_strings.grd b/components/components_strings.grd
  526. --- a/components/components_strings.grd
  527. +++ b/components/components_strings.grd
  528. @@ -327,6 +327,7 @@
  529. <part file="undo_strings.grdp" />
  530. <part file="version_ui_strings.grdp" />
  531. <part file="webapps_strings.grdp" />
  532. + <part file="user_scripts/strings/userscripts_strings.grdp" />
  533. <if expr="not is_android and not is_ios">
  534. <part file="management_strings.grdp" />
  535. diff --git a/components/user_scripts/android/BUILD.gn b/components/user_scripts/android/BUILD.gn
  536. new file mode 100755
  537. --- /dev/null
  538. +++ b/components/user_scripts/android/BUILD.gn
  539. @@ -0,0 +1,82 @@
  540. +# This file is part of Bromite.
  541. +
  542. +# Bromite is free software: you can redistribute it and/or modify
  543. +# it under the terms of the GNU General Public License as published by
  544. +# the Free Software Foundation, either version 3 of the License, or
  545. +# (at your option) any later version.
  546. +
  547. +# Bromite is distributed in the hope that it will be useful,
  548. +# but WITHOUT ANY WARRANTY; without even the implied warranty of
  549. +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  550. +# GNU General Public License for more details.
  551. +
  552. +# You should have received a copy of the GNU General Public License
  553. +# along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  554. +
  555. +import("//build/config/android/rules.gni")
  556. +
  557. +generate_jni("user_scripts_jni_headers") {
  558. + sources = [ "java/src/org/chromium/components/user_scripts/UserScriptsBridge.java" ]
  559. +}
  560. +
  561. +android_resources("java_resources") {
  562. + sources = [
  563. + "java/res/xml/main_preferences_addon_userscripts.xml",
  564. + "java/res/xml/userscripts_preferences.xml",
  565. + "java/res/layout/accept_script_item.xml",
  566. + "java/res/layout/accept_script_list.xml",
  567. + "java/res/layout/scripts_preference.xml",
  568. + "java/res/values/dimens.xml"
  569. + ]
  570. +
  571. + deps = [
  572. + "//components/browser_ui/strings/android:browser_ui_strings_grd",
  573. + "//components/browser_ui/styles/android:java_resources",
  574. + "//components/strings:components_strings_grd",
  575. + "//ui/android:ui_java_resources",
  576. + ]
  577. +}
  578. +
  579. +android_library("java") {
  580. + sources = [
  581. + "java/src/org/chromium/components/user_scripts/FragmentWindowAndroid.java",
  582. + "java/src/org/chromium/components/user_scripts/UserScriptsPreferences.java",
  583. + "java/src/org/chromium/components/user_scripts/UserScriptsBridge.java",
  584. + "java/src/org/chromium/components/user_scripts/IUserScriptsUtils.java",
  585. + "java/src/org/chromium/components/user_scripts/ScriptListBaseAdapter.java",
  586. + "java/src/org/chromium/components/user_scripts/ScriptListPreference.java",
  587. + "java/src/org/chromium/components/user_scripts/ScriptInfo.java",
  588. + ]
  589. + deps = [
  590. + ":java_resources",
  591. + "//base:base_java",
  592. + "//base:jni_java",
  593. + "//components/embedder_support/android:browser_context_java",
  594. + "//components/browser_ui/settings/android:java",
  595. + "//components/browser_ui/widget/android:java",
  596. + "//content/public/android:content_java",
  597. + "//components/prefs/android:java",
  598. + "//third_party/android_deps:android_support_v7_appcompat_java",
  599. + "//third_party/androidx:androidx_annotation_annotation_java",
  600. + "//third_party/androidx:androidx_appcompat_appcompat_resources_java",
  601. + "//third_party/androidx:androidx_preference_preference_java",
  602. + "//ui/android:ui_java",
  603. + ]
  604. + resources_package = "org.chromium.components.user_scripts"
  605. + annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
  606. +}
  607. +
  608. +source_set("android") {
  609. + sources = [
  610. + "user_scripts_bridge.cc",
  611. + "user_scripts_bridge.h",
  612. + ]
  613. + deps = [
  614. + ":user_scripts_jni_headers",
  615. + "//base",
  616. + "//components/user_scripts/browser",
  617. + "//components/embedder_support/android:browser_context",
  618. + "//components/permissions",
  619. + "//content/public/browser",
  620. + ]
  621. +}
  622. 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
  623. new file mode 100644
  624. --- /dev/null
  625. +++ b/components/user_scripts/android/java/res/layout/accept_script_item.xml
  626. @@ -0,0 +1,74 @@
  627. +<?xml version="1.0" encoding="utf-8"?>
  628. +<!-- Copyright 2017 The Chromium Authors. All rights reserved.
  629. + Use of this source code is governed by a BSD-style license that can be
  630. + found in the LICENSE file. -->
  631. +
  632. +<LinearLayout
  633. + xmlns:android="http://schemas.android.com/apk/res/android"
  634. + xmlns:app="http://schemas.android.com/apk/res-auto"
  635. + xmlns:tools="http://schemas.android.com/tools"
  636. + android:id="@+id/language_item"
  637. + android:layout_marginStart="0dp"
  638. + android:paddingStart="@dimen/draggable_list_item_padding"
  639. + android:paddingEnd="@dimen/draggable_list_item_padding"
  640. + style="@style/ListItemContainer">
  641. +
  642. + <Switch
  643. + android:id="@+id/switch_widget"
  644. + android:layout_width="wrap_content"
  645. + android:layout_height="wrap_content"
  646. + android:paddingEnd="15dp"
  647. + android:focusable="false"
  648. + android:background="@null" />
  649. +
  650. + <LinearLayout
  651. + android:layout_width="0dp"
  652. + android:layout_height="wrap_content"
  653. + android:layout_weight="1"
  654. + android:orientation="vertical"
  655. + android:layout_gravity="center_vertical" >
  656. +
  657. + <TextView
  658. + android:id="@+id/title"
  659. + android:layout_width="match_parent"
  660. + android:layout_height="wrap_content"
  661. + style="@style/PreferenceTitle" />
  662. +
  663. + <TextView
  664. + android:id="@+id/description"
  665. + android:layout_width="match_parent"
  666. + android:layout_height="wrap_content"
  667. + style="@style/PreferenceSummary" />
  668. +
  669. + <TextView
  670. + android:id="@+id/version"
  671. + android:layout_width="match_parent"
  672. + android:layout_height="wrap_content"
  673. + style="@style/PreferenceSummary" />
  674. +
  675. + <TextView
  676. + android:id="@+id/file"
  677. + android:layout_width="match_parent"
  678. + android:layout_height="wrap_content"
  679. + style="@style/PreferenceSummary" />
  680. +
  681. + <TextView
  682. + android:id="@+id/url"
  683. + android:layout_width="match_parent"
  684. + android:layout_height="wrap_content"
  685. + style="@style/PreferenceSummary" />
  686. +
  687. + </LinearLayout>
  688. +
  689. + <org.chromium.components.browser_ui.widget.listmenu.ListMenuButton
  690. + android:id="@+id/more"
  691. + android:layout_width="wrap_content"
  692. + android:layout_height="match_parent"
  693. + android:paddingStart="@dimen/default_list_row_padding"
  694. + android:paddingEnd="@dimen/default_list_row_padding"
  695. + android:background="@null"
  696. + android:src="@drawable/ic_more_vert_24dp"
  697. + app:menuMaxWidth="@dimen/pref_scripts_item_popup_width"
  698. + app:tint="@color/default_icon_color_tint_list"
  699. + tools:ignore="ContentDescription" />
  700. +</LinearLayout>
  701. \ No newline at end of file
  702. 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
  703. new file mode 100644
  704. --- /dev/null
  705. +++ b/components/user_scripts/android/java/res/layout/accept_script_list.xml
  706. @@ -0,0 +1,10 @@
  707. +<?xml version="1.0" encoding="utf-8"?>
  708. +<!-- Copyright 2017 The Chromium Authors. All rights reserved.
  709. + Use of this source code is governed by a BSD-style license that can be
  710. + found in the LICENSE file. -->
  711. +
  712. +<androidx.recyclerview.widget.RecyclerView
  713. + xmlns:android="http://schemas.android.com/apk/res/android"
  714. + android:id="@+id/script_list"
  715. + android:layout_width="match_parent"
  716. + android:layout_height="wrap_content" />
  717. \ No newline at end of file
  718. diff --git a/components/user_scripts/android/java/res/layout/scripts_preference.xml b/components/user_scripts/android/java/res/layout/scripts_preference.xml
  719. new file mode 100644
  720. --- /dev/null
  721. +++ b/components/user_scripts/android/java/res/layout/scripts_preference.xml
  722. @@ -0,0 +1,40 @@
  723. +<?xml version="1.0" encoding="utf-8"?>
  724. +<!-- Copyright 2017 The Chromium Authors. All rights reserved.
  725. + Use of this source code is governed by a BSD-style license that can be
  726. + found in the LICENSE file. -->
  727. +
  728. +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  729. + android:id="@+id/accept_scripts_list_container"
  730. + style="@style/PreferenceLayout"
  731. + android:layout_width="match_parent"
  732. + android:layout_height="wrap_content"
  733. + android:paddingStart="0dp"
  734. + android:paddingEnd="0dp"
  735. + android:padding="0dp"
  736. + android:orientation="vertical" >
  737. +
  738. + <TextView
  739. + android:layout_width="match_parent"
  740. + android:layout_height="wrap_content"
  741. + android:padding="@dimen/draggable_list_item_padding"
  742. + android:text="@string/scripts_list_description" />
  743. +
  744. + <FrameLayout
  745. + android:id="@android:id/widget_frame"
  746. + android:layout_width="match_parent"
  747. + android:layout_height="wrap_content" />
  748. +
  749. + <TextView
  750. + android:id="@+id/add_script"
  751. + android:layout_width="match_parent"
  752. + android:layout_height="wrap_content"
  753. + android:background="?attr/selectableItemBackground"
  754. + android:clickable="true"
  755. + android:gravity="center_vertical"
  756. + android:padding="@dimen/draggable_list_item_padding"
  757. + android:paddingStart="@dimen/pref_scripts_add_button_padding"
  758. + android:drawablePadding="@dimen/pref_scripts_add_button_padding"
  759. + android:text="@string/add_script"
  760. + style="@style/PreferenceTitle" />
  761. +
  762. +</LinearLayout>
  763. \ No newline at end of file
  764. diff --git a/components/user_scripts/android/java/res/values/dimens.xml b/components/user_scripts/android/java/res/values/dimens.xml
  765. new file mode 100755
  766. --- /dev/null
  767. +++ b/components/user_scripts/android/java/res/values/dimens.xml
  768. @@ -0,0 +1,11 @@
  769. +<?xml version="1.0" encoding="utf-8"?>
  770. +<!-- Copyright 2014 The Chromium Authors. All rights reserved.
  771. + Use of this source code is governed by a BSD-style license that can be
  772. + found in the LICENSE file. -->
  773. +
  774. +<resources xmlns:tools="http://schemas.android.com/tools">
  775. +
  776. + <dimen name="pref_scripts_add_button_padding">24dp</dimen>
  777. + <dimen name="pref_scripts_item_popup_width">260dp</dimen>
  778. +
  779. +</resources>
  780. 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
  781. new file mode 100755
  782. --- /dev/null
  783. +++ b/components/user_scripts/android/java/res/xml/main_preferences_addon_userscripts.xml
  784. @@ -0,0 +1,29 @@
  785. +<?xml version="1.0" encoding="utf-8"?>
  786. +<!--
  787. + This file is part of Bromite.
  788. +
  789. + Bromite is free software: you can redistribute it and/or modify
  790. + it under the terms of the GNU General Public License as published by
  791. + the Free Software Foundation, either version 3 of the License, or
  792. + (at your option) any later version.
  793. +
  794. + Bromite is distributed in the hope that it will be useful,
  795. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  796. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  797. + GNU General Public License for more details.
  798. +
  799. + You should have received a copy of the GNU General Public License
  800. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  801. +-->
  802. +
  803. +<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
  804. + xmlns:app="http://schemas.android.com/apk/res-auto"
  805. + android:orderingFromXml="false">
  806. +
  807. + <Preference
  808. + android:fragment="org.chromium.components.user_scripts.UserScriptsPreferences"
  809. + android:key="userscripts_settings"
  810. + android:order="20"
  811. + android:title="@string/prefs_userscripts_settings"/>
  812. +
  813. +</PreferenceScreen>
  814. diff --git a/components/user_scripts/android/java/res/xml/userscripts_preferences.xml b/components/user_scripts/android/java/res/xml/userscripts_preferences.xml
  815. new file mode 100644
  816. --- /dev/null
  817. +++ b/components/user_scripts/android/java/res/xml/userscripts_preferences.xml
  818. @@ -0,0 +1,40 @@
  819. +<?xml version="1.0" encoding="utf-8"?>
  820. +<!--
  821. + This file is part of Bromite.
  822. +
  823. + Bromite is free software: you can redistribute it and/or modify
  824. + it under the terms of the GNU General Public License as published by
  825. + the Free Software Foundation, either version 3 of the License, or
  826. + (at your option) any later version.
  827. +
  828. + Bromite is distributed in the hope that it will be useful,
  829. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  830. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  831. + GNU General Public License for more details.
  832. +
  833. + You should have received a copy of the GNU General Public License
  834. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  835. +-->
  836. +
  837. +<PreferenceScreen
  838. + xmlns:android="http://schemas.android.com/apk/res/android"
  839. + xmlns:app="http://schemas.android.com/apk/res-auto">
  840. +
  841. + <org.chromium.components.browser_ui.settings.TextMessagePreference
  842. + android:key="scripts_disabled_description"
  843. + android:title="@string/scripts_disabled_description"
  844. + app:allowDividerBelow="false"
  845. + app:isPreferenceVisible="false"/>
  846. +
  847. + <org.chromium.components.browser_ui.settings.ChromeSwitchPreference
  848. + android:key="enabled_switch"
  849. + android:title="@string/option_userscript_flag"
  850. + android:summaryOn="@string/option_userscript_flag_on"
  851. + android:summaryOff="@string/option_userscript_flag_off" />
  852. +
  853. + <org.chromium.components.user_scripts.ScriptListPreference
  854. + android:key="script_list"
  855. + android:layout="@layout/scripts_preference"
  856. + android:widgetLayout="@layout/accept_script_list" />
  857. +
  858. +</PreferenceScreen>
  859. 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
  860. new file mode 100755
  861. --- /dev/null
  862. +++ b/components/user_scripts/android/java/src/org/chromium/chrome/browser/user_scripts/UserScriptsUtils.java
  863. @@ -0,0 +1,78 @@
  864. +/*
  865. + This file is part of Bromite.
  866. +
  867. + Bromite is free software: you can redistribute it and/or modify
  868. + it under the terms of the GNU General Public License as published by
  869. + the Free Software Foundation, either version 3 of the License, or
  870. + (at your option) any later version.
  871. +
  872. + Bromite is distributed in the hope that it will be useful,
  873. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  874. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  875. + GNU General Public License for more details.
  876. +
  877. + You should have received a copy of the GNU General Public License
  878. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  879. +*/
  880. +
  881. +package org.chromium.chrome.browser.user_scripts;
  882. +
  883. +import android.content.Context;
  884. +import android.content.Intent;
  885. +import android.provider.Browser;
  886. +import android.net.Uri;
  887. +
  888. +import org.chromium.base.ContextUtils;
  889. +import org.chromium.base.IntentUtils;
  890. +
  891. +import org.chromium.chrome.browser.IntentHandler;
  892. +import org.chromium.chrome.browser.settings.SettingsLauncherImpl;
  893. +import org.chromium.components.browser_ui.settings.SettingsLauncher;
  894. +
  895. +import org.chromium.components.user_scripts.UserScriptsPreferences;
  896. +import org.chromium.components.user_scripts.UserScriptsBridge;
  897. +import org.chromium.components.user_scripts.IUserScriptsUtils;
  898. +
  899. +public class UserScriptsUtils implements IUserScriptsUtils
  900. +{
  901. + private static UserScriptsUtils instance;
  902. +
  903. + private UserScriptsUtils() {}
  904. +
  905. + public static void Initialize() {
  906. + instance = new UserScriptsUtils();
  907. + UserScriptsBridge.registerUtils(instance);
  908. + }
  909. +
  910. + public static UserScriptsUtils getInstance() {
  911. + return instance;
  912. + }
  913. +
  914. + public boolean openFile(String filePath, String mimeType, String downloadGuid,
  915. + boolean isOffTheRecord, String originalUrl, String referrer) {
  916. + if (UserScriptsBridge.isUserEnabled() == false) return false;
  917. +
  918. + if (filePath.toUpperCase().endsWith(".USER.JS") == false) return false;
  919. +
  920. + Context context = ContextUtils.getApplicationContext();
  921. +
  922. + SettingsLauncher settingsLauncher = new SettingsLauncherImpl();
  923. + Intent intent = settingsLauncher.createSettingsActivityIntent(
  924. + context, UserScriptsPreferences.class.getName(),
  925. + UserScriptsPreferences.createFragmentArgsForInstall(filePath));
  926. + IntentUtils.safeStartActivity(context, intent);
  927. +
  928. + return true;
  929. + }
  930. +
  931. + public void openSourceFile(String scriptKey) {
  932. + Context context = ContextUtils.getApplicationContext();
  933. +
  934. + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("chrome://user-scripts/?key=" + scriptKey));
  935. + intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
  936. + intent.putExtra(Browser.EXTRA_CREATE_NEW_TAB, true);
  937. + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  938. + intent.setPackage(context.getPackageName());
  939. + IntentHandler.startChromeLauncherActivityForTrustedIntent(intent);
  940. + }
  941. +}
  942. \ No newline at end of file
  943. 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
  944. new file mode 100644
  945. --- /dev/null
  946. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/FragmentWindowAndroid.java
  947. @@ -0,0 +1,68 @@
  948. +// Copyright 2019 The Chromium Authors. All rights reserved.
  949. +// Use of this source code is governed by a BSD-style license that can be
  950. +// found in the LICENSE file.
  951. +
  952. +package org.chromium.components.user_scripts;
  953. +
  954. +import android.annotation.TargetApi;
  955. +import android.app.Activity;
  956. +import android.content.Context;
  957. +import android.content.Intent;
  958. +import android.content.IntentSender;
  959. +import android.os.Build;
  960. +import android.view.View;
  961. +
  962. +import androidx.fragment.app.Fragment;
  963. +
  964. +import org.chromium.ui.base.ActivityKeyboardVisibilityDelegate;
  965. +import org.chromium.ui.base.ActivityAndroidPermissionDelegate;
  966. +import org.chromium.ui.base.ImmutableWeakReference;
  967. +import org.chromium.ui.base.IntentWindowAndroid;
  968. +
  969. +import java.lang.ref.WeakReference;
  970. +
  971. +/**
  972. + * Implements intent sending for a fragment based window. This should be created when
  973. + * onAttach() is called on the fragment, and destroyed when onDetach() is called.
  974. + */
  975. +public class FragmentWindowAndroid extends IntentWindowAndroid {
  976. + private Fragment mFragment;
  977. +
  978. + // This WeakReference is purely to avoid gc churn of creating a new WeakReference in
  979. + // every getActivity call. It is not needed for correctness.
  980. + private ImmutableWeakReference<Activity> mActivityWeakRefHolder;
  981. +
  982. + FragmentWindowAndroid(Context context, Fragment fragment) {
  983. + super(context);
  984. + mFragment = fragment;
  985. +
  986. + setKeyboardDelegate(new ActivityKeyboardVisibilityDelegate(getActivity()));
  987. + setAndroidPermissionDelegate(new ActivityAndroidPermissionDelegate(getActivity()));
  988. + }
  989. +
  990. + @Override
  991. + protected final boolean startIntentSenderForResult(IntentSender intentSender, int requestCode) {
  992. + try {
  993. + mFragment.startIntentSenderForResult(
  994. + intentSender, requestCode, new Intent(), 0, 0, 0, null);
  995. + } catch (IntentSender.SendIntentException e) {
  996. + return false;
  997. + }
  998. + return true;
  999. + }
  1000. +
  1001. + @Override
  1002. + protected final boolean startActivityForResult(Intent intent, int requestCode) {
  1003. + mFragment.startActivityForResult(intent, requestCode, null);
  1004. + return true;
  1005. + }
  1006. +
  1007. + @Override
  1008. + public final WeakReference<Activity> getActivity() {
  1009. + if (mActivityWeakRefHolder == null
  1010. + || mActivityWeakRefHolder.get() != mFragment.getActivity()) {
  1011. + mActivityWeakRefHolder = new ImmutableWeakReference<>(mFragment.getActivity());
  1012. + }
  1013. + return mActivityWeakRefHolder;
  1014. + }
  1015. +}
  1016. \ No newline at end of file
  1017. diff --git a/components/user_scripts/android/java/src/org/chromium/components/user_scripts/IUserScriptsUtils.java b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/IUserScriptsUtils.java
  1018. new file mode 100644
  1019. --- /dev/null
  1020. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/IUserScriptsUtils.java
  1021. @@ -0,0 +1,22 @@
  1022. +/*
  1023. + This file is part of Bromite.
  1024. +
  1025. + Bromite is free software: you can redistribute it and/or modify
  1026. + it under the terms of the GNU General Public License as published by
  1027. + the Free Software Foundation, either version 3 of the License, or
  1028. + (at your option) any later version.
  1029. +
  1030. + Bromite is distributed in the hope that it will be useful,
  1031. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1032. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1033. + GNU General Public License for more details.
  1034. +
  1035. + You should have received a copy of the GNU General Public License
  1036. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1037. +*/
  1038. +
  1039. +package org.chromium.components.user_scripts;
  1040. +
  1041. +public interface IUserScriptsUtils {
  1042. + public void openSourceFile(String scriptKey);
  1043. +}
  1044. \ No newline at end of file
  1045. 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
  1046. new file mode 100644
  1047. --- /dev/null
  1048. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptInfo.java
  1049. @@ -0,0 +1,33 @@
  1050. +/*
  1051. + This file is part of Bromite.
  1052. +
  1053. + Bromite is free software: you can redistribute it and/or modify
  1054. + it under the terms of the GNU General Public License as published by
  1055. + the Free Software Foundation, either version 3 of the License, or
  1056. + (at your option) any later version.
  1057. +
  1058. + Bromite is distributed in the hope that it will be useful,
  1059. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1060. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1061. + GNU General Public License for more details.
  1062. +
  1063. + You should have received a copy of the GNU General Public License
  1064. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1065. +*/
  1066. +
  1067. +package org.chromium.components.user_scripts;
  1068. +
  1069. +import java.time.LocalDateTime;
  1070. +
  1071. +public class ScriptInfo {
  1072. + public String Key;
  1073. + public String Name;
  1074. + public String Description;
  1075. + public String Version;
  1076. + public String FilePath;
  1077. + public String UrlSource;
  1078. + public boolean Enabled;
  1079. + public LocalDateTime InstallTime;
  1080. +
  1081. + public ScriptInfo() {}
  1082. +}
  1083. 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
  1084. new file mode 100644
  1085. --- /dev/null
  1086. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptListBaseAdapter.java
  1087. @@ -0,0 +1,194 @@
  1088. +/*
  1089. + This file is part of Bromite.
  1090. +
  1091. + Bromite is free software: you can redistribute it and/or modify
  1092. + it under the terms of the GNU General Public License as published by
  1093. + the Free Software Foundation, either version 3 of the License, or
  1094. + (at your option) any later version.
  1095. +
  1096. + Bromite is distributed in the hope that it will be useful,
  1097. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1098. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1099. + GNU General Public License for more details.
  1100. +
  1101. + You should have received a copy of the GNU General Public License
  1102. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1103. +*/
  1104. +
  1105. +package org.chromium.components.user_scripts;
  1106. +
  1107. +import android.content.Context;
  1108. +import android.view.LayoutInflater;
  1109. +import android.view.MotionEvent;
  1110. +import android.view.View;
  1111. +import android.view.ViewGroup;
  1112. +import android.view.accessibility.AccessibilityManager;
  1113. +import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
  1114. +import android.widget.ImageView;
  1115. +import android.widget.TextView;
  1116. +import android.widget.Switch;
  1117. +import android.widget.CompoundButton;
  1118. +
  1119. +import androidx.annotation.DrawableRes;
  1120. +import androidx.annotation.NonNull;
  1121. +import androidx.core.view.ViewCompat;
  1122. +import androidx.recyclerview.widget.RecyclerView.ViewHolder;
  1123. +
  1124. +import org.chromium.components.browser_ui.widget.dragreorder.DragReorderableListAdapter;
  1125. +import org.chromium.components.browser_ui.widget.dragreorder.DragStateDelegate;
  1126. +import org.chromium.components.browser_ui.widget.listmenu.ListMenuButton;
  1127. +import org.chromium.components.browser_ui.widget.listmenu.ListMenuButtonDelegate;
  1128. +
  1129. +import java.util.ArrayList;
  1130. +import java.util.List;
  1131. +
  1132. +public class ScriptListBaseAdapter extends DragReorderableListAdapter<ScriptInfo> {
  1133. +
  1134. + class ItemClickListener {
  1135. + void onScriptOnOff(boolean Enabled) {}
  1136. + void onScriptClicked() {}
  1137. + }
  1138. +
  1139. + static class ScriptInfoRowViewHolder extends ViewHolder {
  1140. + private TextView mTitle;
  1141. + private TextView mDescription;
  1142. + private TextView mVersion;
  1143. + private TextView mFile;
  1144. + private TextView mUrl;
  1145. + private Switch mSwitch;
  1146. +
  1147. + private ListMenuButton mMoreButton;
  1148. +
  1149. + private CompoundButton.OnCheckedChangeListener mOnOffListener;
  1150. +
  1151. + ScriptInfoRowViewHolder(View view) {
  1152. + super(view);
  1153. +
  1154. + mSwitch = view.findViewById(R.id.switch_widget);
  1155. + mTitle = view.findViewById(R.id.title);
  1156. + mDescription = view.findViewById(R.id.description);
  1157. + mVersion = view.findViewById(R.id.version);
  1158. + mFile = view.findViewById(R.id.file);
  1159. + mUrl = view.findViewById(R.id.url);
  1160. +
  1161. + mMoreButton = view.findViewById(R.id.more);
  1162. + }
  1163. +
  1164. + protected void updateScriptInfo(ScriptInfo item) {
  1165. + mSwitch.setOnCheckedChangeListener(null);
  1166. + mSwitch.setChecked(item.Enabled);
  1167. + mSwitch.setOnCheckedChangeListener(mOnOffListener);
  1168. +
  1169. + mTitle.setText(item.Name);
  1170. + mDescription.setText(item.Description);
  1171. + mVersion.setText(item.Version);
  1172. + mFile.setText(item.Key);
  1173. + mUrl.setText(item.UrlSource);
  1174. +
  1175. + if (item.UrlSource == null || item.UrlSource.isEmpty()) {
  1176. + mUrl.setVisibility(View.GONE);
  1177. + }
  1178. + }
  1179. +
  1180. + void setMenuButtonDelegate(@NonNull ListMenuButtonDelegate delegate) {
  1181. + mMoreButton.setVisibility(View.VISIBLE);
  1182. + mMoreButton.setDelegate(delegate);
  1183. + // Set item row end padding 0 when MenuButton is visible.
  1184. + ViewCompat.setPaddingRelative(itemView, ViewCompat.getPaddingStart(itemView),
  1185. + itemView.getPaddingTop(), 0, itemView.getPaddingBottom());
  1186. + }
  1187. +
  1188. + void setItemListener(@NonNull ItemClickListener listener) {
  1189. + mOnOffListener = (buttonView, isChecked) -> listener.onScriptOnOff(isChecked);
  1190. + mSwitch.setOnCheckedChangeListener(mOnOffListener);
  1191. + itemView.setOnClickListener(view -> listener.onScriptClicked());
  1192. + }
  1193. + }
  1194. +
  1195. + private class ScriptDragStateDelegate implements DragStateDelegate {
  1196. + private AccessibilityManager mA11yManager;
  1197. + private AccessibilityStateChangeListener mA11yListener;
  1198. + private boolean mA11yEnabled;
  1199. +
  1200. + public ScriptDragStateDelegate() {
  1201. + mA11yManager =
  1202. + (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
  1203. + mA11yEnabled = mA11yManager.isEnabled();
  1204. + mA11yListener = enabled -> {
  1205. + mA11yEnabled = enabled;
  1206. + notifyDataSetChanged();
  1207. + };
  1208. + mA11yManager.addAccessibilityStateChangeListener(mA11yListener);
  1209. + }
  1210. +
  1211. + @Override
  1212. + public boolean getDragEnabled() {
  1213. + return !mA11yEnabled;
  1214. + }
  1215. +
  1216. + @Override
  1217. + public boolean getDragActive() {
  1218. + return getDragEnabled();
  1219. + }
  1220. +
  1221. + @Override
  1222. + public void setA11yStateForTesting(boolean a11yEnabled) {
  1223. + }
  1224. + }
  1225. +
  1226. + ScriptListBaseAdapter(Context context) {
  1227. + super(context);
  1228. + setDragStateDelegate(new ScriptDragStateDelegate());
  1229. + }
  1230. +
  1231. + void showDragIndicatorInRow(ScriptInfoRowViewHolder holder) {
  1232. + // Quit if it's not applicable.
  1233. + if (getItemCount() <= 1 || !mDragStateDelegate.getDragEnabled()) return;
  1234. +
  1235. + // assert mItemTouchHelper != null;
  1236. + // //holder.setStartIcon(R.drawable.ic_drag_handle_grey600_24dp);
  1237. + // holder.mStartIcon.setOnTouchListener((v, event) -> {
  1238. + // if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
  1239. + // mItemTouchHelper.startDrag(holder);
  1240. + // }
  1241. + // return false;
  1242. + // });
  1243. + }
  1244. +
  1245. + @Override
  1246. + public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
  1247. + View row = LayoutInflater.from(viewGroup.getContext())
  1248. + .inflate(R.layout.accept_script_item, viewGroup, false);
  1249. + return new ScriptInfoRowViewHolder(row);
  1250. + }
  1251. +
  1252. + @Override
  1253. + public void onBindViewHolder(ViewHolder viewHolder, int i) {
  1254. + ((ScriptInfoRowViewHolder) viewHolder).updateScriptInfo(mElements.get(i));
  1255. + }
  1256. +
  1257. + @Override
  1258. + protected void setOrder(List<ScriptInfo> order) {
  1259. + // String[] codes = new String[order.size()];
  1260. + // for (int i = 0; i < order.size(); i++) {
  1261. + // codes[i] = order.get(i).getCode();
  1262. + // }
  1263. + //LanguagesManager.getInstance().setOrder(codes, false);
  1264. + //notifyDataSetChanged();
  1265. + }
  1266. +
  1267. + void setDisplayedScriptInfo(List<ScriptInfo> values) {
  1268. + mElements = new ArrayList<>(values);
  1269. + notifyDataSetChanged();
  1270. + }
  1271. +
  1272. + @Override
  1273. + protected boolean isActivelyDraggable(ViewHolder viewHolder) {
  1274. + return isPassivelyDraggable(viewHolder);
  1275. + }
  1276. +
  1277. + @Override
  1278. + protected boolean isPassivelyDraggable(ViewHolder viewHolder) {
  1279. + return viewHolder instanceof ScriptInfoRowViewHolder;
  1280. + }
  1281. +}
  1282. 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
  1283. new file mode 100644
  1284. --- /dev/null
  1285. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptListPreference.java
  1286. @@ -0,0 +1,169 @@
  1287. +/*
  1288. + This file is part of Bromite.
  1289. +
  1290. + Bromite is free software: you can redistribute it and/or modify
  1291. + it under the terms of the GNU General Public License as published by
  1292. + the Free Software Foundation, either version 3 of the License, or
  1293. + (at your option) any later version.
  1294. +
  1295. + Bromite is distributed in the hope that it will be useful,
  1296. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1297. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1298. + GNU General Public License for more details.
  1299. +
  1300. + You should have received a copy of the GNU General Public License
  1301. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1302. +*/
  1303. +
  1304. +package org.chromium.components.user_scripts;
  1305. +
  1306. +import static org.chromium.components.browser_ui.widget.listmenu.BasicListMenu.buildMenuListItem;
  1307. +import static org.chromium.components.browser_ui.widget.listmenu.BasicListMenu.buildMenuListItemWithEndIcon;
  1308. +
  1309. +import android.content.Context;
  1310. +import android.content.Intent;
  1311. +import android.provider.Browser;
  1312. +import android.net.Uri;
  1313. +import android.util.AttributeSet;
  1314. +import android.widget.TextView;
  1315. +import android.widget.Toast;
  1316. +
  1317. +import androidx.preference.Preference;
  1318. +import androidx.preference.PreferenceViewHolder;
  1319. +import androidx.recyclerview.widget.DividerItemDecoration;
  1320. +import androidx.recyclerview.widget.LinearLayoutManager;
  1321. +import androidx.recyclerview.widget.RecyclerView;
  1322. +import androidx.recyclerview.widget.RecyclerView.ViewHolder;
  1323. +
  1324. +import org.chromium.ui.base.WindowAndroid;
  1325. +import org.chromium.ui.base.ActivityWindowAndroid;
  1326. +
  1327. +import org.chromium.base.ApplicationStatus;
  1328. +import org.chromium.base.ContextUtils;
  1329. +import org.chromium.components.browser_ui.widget.TintedDrawable;
  1330. +import org.chromium.components.browser_ui.widget.listmenu.BasicListMenu;
  1331. +import org.chromium.components.browser_ui.widget.listmenu.ListMenu;
  1332. +import org.chromium.components.browser_ui.widget.listmenu.ListMenuItemProperties;
  1333. +import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
  1334. +
  1335. +import org.chromium.components.user_scripts.ScriptListBaseAdapter;
  1336. +import org.chromium.components.user_scripts.FragmentWindowAndroid;
  1337. +
  1338. +public class ScriptListPreference extends Preference {
  1339. + private static class ScriptListAdapter
  1340. + extends ScriptListBaseAdapter {
  1341. + private final Context mContext;
  1342. +
  1343. + ScriptListAdapter(Context context) {
  1344. + super(context);
  1345. + mContext = context;
  1346. + }
  1347. +
  1348. + @Override
  1349. + public void onBindViewHolder(ViewHolder holder, int position) {
  1350. + super.onBindViewHolder(holder, position);
  1351. +
  1352. + final ScriptInfo info = getItemByPosition(position);
  1353. +
  1354. + showDragIndicatorInRow((ScriptInfoRowViewHolder) holder);
  1355. + ModelList menuItems = new ModelList();
  1356. +
  1357. + menuItems.add(buildMenuListItem(R.string.remove, 0, 0, true));
  1358. + menuItems.add(buildMenuListItem(R.string.scripts_open_url, 0, 0, info.UrlSource != null &&
  1359. + info.UrlSource.isEmpty() == false));
  1360. + menuItems.add(buildMenuListItem(R.string.scripts_view_source, 0, 0, true));
  1361. +
  1362. + ListMenu.Delegate delegate = (model) -> {
  1363. + int textId = model.get(ListMenuItemProperties.TITLE_ID);
  1364. + if (textId == R.string.remove) {
  1365. + UserScriptsBridge.RemoveScript(info.Key);
  1366. + } else if (textId == R.string.scripts_view_source) {
  1367. + UserScriptsBridge.getUtils().openSourceFile(info.Key);
  1368. + } else if (textId == R.string.scripts_open_url) {
  1369. + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(info.UrlSource));
  1370. + intent.putExtra(Browser.EXTRA_APPLICATION_ID, mContext.getPackageName());
  1371. + intent.putExtra(Browser.EXTRA_CREATE_NEW_TAB, true);
  1372. + intent.setPackage(mContext.getPackageName());
  1373. + mContext.startActivity(intent);
  1374. + }
  1375. + };
  1376. + ((ScriptInfoRowViewHolder) holder)
  1377. + .setMenuButtonDelegate(() -> new BasicListMenu(mContext, menuItems, delegate));
  1378. + ((ScriptInfoRowViewHolder) holder)
  1379. + .setItemListener(new ScriptListBaseAdapter.ItemClickListener() {
  1380. + @Override
  1381. + public void onScriptOnOff(boolean Enabled) {
  1382. + UserScriptsBridge.SetScriptEnabled(info.Key, Enabled);
  1383. + }
  1384. +
  1385. + @Override
  1386. + public void onScriptClicked() {}
  1387. + });
  1388. + }
  1389. +
  1390. + // @Override
  1391. + public void onDataUpdated() {
  1392. + if (mDragStateDelegate.getDragActive()) {
  1393. + enableDrag();
  1394. + } else {
  1395. + disableDrag();
  1396. + }
  1397. + setDisplayedScriptInfo(UserScriptsBridge.getUserScriptItems());
  1398. + }
  1399. + }
  1400. +
  1401. + private TextView mAddButton;
  1402. + private RecyclerView mRecyclerView;
  1403. + private ScriptListAdapter mAdapter;
  1404. + private FragmentWindowAndroid mWindowAndroid;
  1405. +
  1406. + public ScriptListPreference(Context context, AttributeSet attrs) {
  1407. + super(context, attrs);
  1408. + mAdapter = new ScriptListAdapter(context);
  1409. + }
  1410. +
  1411. + public void setWindowAndroid(FragmentWindowAndroid windowAndroid) {
  1412. + mWindowAndroid = windowAndroid;
  1413. + }
  1414. +
  1415. + @Override
  1416. + public void onBindViewHolder(PreferenceViewHolder holder) {
  1417. + super.onBindViewHolder(holder);
  1418. +
  1419. + mAddButton = (TextView) holder.findViewById(R.id.add_script);
  1420. + mAddButton.setCompoundDrawablesRelativeWithIntrinsicBounds(
  1421. + TintedDrawable.constructTintedDrawable(
  1422. + getContext(), R.drawable.plus, R.color.default_control_color_active),
  1423. + null, null, null);
  1424. + mAddButton.setOnClickListener(view -> {
  1425. + UserScriptsBridge.SelectAndAddScriptFromFile(mWindowAndroid);
  1426. + });
  1427. +
  1428. + mRecyclerView = (RecyclerView) holder.findViewById(R.id.script_list);
  1429. + LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());
  1430. + mRecyclerView.setLayoutManager(layoutManager);
  1431. + mRecyclerView.addItemDecoration(
  1432. + new DividerItemDecoration(getContext(), layoutManager.getOrientation()));
  1433. +
  1434. + UserScriptsBridge.RegisterLoadCallback(this);
  1435. +
  1436. + // We do not want the RecyclerView to be announced by screen readers every time
  1437. + // the view is bound.
  1438. + if (mRecyclerView.getAdapter() != mAdapter) {
  1439. + mRecyclerView.setAdapter(mAdapter);
  1440. + // Initialize script list.
  1441. + mAdapter.onDataUpdated();
  1442. + }
  1443. + }
  1444. +
  1445. + public void NotifyScriptsChanged() {
  1446. + mAdapter.onDataUpdated();
  1447. + }
  1448. +
  1449. + public void OnUserScriptLoaded(boolean result, String error) {
  1450. + if (result == false) {
  1451. + Toast toast = Toast.makeText(getContext(), error, Toast.LENGTH_LONG);
  1452. + toast.show();
  1453. + }
  1454. + }
  1455. +}
  1456. \ No newline at end of file
  1457. 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
  1458. new file mode 100644
  1459. --- /dev/null
  1460. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/UserScriptsBridge.java
  1461. @@ -0,0 +1,178 @@
  1462. +/*
  1463. + This file is part of Bromite.
  1464. +
  1465. + Bromite is free software: you can redistribute it and/or modify
  1466. + it under the terms of the GNU General Public License as published by
  1467. + the Free Software Foundation, either version 3 of the License, or
  1468. + (at your option) any later version.
  1469. +
  1470. + Bromite is distributed in the hope that it will be useful,
  1471. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1472. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1473. + GNU General Public License for more details.
  1474. +
  1475. + You should have received a copy of the GNU General Public License
  1476. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1477. +*/
  1478. +
  1479. +package org.chromium.components.user_scripts;
  1480. +
  1481. +import java.util.ArrayList;
  1482. +import java.util.List;
  1483. +import java.lang.ref.WeakReference;
  1484. +
  1485. +import org.json.JSONArray;
  1486. +import org.json.JSONException;
  1487. +import org.json.JSONObject;
  1488. +
  1489. +import android.content.Context;
  1490. +import android.content.Intent;
  1491. +import android.net.Uri;
  1492. +import androidx.annotation.Nullable;
  1493. +
  1494. +import org.chromium.base.annotations.CalledByNative;
  1495. +import org.chromium.base.annotations.JNINamespace;
  1496. +import org.chromium.base.annotations.NativeMethods;
  1497. +import org.chromium.base.Log;
  1498. +import org.chromium.ui.base.WindowAndroid;
  1499. +
  1500. +import org.chromium.components.user_scripts.ScriptListPreference;
  1501. +import org.chromium.components.user_scripts.IUserScriptsUtils;
  1502. +
  1503. +@JNINamespace("user_scripts")
  1504. +public class UserScriptsBridge {
  1505. + static WeakReference<ScriptListPreference> observer;
  1506. +
  1507. + private static IUserScriptsUtils utilInstance;
  1508. +
  1509. + public static void registerUtils(IUserScriptsUtils instance) {
  1510. + utilInstance = instance;
  1511. + }
  1512. +
  1513. + public static IUserScriptsUtils getUtils() {
  1514. + return utilInstance;
  1515. + }
  1516. +
  1517. + public static boolean isFeatureEnabled() {
  1518. + return UserScriptsBridgeJni.get().isFeatureEnabled();
  1519. + }
  1520. +
  1521. + public static boolean isUserEnabled() {
  1522. + return UserScriptsBridgeJni.get().isUserEnabled();
  1523. + }
  1524. +
  1525. + public static void setUserEnabled(boolean enabled) {
  1526. + UserScriptsBridgeJni.get().setUserEnabled(enabled);
  1527. + }
  1528. +
  1529. + public static void RemoveScript(String key) {
  1530. + UserScriptsBridgeJni.get().removeScript(key);
  1531. + }
  1532. +
  1533. + public static void SetScriptEnabled(String key,
  1534. + boolean enabled) {
  1535. + UserScriptsBridgeJni.get().setScriptEnabled(key, enabled);
  1536. + }
  1537. +
  1538. + public static void Reload() {
  1539. + UserScriptsBridgeJni.get().reload();
  1540. + }
  1541. +
  1542. + public static void SelectAndAddScriptFromFile(WindowAndroid window) {
  1543. + Context context = window.getContext().get();
  1544. +
  1545. + Intent fileSelector = new Intent(Intent.ACTION_OPEN_DOCUMENT);
  1546. + fileSelector.addCategory(Intent.CATEGORY_OPENABLE);
  1547. + fileSelector.setType("*/*");
  1548. + fileSelector.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
  1549. +
  1550. + window.showIntent(fileSelector,
  1551. + new WindowAndroid.IntentCallback() {
  1552. + @Override
  1553. + public void onIntentCompleted(WindowAndroid window, int resultCode, Intent data) {
  1554. + if (data == null) return;
  1555. + Uri filePath = data.getData();
  1556. + UserScriptsBridgeJni.get().tryToInstall(filePath.toString());
  1557. + }
  1558. + },
  1559. + null);
  1560. + }
  1561. +
  1562. + public static void TryToInstall(String ScriptFullPath) {
  1563. + UserScriptsBridgeJni.get().tryToInstall(ScriptFullPath);
  1564. + }
  1565. +
  1566. + public static List<ScriptInfo> getUserScriptItems() {
  1567. + List<ScriptInfo> list = new ArrayList<>();
  1568. + try {
  1569. + String json = UserScriptsBridgeJni.get().getScriptsInfo();
  1570. +
  1571. + JSONObject jsonObject = new JSONObject(json);
  1572. +
  1573. + JSONArray scripts = jsonObject.names();
  1574. + if (scripts != null) {
  1575. + Log.i("User Scripts Loaded", json);
  1576. + Log.i("Totals scripts", Integer.toString(scripts.length()));
  1577. + for (int i = 0; i < scripts.length(); i++) {
  1578. + String key = (String) scripts.get(i);
  1579. + JSONObject script = jsonObject.getJSONObject(key);
  1580. +
  1581. + ScriptInfo si = new ScriptInfo();
  1582. + si.Key = key;
  1583. + list.add(si);
  1584. +
  1585. + if(script.has("name")) si.Name = script.getString("name");
  1586. + if(script.has("description")) si.Description = script.getString("description");
  1587. + if(script.has("version")) si.Version = script.getString("version");
  1588. + if(script.has("file_path")) si.FilePath = script.getString("file_path");
  1589. + if(script.has("url_source")) si.UrlSource = script.getString("url_source");
  1590. + si.Enabled = script.getBoolean("enabled");
  1591. + }
  1592. + }
  1593. + } catch (Exception e) {
  1594. + Log.e("User Scripts Load Error", e.toString());
  1595. + }
  1596. + return list;
  1597. + }
  1598. +
  1599. + public static void RegisterLoadCallback(ScriptListPreference caller) {
  1600. + UserScriptsBridgeJni.get().registerLoadCallback();
  1601. + observer = new WeakReference<ScriptListPreference>(caller);
  1602. + }
  1603. +
  1604. + @CalledByNative
  1605. + private static void shouldRefreshUserScriptList() {
  1606. + ScriptListPreference reference = observer.get();
  1607. + if (reference != null) {
  1608. + reference.NotifyScriptsChanged();
  1609. + }
  1610. + }
  1611. +
  1612. + @CalledByNative
  1613. + private static void onUserScriptLoaded(boolean result, String error) {
  1614. + ScriptListPreference reference = observer.get();
  1615. + if (reference != null) {
  1616. + reference.OnUserScriptLoaded(result, error);
  1617. + }
  1618. + }
  1619. +
  1620. + @NativeMethods
  1621. + interface Natives {
  1622. + boolean isFeatureEnabled();
  1623. +
  1624. + boolean isUserEnabled();
  1625. + void setUserEnabled(boolean enabled);
  1626. +
  1627. + String getScriptsInfo();
  1628. +
  1629. + void removeScript(String scriptKey);
  1630. + void setScriptEnabled(String scriptKey, boolean enabled);
  1631. +
  1632. + void reload();
  1633. + void selectAndAddScriptFromFile(WindowAndroid window);
  1634. + void tryToInstall(String scriptFullPath);
  1635. +
  1636. + void registerLoadCallback();
  1637. + }
  1638. +
  1639. +}
  1640. \ No newline at end of file
  1641. 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
  1642. new file mode 100755
  1643. --- /dev/null
  1644. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/UserScriptsPreferences.java
  1645. @@ -0,0 +1,144 @@
  1646. +/*
  1647. + This file is part of Bromite.
  1648. +
  1649. + Bromite is free software: you can redistribute it and/or modify
  1650. + it under the terms of the GNU General Public License as published by
  1651. + the Free Software Foundation, either version 3 of the License, or
  1652. + (at your option) any later version.
  1653. +
  1654. + Bromite is distributed in the hope that it will be useful,
  1655. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1656. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1657. + GNU General Public License for more details.
  1658. +
  1659. + You should have received a copy of the GNU General Public License
  1660. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1661. +*/
  1662. +
  1663. +package org.chromium.components.user_scripts;
  1664. +
  1665. +import android.app.Activity;
  1666. +import android.app.AlertDialog;
  1667. +import android.content.Context;
  1668. +import android.content.Intent;
  1669. +import android.content.DialogInterface;
  1670. +import android.os.Bundle;
  1671. +import android.provider.Browser;
  1672. +import android.net.Uri;
  1673. +import android.view.MenuItem;
  1674. +import android.view.View;
  1675. +
  1676. +import androidx.preference.Preference;
  1677. +import androidx.preference.PreferenceFragmentCompat;
  1678. +
  1679. +import org.chromium.base.Log;
  1680. +import org.chromium.ui.base.WindowAndroid;
  1681. +import org.chromium.ui.base.ActivityWindowAndroid;
  1682. +
  1683. +import org.chromium.components.browser_ui.settings.ChromeSwitchPreference;
  1684. +import org.chromium.components.browser_ui.settings.SettingsUtils;
  1685. +import org.chromium.components.browser_ui.settings.TextMessagePreference;
  1686. +
  1687. +import org.chromium.components.user_scripts.UserScriptsBridge;
  1688. +import org.chromium.components.user_scripts.FragmentWindowAndroid;
  1689. +
  1690. +public class UserScriptsPreferences
  1691. + extends PreferenceFragmentCompat
  1692. + implements SettingsUtils.ISupportHelpAndFeedback {
  1693. +
  1694. + private static final String PREF_ENABLED_SWITCH = "enabled_switch";
  1695. + private static final String PREF_SCRIPTLISTPREFERENCE = "script_list";
  1696. + private static final String PREF_SCRIPTS_DISABLED_DESCRIPTION = "scripts_disabled_description";
  1697. +
  1698. + public static final String EXTRA_SCRIPT_FILE = "org.chromium.chrome.preferences.script_file";
  1699. +
  1700. + private FragmentWindowAndroid mwindowAndroid;
  1701. +
  1702. + @Override
  1703. + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
  1704. + getActivity().setTitle(R.string.prefs_userscripts_settings);
  1705. + SettingsUtils.addPreferencesFromResource(this, R.xml.userscripts_preferences);
  1706. +
  1707. + ChromeSwitchPreference enabledSwitch =
  1708. + (ChromeSwitchPreference) findPreference(PREF_ENABLED_SWITCH);
  1709. + ScriptListPreference listPreference =
  1710. + (ScriptListPreference) findPreference(PREF_SCRIPTLISTPREFERENCE);
  1711. +
  1712. + boolean enabled = UserScriptsBridge.isUserEnabled();
  1713. + enabledSwitch.setChecked(enabled);
  1714. + listPreference.setEnabled(enabled);
  1715. + enabledSwitch.setOnPreferenceChangeListener((preference, newValue) -> {
  1716. + UserScriptsBridge.setUserEnabled((boolean) newValue);
  1717. + listPreference.setEnabled((boolean) newValue);
  1718. + return true;
  1719. + });
  1720. +
  1721. + mwindowAndroid = new FragmentWindowAndroid(getContext(), this);
  1722. + listPreference.setWindowAndroid(mwindowAndroid);
  1723. +
  1724. + if (UserScriptsBridge.isFeatureEnabled() == false) {
  1725. + enabledSwitch.setEnabled(false);
  1726. + listPreference.setEnabled(false);
  1727. +
  1728. + TextMessagePreference scripts_disabled_description =
  1729. + (TextMessagePreference) findPreference(PREF_SCRIPTS_DISABLED_DESCRIPTION);
  1730. + scripts_disabled_description.setVisible(true);
  1731. + }
  1732. + }
  1733. +
  1734. + @Override
  1735. + public void onActivityResult(int requestCode, int resultCode, Intent data) {
  1736. + // handle picker callback from SelectFileDialog
  1737. + mwindowAndroid.onActivityResult(requestCode, resultCode, data);
  1738. + }
  1739. +
  1740. + public void onHelpAndFeebackPressed() {
  1741. + Context context = getContext();
  1742. +
  1743. + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/bromite/bromite/wiki/UserScripts"));
  1744. + // Let Chromium know that this intent is from Chromium, so that it does not close the app when
  1745. + // the user presses 'back' button.
  1746. + intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
  1747. + intent.putExtra(Browser.EXTRA_CREATE_NEW_TAB, true);
  1748. + intent.setPackage(context.getPackageName());
  1749. + context.startActivity(intent);
  1750. + }
  1751. +
  1752. + public static Bundle createFragmentArgsForInstall(String filePath) {
  1753. + Bundle fragmentArgs = new Bundle();
  1754. + fragmentArgs.putSerializable(EXTRA_SCRIPT_FILE, filePath);
  1755. + return fragmentArgs;
  1756. + }
  1757. +
  1758. + @Override
  1759. + public void onActivityCreated(Bundle savedInstanceState) {
  1760. + super.onActivityCreated(savedInstanceState);
  1761. +
  1762. + String scriptToInstall = (String)getArguments().getSerializable(EXTRA_SCRIPT_FILE);
  1763. + if (scriptToInstall != null) {
  1764. + DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
  1765. + @Override
  1766. + public void onClick(DialogInterface dialog, int which) {
  1767. + switch (which){
  1768. + case DialogInterface.BUTTON_POSITIVE:
  1769. + UserScriptsBridge.TryToInstall(scriptToInstall);
  1770. + break;
  1771. +
  1772. + case DialogInterface.BUTTON_NEGATIVE:
  1773. + break;
  1774. + }
  1775. + }
  1776. + };
  1777. +
  1778. + Context context = getContext();
  1779. + String message = context.getString(R.string.ask_to_install) + " " +
  1780. + scriptToInstall;
  1781. +
  1782. + AlertDialog.Builder builder = new AlertDialog.Builder(context);
  1783. + builder.setMessage(message)
  1784. + .setPositiveButton(context.getString(R.string.yes), dialogClickListener)
  1785. + .setNegativeButton(context.getString(R.string.no), dialogClickListener)
  1786. + .show();
  1787. + }
  1788. + }
  1789. +}
  1790. diff --git a/components/user_scripts/android/java_sources.gni b/components/user_scripts/android/java_sources.gni
  1791. new file mode 100644
  1792. --- /dev/null
  1793. +++ b/components/user_scripts/android/java_sources.gni
  1794. @@ -0,0 +1,18 @@
  1795. +# This file is part of Bromite.
  1796. +
  1797. +# Bromite is free software: you can redistribute it and/or modify
  1798. +# it under the terms of the GNU General Public License as published by
  1799. +# the Free Software Foundation, either version 3 of the License, or
  1800. +# (at your option) any later version.
  1801. +
  1802. +# Bromite is distributed in the hope that it will be useful,
  1803. +# but WITHOUT ANY WARRANTY; without even the implied warranty of
  1804. +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1805. +# GNU General Public License for more details.
  1806. +
  1807. +# You should have received a copy of the GNU General Public License
  1808. +# along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1809. +
  1810. +userscripts_java_sources = [
  1811. + "//components/user_scripts/android/java/src/org/chromium/chrome/browser/user_scripts/UserScriptsUtils.java",
  1812. +]
  1813. diff --git a/components/user_scripts/android/user_scripts_bridge.cc b/components/user_scripts/android/user_scripts_bridge.cc
  1814. new file mode 100644
  1815. --- /dev/null
  1816. +++ b/components/user_scripts/android/user_scripts_bridge.cc
  1817. @@ -0,0 +1,179 @@
  1818. +/*
  1819. + This file is part of Bromite.
  1820. +
  1821. + Bromite is free software: you can redistribute it and/or modify
  1822. + it under the terms of the GNU General Public License as published by
  1823. + the Free Software Foundation, either version 3 of the License, or
  1824. + (at your option) any later version.
  1825. +
  1826. + Bromite is distributed in the hope that it will be useful,
  1827. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1828. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1829. + GNU General Public License for more details.
  1830. +
  1831. + You should have received a copy of the GNU General Public License
  1832. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1833. +*/
  1834. +
  1835. +#include <jni.h>
  1836. +#include <algorithm>
  1837. +#include <string>
  1838. +#include <vector>
  1839. +#include <sstream>
  1840. +#include <iterator>
  1841. +
  1842. +#include "base/android/callback_android.h"
  1843. +#include "base/android/jni_android.h"
  1844. +#include "base/android/jni_array.h"
  1845. +#include "base/android/jni_string.h"
  1846. +#include "base/android/scoped_java_ref.h"
  1847. +#include "components/embedder_support/android/browser_context/browser_context_handle.h"
  1848. +#include "ui/android/window_android.h"
  1849. +
  1850. +#include "components/user_scripts/android/user_scripts_jni_headers/UserScriptsBridge_jni.h"
  1851. +#include "../browser/userscripts_browser_client.h"
  1852. +#include "user_scripts_bridge.h"
  1853. +
  1854. +using base::android::AttachCurrentThread;
  1855. +using base::android::ConvertJavaStringToUTF8;
  1856. +using base::android::ConvertUTF16ToJavaString;
  1857. +using base::android::ConvertUTF8ToJavaString;
  1858. +using base::android::JavaParamRef;
  1859. +using base::android::JavaRef;
  1860. +using base::android::ScopedJavaGlobalRef;
  1861. +using base::android::ScopedJavaLocalRef;
  1862. +using content::BrowserContext;
  1863. +
  1864. +namespace {
  1865. +
  1866. +user_scripts::UserScriptsBrowserClient* GetUserScriptsBrowserClient() {
  1867. + return user_scripts::UserScriptsBrowserClient::GetInstance();
  1868. +}
  1869. +
  1870. +class CallbackObserver : public user_scripts::UserScriptLoader::Observer {
  1871. + private:
  1872. + void OnScriptsLoaded(user_scripts::UserScriptLoader* loader,
  1873. + content::BrowserContext* browser_context) override {
  1874. + user_scripts::ShouldRefreshUserScriptList(base::android::AttachCurrentThread());
  1875. + }
  1876. +
  1877. + void OnUserScriptLoaded(user_scripts::UserScriptLoader* loader,
  1878. + bool result, const std::string& error) override {
  1879. + user_scripts::OnUserScriptLoaded(base::android::AttachCurrentThread(),
  1880. + result, error);
  1881. + }
  1882. +
  1883. + void OnUserScriptLoaderDestroyed(user_scripts::UserScriptLoader* loader) override {}
  1884. +};
  1885. +
  1886. +CallbackObserver* g_userscripts_loader_observer = NULL;
  1887. +
  1888. +}
  1889. +
  1890. +namespace user_scripts {
  1891. +
  1892. +static jboolean JNI_UserScriptsBridge_IsFeatureEnabled(
  1893. + JNIEnv* env) {
  1894. + return GetUserScriptsBrowserClient() != NULL;
  1895. +}
  1896. +
  1897. +static jboolean JNI_UserScriptsBridge_IsUserEnabled(
  1898. + JNIEnv* env) {
  1899. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  1900. + if (client == NULL) return false;
  1901. + return client->GetPrefs()->IsEnabled();
  1902. +}
  1903. +
  1904. +static void JNI_UserScriptsBridge_SetUserEnabled(
  1905. + JNIEnv* env,
  1906. + jboolean is_enabled) {
  1907. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  1908. + if (client == NULL) return;
  1909. + client->GetPrefs()->SetEnabled(is_enabled);
  1910. + client->GetLoader()->StartLoad();
  1911. +}
  1912. +
  1913. +static base::android::ScopedJavaLocalRef<jstring> JNI_UserScriptsBridge_GetScriptsInfo(
  1914. + JNIEnv* env) {
  1915. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  1916. + if (client == NULL) return ConvertUTF8ToJavaString(env, {});
  1917. +
  1918. + std::string json = client->GetPrefs()->GetScriptsInfo();
  1919. + return ConvertUTF8ToJavaString(env, json);
  1920. +}
  1921. +
  1922. +static void JNI_UserScriptsBridge_RemoveScript(
  1923. + JNIEnv* env,
  1924. + const JavaParamRef<jstring>& jscript_key) {
  1925. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  1926. + if (client == NULL) return;
  1927. +
  1928. + std::string script_key = base::android::ConvertJavaStringToUTF8(jscript_key);
  1929. + client->GetLoader()->RemoveScript(script_key);
  1930. +}
  1931. +
  1932. +static void JNI_UserScriptsBridge_SetScriptEnabled(
  1933. + JNIEnv* env,
  1934. + const JavaParamRef<jstring>& jscript_key,
  1935. + jboolean is_enabled) {
  1936. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  1937. + if (client == NULL) return;
  1938. +
  1939. + std::string script_key = base::android::ConvertJavaStringToUTF8(jscript_key);
  1940. + client->GetLoader()->SetScriptEnabled(script_key, is_enabled);
  1941. +}
  1942. +
  1943. +static void JNI_UserScriptsBridge_Reload(
  1944. + JNIEnv* env) {
  1945. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  1946. + if (client == NULL) return;
  1947. +
  1948. + client->GetLoader()->StartLoad();
  1949. + user_scripts::ShouldRefreshUserScriptList(env);
  1950. +}
  1951. +
  1952. +static void JNI_UserScriptsBridge_SelectAndAddScriptFromFile(
  1953. + JNIEnv* env,
  1954. + const JavaParamRef<jobject>& jwindow_android) {
  1955. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  1956. + if (client == NULL) return;
  1957. +
  1958. + client->GetLoader()->SelectAndAddScriptFromFile(
  1959. + ui::WindowAndroid::FromJavaWindowAndroid(jwindow_android));
  1960. +}
  1961. +
  1962. +static void JNI_UserScriptsBridge_TryToInstall(JNIEnv* env,
  1963. + const JavaParamRef<jstring>& jscript_path) {
  1964. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  1965. + if (client == NULL) return;
  1966. +
  1967. + std::string script_path = base::android::ConvertJavaStringToUTF8(jscript_path);
  1968. + base::FilePath path(script_path);
  1969. +
  1970. + client->GetLoader()->TryToInstall(path);
  1971. +}
  1972. +
  1973. +static void JNI_UserScriptsBridge_RegisterLoadCallback(
  1974. + JNIEnv* env) {
  1975. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  1976. + if (client == NULL) return;
  1977. +
  1978. + if( g_userscripts_loader_observer == NULL ) {
  1979. + g_userscripts_loader_observer = new CallbackObserver();
  1980. + client->GetLoader()->AddObserver(g_userscripts_loader_observer);
  1981. + }
  1982. +}
  1983. +
  1984. +static void ShouldRefreshUserScriptList(JNIEnv* env) {
  1985. + Java_UserScriptsBridge_shouldRefreshUserScriptList(env);
  1986. +}
  1987. +
  1988. +static void OnUserScriptLoaded(JNIEnv* env,
  1989. + bool result, const std::string& error) {
  1990. + base::android::ScopedJavaLocalRef<jstring> j_error =
  1991. + base::android::ConvertUTF8ToJavaString(env, error);
  1992. +
  1993. + Java_UserScriptsBridge_onUserScriptLoaded(env, result, j_error);
  1994. +}
  1995. +
  1996. +}
  1997. \ No newline at end of file
  1998. diff --git a/components/user_scripts/android/user_scripts_bridge.h b/components/user_scripts/android/user_scripts_bridge.h
  1999. new file mode 100644
  2000. --- /dev/null
  2001. +++ b/components/user_scripts/android/user_scripts_bridge.h
  2002. @@ -0,0 +1,31 @@
  2003. +/*
  2004. + This file is part of Bromite.
  2005. +
  2006. + Bromite is free software: you can redistribute it and/or modify
  2007. + it under the terms of the GNU General Public License as published by
  2008. + the Free Software Foundation, either version 3 of the License, or
  2009. + (at your option) any later version.
  2010. +
  2011. + Bromite is distributed in the hope that it will be useful,
  2012. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2013. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2014. + GNU General Public License for more details.
  2015. +
  2016. + You should have received a copy of the GNU General Public License
  2017. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2018. +*/
  2019. +
  2020. +#ifndef COMPONENTS_USERSCRIPS_HELPER_ANDROID_H_
  2021. +#define COMPONENTS_USERSCRIPS_HELPER_ANDROID_H_
  2022. +
  2023. +#include <jni.h>
  2024. +
  2025. +namespace user_scripts {
  2026. +
  2027. +static void ShouldRefreshUserScriptList(JNIEnv* env);
  2028. +static void OnUserScriptLoaded(JNIEnv* env,
  2029. + bool result, const std::string& error);
  2030. +
  2031. +} // namespace user_scripts
  2032. +
  2033. +#endif
  2034. \ No newline at end of file
  2035. diff --git a/components/user_scripts/browser/BUILD.gn b/components/user_scripts/browser/BUILD.gn
  2036. new file mode 100755
  2037. --- /dev/null
  2038. +++ b/components/user_scripts/browser/BUILD.gn
  2039. @@ -0,0 +1,91 @@
  2040. +# This file is part of Bromite.
  2041. +
  2042. +# Bromite is free software: you can redistribute it and/or modify
  2043. +# it under the terms of the GNU General Public License as published by
  2044. +# the Free Software Foundation, either version 3 of the License, or
  2045. +# (at your option) any later version.
  2046. +
  2047. +# Bromite is distributed in the hope that it will be useful,
  2048. +# but WITHOUT ANY WARRANTY; without even the implied warranty of
  2049. +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2050. +# GNU General Public License for more details.
  2051. +
  2052. +# You should have received a copy of the GNU General Public License
  2053. +# along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2054. +
  2055. +import("//build/config/features.gni")
  2056. +import("//tools/grit/grit_rule.gni")
  2057. +
  2058. +group("browser") {
  2059. + public_deps = [
  2060. + "//components/user_scripts/browser:browser_sources",
  2061. + ]
  2062. +}
  2063. +
  2064. +source_set("browser_sources") {
  2065. + visibility = [ "./*" ]
  2066. +
  2067. + sources = [
  2068. + "file_task_runner.cc",
  2069. + "file_task_runner.h",
  2070. + "userscripts_browser_client.cc",
  2071. + "userscripts_browser_client.h",
  2072. + "user_script_loader.cc",
  2073. + "user_script_loader.h",
  2074. + "user_script_prefs.cc",
  2075. + "user_script_prefs.h",
  2076. + "user_script_pref_info.cc",
  2077. + "user_script_pref_info.h",
  2078. + "ui/user_scripts_ui.h",
  2079. + "ui/user_scripts_ui.cc",
  2080. + ]
  2081. +
  2082. + deps = [
  2083. + ":userscripts_browser_resources",
  2084. + "//base:i18n",
  2085. + "//components/keyed_service/content",
  2086. + "//components/keyed_service/core",
  2087. + "//components/pref_registry",
  2088. + "//components/prefs",
  2089. + "//content/public/browser",
  2090. + "//crypto:platform",
  2091. + "//components/user_scripts/common",
  2092. + "//services/device/public/mojom",
  2093. + "//services/preferences/public/cpp",
  2094. + "//services/service_manager/public/cpp",
  2095. + "//third_party/blink/public/common",
  2096. + "//third_party/blink/public/mojom/frame",
  2097. + "//ui/display",
  2098. + ]
  2099. +
  2100. + public_deps = [
  2101. + "//content/public/common",
  2102. + ]
  2103. +
  2104. + configs += [
  2105. + "//build/config:precompiled_headers",
  2106. +
  2107. + # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
  2108. + "//build/config/compiler:no_size_t_to_int_warning",
  2109. + "//build/config/compiler:wexit_time_destructors",
  2110. + ]
  2111. +}
  2112. +
  2113. +group("closure_compile") {
  2114. + deps = [ "resources/user-script-ui:closure_compile" ]
  2115. +}
  2116. +
  2117. +grit("userscripts_browser_resources") {
  2118. + source = "resources/browser_resources.grd"
  2119. +
  2120. + output_dir = "$root_gen_dir/chrome"
  2121. + outputs = [
  2122. + "grit/userscripts_browser_resources.h",
  2123. + "userscripts_browser_resources.pak",
  2124. + ]
  2125. +
  2126. + deps = [
  2127. + "//chrome/browser/resources/web_app_internals:components",
  2128. + "//chrome/browser/ui/webui/internals/web_app:mojo_bindings_js",
  2129. + ]
  2130. +}
  2131. diff --git a/components/user_scripts/browser/file_task_runner.cc b/components/user_scripts/browser/file_task_runner.cc
  2132. new file mode 100755
  2133. --- /dev/null
  2134. +++ b/components/user_scripts/browser/file_task_runner.cc
  2135. @@ -0,0 +1,40 @@
  2136. +/*
  2137. + This file is part of Bromite.
  2138. +
  2139. + Bromite is free software: you can redistribute it and/or modify
  2140. + it under the terms of the GNU General Public License as published by
  2141. + the Free Software Foundation, either version 3 of the License, or
  2142. + (at your option) any later version.
  2143. +
  2144. + Bromite is distributed in the hope that it will be useful,
  2145. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2146. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2147. + GNU General Public License for more details.
  2148. +
  2149. + You should have received a copy of the GNU General Public License
  2150. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2151. +*/
  2152. +
  2153. +#include "file_task_runner.h"
  2154. +
  2155. +#include "base/sequenced_task_runner.h"
  2156. +#include "base/task/lazy_thread_pool_task_runner.h"
  2157. +#include "base/task/task_traits.h"
  2158. +
  2159. +namespace user_scripts {
  2160. +
  2161. +namespace {
  2162. +
  2163. +base::LazyThreadPoolSequencedTaskRunner g_us_task_runner =
  2164. + LAZY_THREAD_POOL_SEQUENCED_TASK_RUNNER_INITIALIZER(
  2165. + base::TaskTraits(base::MayBlock(),
  2166. + base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN,
  2167. + base::TaskPriority::USER_VISIBLE));
  2168. +
  2169. +} // namespace
  2170. +
  2171. +scoped_refptr<base::SequencedTaskRunner> GetUserScriptsFileTaskRunner() {
  2172. + return g_us_task_runner.Get();
  2173. +}
  2174. +
  2175. +} // namespace user_scripts
  2176. diff --git a/components/user_scripts/browser/file_task_runner.h b/components/user_scripts/browser/file_task_runner.h
  2177. new file mode 100755
  2178. --- /dev/null
  2179. +++ b/components/user_scripts/browser/file_task_runner.h
  2180. @@ -0,0 +1,34 @@
  2181. +/*
  2182. + This file is part of Bromite.
  2183. +
  2184. + Bromite is free software: you can redistribute it and/or modify
  2185. + it under the terms of the GNU General Public License as published by
  2186. + the Free Software Foundation, either version 3 of the License, or
  2187. + (at your option) any later version.
  2188. +
  2189. + Bromite is distributed in the hope that it will be useful,
  2190. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2191. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2192. + GNU General Public License for more details.
  2193. +
  2194. + You should have received a copy of the GNU General Public License
  2195. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2196. +*/
  2197. +
  2198. +#ifndef USERSCRIPTS_BROWSER_FILE_TASK_RUNNER_H_
  2199. +#define USERSCRIPTS_BROWSER_FILE_TASK_RUNNER_H_
  2200. +
  2201. +#include "base/memory/ref_counted.h"
  2202. +#include "base/task/task_traits.h"
  2203. +
  2204. +namespace base {
  2205. +class SequencedTaskRunner;
  2206. +}
  2207. +
  2208. +namespace user_scripts {
  2209. +
  2210. +scoped_refptr<base::SequencedTaskRunner> GetUserScriptsFileTaskRunner();
  2211. +
  2212. +} // namespace extensions
  2213. +
  2214. +#endif // USERSCRIPTS_BROWSER_FILE_TASK_RUNNER_H_
  2215. diff --git a/components/user_scripts/browser/resources/browser_resources.grd b/components/user_scripts/browser/resources/browser_resources.grd
  2216. new file mode 100644
  2217. --- /dev/null
  2218. +++ b/components/user_scripts/browser/resources/browser_resources.grd
  2219. @@ -0,0 +1,14 @@
  2220. +<grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
  2221. + <outputs>
  2222. + <output filename="grit/userscripts_browser_resources.h" type="rc_header">
  2223. + <emit emit_type='prepend'></emit>
  2224. + </output>
  2225. + <output filename="userscripts_browser_resources.pak" type="data_package" />
  2226. + </outputs>
  2227. + <release seq="1">
  2228. + <includes>
  2229. + <include name="IDR_USER_SCRIPTS_HTML" file="user-script-ui\user-scripts-ui.html" type="BINDATA" />
  2230. + <include name="IDR_USER_SCRIPTS_JS" file="user-script-ui\user-scripts-ui.js" type="BINDATA" />
  2231. + </includes>
  2232. + </release>
  2233. +</grit>
  2234. \ No newline at end of file
  2235. diff --git a/components/user_scripts/browser/resources/user-script-ui/BUILD.gn b/components/user_scripts/browser/resources/user-script-ui/BUILD.gn
  2236. new file mode 100644
  2237. --- /dev/null
  2238. +++ b/components/user_scripts/browser/resources/user-script-ui/BUILD.gn
  2239. @@ -0,0 +1,12 @@
  2240. +import("//third_party/closure_compiler/compile_js.gni")
  2241. +
  2242. +js_type_check("closure_compile") {
  2243. + deps = [ ":view_script_source" ]
  2244. +}
  2245. +
  2246. +js_library("view_script_source") {
  2247. + deps = [
  2248. + "//ui/webui/resources/js:cr.m",
  2249. + "//ui/webui/resources/js:util.m",
  2250. + ]
  2251. +}
  2252. \ No newline at end of file
  2253. diff --git a/components/user_scripts/browser/resources/user-script-ui/user-scripts-ui.html b/components/user_scripts/browser/resources/user-script-ui/user-scripts-ui.html
  2254. new file mode 100644
  2255. --- /dev/null
  2256. +++ b/components/user_scripts/browser/resources/user-script-ui/user-scripts-ui.html
  2257. @@ -0,0 +1,14 @@
  2258. +<!doctype html>
  2259. +<html lang="en">
  2260. +<head>
  2261. + <meta charset="utf-8">
  2262. + <title>Local State Debug Page</title>
  2263. + <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
  2264. + <script type="module" src="user-scripts-ui.js"></script>
  2265. +</head>
  2266. +<body>
  2267. + <pre id="content">
  2268. + Loading Script Source file...
  2269. + </pre>
  2270. +</body>
  2271. +</html>
  2272. \ No newline at end of file
  2273. diff --git a/components/user_scripts/browser/resources/user-script-ui/user-scripts-ui.js b/components/user_scripts/browser/resources/user-script-ui/user-scripts-ui.js
  2274. new file mode 100644
  2275. --- /dev/null
  2276. +++ b/components/user_scripts/browser/resources/user-script-ui/user-scripts-ui.js
  2277. @@ -0,0 +1,9 @@
  2278. +import {sendWithPromise} from 'chrome://resources/js/cr.m.js';
  2279. +import {$} from 'chrome://resources/js/util.m.js';
  2280. +
  2281. +document.addEventListener('DOMContentLoaded', function() {
  2282. + const urlParams = new URLSearchParams(window.location.search);
  2283. + sendWithPromise('requestSource', urlParams.get('key')).then(textContent => {
  2284. + $('content').textContent = textContent[0].content;
  2285. + });
  2286. +});
  2287. \ No newline at end of file
  2288. diff --git a/components/user_scripts/browser/ui/user_scripts_ui.cc b/components/user_scripts/browser/ui/user_scripts_ui.cc
  2289. new file mode 100644
  2290. --- /dev/null
  2291. +++ b/components/user_scripts/browser/ui/user_scripts_ui.cc
  2292. @@ -0,0 +1,150 @@
  2293. +/*
  2294. + This file is part of Bromite.
  2295. +
  2296. + Bromite is free software: you can redistribute it and/or modify
  2297. + it under the terms of the GNU General Public License as published by
  2298. + the Free Software Foundation, either version 3 of the License, or
  2299. + (at your option) any later version.
  2300. +
  2301. + Bromite is distributed in the hope that it will be useful,
  2302. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2303. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2304. + GNU General Public License for more details.
  2305. +
  2306. + You should have received a copy of the GNU General Public License
  2307. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2308. +*/
  2309. +
  2310. +
  2311. +#include <memory>
  2312. +
  2313. +#include "base/bind.h"
  2314. +#include "base/json/json_string_value_serializer.h"
  2315. +#include "base/macros.h"
  2316. +#include "base/memory/writable_shared_memory_region.h"
  2317. +#include "base/strings/string_util.h"
  2318. +#include "base/values.h"
  2319. +
  2320. +#include "chrome/browser/browser_process.h"
  2321. +#include "chrome/browser/profiles/profile.h"
  2322. +#include "chrome/common/url_constants.h"
  2323. +#include "chrome/grit/userscripts_browser_resources.h"
  2324. +#include "components/prefs/pref_service.h"
  2325. +#include "content/public/browser/web_ui.h"
  2326. +#include "content/public/browser/web_ui_controller.h"
  2327. +#include "content/public/browser/web_ui_data_source.h"
  2328. +#include "content/public/browser/web_ui_message_handler.h"
  2329. +
  2330. +#include "user_scripts_ui.h"
  2331. +#include "../userscripts_browser_client.h"
  2332. +#include "../../common/user_script.h"
  2333. +
  2334. +namespace {
  2335. +
  2336. +class UserScriptsUIHandler : public content::WebUIMessageHandler {
  2337. + public:
  2338. + UserScriptsUIHandler();
  2339. + ~UserScriptsUIHandler() override;
  2340. +
  2341. + // content::WebUIMessageHandler:
  2342. + void RegisterMessages() override;
  2343. +
  2344. + private:
  2345. + void HandleRequestSource(const base::ListValue* args);
  2346. + void OnScriptsLoaded(
  2347. + const std::string callback_id,
  2348. + const std::string script_key,
  2349. + std::unique_ptr<user_scripts::UserScriptList> user_scripts,
  2350. + base::ReadOnlySharedMemoryRegion shared_memory);
  2351. +
  2352. + std::unique_ptr<user_scripts::UserScriptList> loaded_scripts_;
  2353. +
  2354. + base::WeakPtrFactory<UserScriptsUIHandler> weak_factory_{this};
  2355. +
  2356. + DISALLOW_COPY_AND_ASSIGN(UserScriptsUIHandler);
  2357. +};
  2358. +
  2359. +UserScriptsUIHandler::UserScriptsUIHandler()
  2360. + : loaded_scripts_(new user_scripts::UserScriptList()) {
  2361. +}
  2362. +
  2363. +UserScriptsUIHandler::~UserScriptsUIHandler() {
  2364. +}
  2365. +
  2366. +void UserScriptsUIHandler::RegisterMessages() {
  2367. + web_ui()->RegisterMessageCallback(
  2368. + "requestSource",
  2369. + base::BindRepeating(&UserScriptsUIHandler::HandleRequestSource,
  2370. + base::Unretained(this)));
  2371. +}
  2372. +
  2373. +void UserScriptsUIHandler::HandleRequestSource(const base::ListValue* args) {
  2374. + AllowJavascript();
  2375. + std::string callback_id;
  2376. + CHECK(args->GetString(0, &callback_id));
  2377. +
  2378. + std::string script_key;
  2379. + if (args->GetString(1, &script_key) == false) {
  2380. + std::string json = "Missing key value.";
  2381. + ResolveJavascriptCallback(base::Value(callback_id), base::Value(json));
  2382. + return;
  2383. + }
  2384. +
  2385. + user_scripts::UserScriptsBrowserClient* client = user_scripts::UserScriptsBrowserClient::GetInstance();
  2386. + if (client == NULL) {
  2387. + std::string json = "User scripts disabled.";
  2388. + ResolveJavascriptCallback(base::Value(callback_id), base::Value(json));
  2389. + } else {
  2390. + std::unique_ptr<user_scripts::UserScriptList> scripts_to_load =
  2391. + std::move(loaded_scripts_);
  2392. + scripts_to_load->clear();
  2393. +
  2394. + client->GetLoader()->LoadScripts(std::move(scripts_to_load),
  2395. + base::BindOnce(
  2396. + &UserScriptsUIHandler::OnScriptsLoaded,
  2397. + weak_factory_.GetWeakPtr(),
  2398. + callback_id, script_key)
  2399. + );
  2400. + }
  2401. +}
  2402. +
  2403. +void UserScriptsUIHandler::OnScriptsLoaded(
  2404. + const std::string callback_id,
  2405. + const std::string script_key,
  2406. + std::unique_ptr<user_scripts::UserScriptList> user_scripts,
  2407. + base::ReadOnlySharedMemoryRegion shared_memory) {
  2408. + loaded_scripts_ = std::move(user_scripts);
  2409. +
  2410. + base::ListValue response;
  2411. + for (const std::unique_ptr<user_scripts::UserScript>& script : *loaded_scripts_) {
  2412. + if (script->key() == script_key) {
  2413. + auto scriptData = std::make_unique<base::DictionaryValue>();
  2414. + for (const std::unique_ptr<user_scripts::UserScript::File>& js_file :
  2415. + script->js_scripts()) {
  2416. + base::StringPiece contents = js_file->GetContent();
  2417. + scriptData->SetString("content", contents.data());
  2418. + }
  2419. + response.Append(std::move(scriptData));
  2420. + }
  2421. + }
  2422. +
  2423. + ResolveJavascriptCallback(base::Value(callback_id), response);
  2424. +}
  2425. +
  2426. +} // namespace
  2427. +
  2428. +namespace user_scripts {
  2429. +
  2430. +UserScriptsUI::UserScriptsUI(content::WebUI* web_ui) : WebUIController(web_ui) {
  2431. + content::WebUIDataSource* html_source =
  2432. + content::WebUIDataSource::Create(kChromeUIUserScriptsHost);
  2433. + html_source->SetDefaultResource(IDR_USER_SCRIPTS_HTML);
  2434. + html_source->AddResourcePath("user-scripts-ui.js", IDR_USER_SCRIPTS_JS);
  2435. + content::WebUIDataSource::Add(Profile::FromWebUI(web_ui), html_source);
  2436. + web_ui->AddMessageHandler(std::make_unique<UserScriptsUIHandler>());
  2437. +}
  2438. +
  2439. +UserScriptsUI::~UserScriptsUI() {
  2440. +}
  2441. +
  2442. +}
  2443. \ No newline at end of file
  2444. diff --git a/components/user_scripts/browser/ui/user_scripts_ui.h b/components/user_scripts/browser/ui/user_scripts_ui.h
  2445. new file mode 100644
  2446. --- /dev/null
  2447. +++ b/components/user_scripts/browser/ui/user_scripts_ui.h
  2448. @@ -0,0 +1,39 @@
  2449. +/*
  2450. + This file is part of Bromite.
  2451. +
  2452. + Bromite is free software: you can redistribute it and/or modify
  2453. + it under the terms of the GNU General Public License as published by
  2454. + the Free Software Foundation, either version 3 of the License, or
  2455. + (at your option) any later version.
  2456. +
  2457. + Bromite is distributed in the hope that it will be useful,
  2458. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2459. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2460. + GNU General Public License for more details.
  2461. +
  2462. + You should have received a copy of the GNU General Public License
  2463. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2464. +*/
  2465. +
  2466. +#ifndef USERSCRIPTS_BROWSER_UI_USER_SCRIPTS_UI_H_
  2467. +#define USERSCRIPTS_BROWSER_UI_USER_SCRIPTS_UI_H_
  2468. +
  2469. +#include "base/macros.h"
  2470. +#include "content/public/browser/web_ui_controller.h"
  2471. +
  2472. +namespace user_scripts {
  2473. +
  2474. +const char kChromeUIUserScriptsHost[] = "user-scripts";
  2475. +
  2476. +class UserScriptsUI : public content::WebUIController {
  2477. + public:
  2478. + explicit UserScriptsUI(content::WebUI* web_ui);
  2479. + ~UserScriptsUI() override;
  2480. +
  2481. + private:
  2482. + DISALLOW_COPY_AND_ASSIGN(UserScriptsUI);
  2483. +};
  2484. +
  2485. +}
  2486. +
  2487. +#endif
  2488. \ No newline at end of file
  2489. diff --git a/components/user_scripts/browser/user_script_loader.cc b/components/user_scripts/browser/user_script_loader.cc
  2490. new file mode 100755
  2491. --- /dev/null
  2492. +++ b/components/user_scripts/browser/user_script_loader.cc
  2493. @@ -0,0 +1,657 @@
  2494. +/*
  2495. + This file is part of Bromite.
  2496. +
  2497. + Bromite is free software: you can redistribute it and/or modify
  2498. + it under the terms of the GNU General Public License as published by
  2499. + the Free Software Foundation, either version 3 of the License, or
  2500. + (at your option) any later version.
  2501. +
  2502. + Bromite is distributed in the hope that it will be useful,
  2503. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2504. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2505. + GNU General Public License for more details.
  2506. +
  2507. + You should have received a copy of the GNU General Public License
  2508. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2509. +*/
  2510. +
  2511. +#include "user_script_loader.h"
  2512. +
  2513. +#include <stddef.h>
  2514. +
  2515. +#include <set>
  2516. +#include <string>
  2517. +#include <utility>
  2518. +
  2519. +#include "base/bind.h"
  2520. +#include "base/memory/writable_shared_memory_region.h"
  2521. +#include "base/strings/string_util.h"
  2522. +#include "base/version.h"
  2523. +#include "base/task/task_traits.h"
  2524. +#include "base/files/file_util.h"
  2525. +#include "base/files/file_enumerator.h"
  2526. +#include "base/path_service.h"
  2527. +#include "base/base_paths_android.h"
  2528. +#include "base/strings/utf_string_conversions.h"
  2529. +#include "base/android/content_uri_utils.h"
  2530. +#include "base/android/jni_android.h"
  2531. +
  2532. +#include "crypto/sha2.h"
  2533. +#include "base/base64.h"
  2534. +
  2535. +#include "build/build_config.h"
  2536. +#include "content/public/browser/browser_context.h"
  2537. +#include "content/public/browser/browser_task_traits.h"
  2538. +#include "content/public/browser/browser_thread.h"
  2539. +#include "content/public/browser/notification_service.h"
  2540. +#include "content/public/browser/notification_types.h"
  2541. +#include "content/public/browser/render_process_host.h"
  2542. +#include "ui/shell_dialogs/select_file_dialog.h"
  2543. +#include "content/browser/file_system_access/file_system_chooser.h"
  2544. +#include "chrome/browser/ui/chrome_select_file_policy.h"
  2545. +#include "ui/android/window_android.h"
  2546. +
  2547. +#include "../common/user_scripts_features.h"
  2548. +#include "../common/extension_messages.h"
  2549. +#include "file_task_runner.h"
  2550. +#include "user_script_prefs.h"
  2551. +#include "user_script_pref_info.h"
  2552. +
  2553. +using content::BrowserThread;
  2554. +using content::BrowserContext;
  2555. +
  2556. +namespace user_scripts {
  2557. +
  2558. +namespace {
  2559. +
  2560. +bool invalidChar(unsigned char c)
  2561. +{
  2562. + return !(c>=0 && c <128);
  2563. +}
  2564. +
  2565. +void stripUnicode(std::string& str)
  2566. +{
  2567. + str.erase(remove_if(str.begin(),str.end(), invalidChar), str.end());
  2568. +}
  2569. +
  2570. +// Helper function to parse greasesmonkey headers
  2571. +bool GetDeclarationValue(const base::StringPiece& line,
  2572. + const base::StringPiece& prefix,
  2573. + std::string* value) {
  2574. + base::StringPiece::size_type index = line.find(prefix);
  2575. + if (index == base::StringPiece::npos)
  2576. + return false;
  2577. +
  2578. + std::string temp(line.data() + index + prefix.length(),
  2579. + line.length() - index - prefix.length());
  2580. +
  2581. + if (temp.empty() || !base::IsUnicodeWhitespace(temp[0]))
  2582. + return false;
  2583. +
  2584. + base::TrimWhitespaceASCII(temp, base::TRIM_ALL, value);
  2585. + return true;
  2586. +}
  2587. +
  2588. +} // namespace
  2589. +
  2590. +// static
  2591. +bool UserScriptLoader::ParseMetadataHeader(const base::StringPiece& script_text,
  2592. + std::unique_ptr<UserScript>& script,
  2593. + std::string& error_message) {
  2594. + // http://wiki.greasespot.net/Metadata_block
  2595. + base::StringPiece line;
  2596. + size_t line_start = 0;
  2597. + size_t line_end = line_start;
  2598. + bool in_metadata = false;
  2599. +
  2600. + static const base::StringPiece kUserScriptBegin("// ==UserScript==");
  2601. + static const base::StringPiece kUserScriptEng("// ==/UserScript==");
  2602. + static const base::StringPiece kNamespaceDeclaration("// @namespace");
  2603. + static const base::StringPiece kNameDeclaration("// @name");
  2604. + static const base::StringPiece kVersionDeclaration("// @version");
  2605. + static const base::StringPiece kDescriptionDeclaration("// @description");
  2606. + static const base::StringPiece kIncludeDeclaration("// @include");
  2607. + static const base::StringPiece kExcludeDeclaration("// @exclude");
  2608. + static const base::StringPiece kMatchDeclaration("// @match");
  2609. + static const base::StringPiece kExcludeMatchDeclaration("// @exclude_match");
  2610. + static const base::StringPiece kRunAtDeclaration("// @run-at");
  2611. + static const base::StringPiece kRunAtDocumentStartValue("document-start");
  2612. + static const base::StringPiece kRunAtDocumentEndValue("document-end");
  2613. + static const base::StringPiece kRunAtDocumentIdleValue("document-idle");
  2614. + static const base::StringPiece kUrlSourceDeclaration("// @url");
  2615. +
  2616. + while (line_start < script_text.length()) {
  2617. + line_end = script_text.find('\n', line_start);
  2618. +
  2619. + // Handle the case where there is no trailing newline in the file.
  2620. + if (line_end == std::string::npos)
  2621. + line_end = script_text.length() - 1;
  2622. +
  2623. + line = base::StringPiece(script_text.data() + line_start,
  2624. + line_end - line_start);
  2625. +
  2626. + if (!in_metadata) {
  2627. + if (base::StartsWith(line, kUserScriptBegin))
  2628. + in_metadata = true;
  2629. + } else {
  2630. + if (base::StartsWith(line, kUserScriptEng))
  2631. + break;
  2632. +
  2633. + std::string value;
  2634. + if (GetDeclarationValue(line, kIncludeDeclaration, &value)) {
  2635. + // We escape some characters that MatchPattern() considers special.
  2636. + base::ReplaceSubstringsAfterOffset(&value, 0, "\\", "\\\\");
  2637. + base::ReplaceSubstringsAfterOffset(&value, 0, "?", "\\?");
  2638. + script->add_glob(value);
  2639. + } else if (GetDeclarationValue(line, kExcludeDeclaration, &value)) {
  2640. + base::ReplaceSubstringsAfterOffset(&value, 0, "\\", "\\\\");
  2641. + base::ReplaceSubstringsAfterOffset(&value, 0, "?", "\\?");
  2642. + script->add_exclude_glob(value);
  2643. + } else if (GetDeclarationValue(line, kNamespaceDeclaration, &value)) {
  2644. + script->set_name_space(value);
  2645. + } else if (GetDeclarationValue(line, kNameDeclaration, &value)) {
  2646. + script->set_name(value);
  2647. + } else if (GetDeclarationValue(line, kVersionDeclaration, &value)) {
  2648. + base::Version version(value);
  2649. + if (version.IsValid())
  2650. + script->set_version(version.GetString());
  2651. + } else if (GetDeclarationValue(line, kDescriptionDeclaration, &value)) {
  2652. + script->set_description(value);
  2653. + } else if (GetDeclarationValue(line, kMatchDeclaration, &value)) {
  2654. + URLPattern pattern(UserScript::ValidUserScriptSchemes());
  2655. + if (URLPattern::ParseResult::kSuccess != pattern.Parse(value)) {
  2656. + error_message = "Invalid UserScript Schema " + value;
  2657. + return false;
  2658. + }
  2659. + script->add_url_pattern(pattern);
  2660. + } else if (GetDeclarationValue(line, kExcludeMatchDeclaration, &value)) {
  2661. + URLPattern exclude(UserScript::ValidUserScriptSchemes());
  2662. + if (URLPattern::ParseResult::kSuccess != exclude.Parse(value)) {
  2663. + error_message = "Invalid UserScript Schema " + value;
  2664. + return false;
  2665. + }
  2666. + script->add_exclude_url_pattern(exclude);
  2667. + } else if (GetDeclarationValue(line, kRunAtDeclaration, &value)) {
  2668. + if (value == kRunAtDocumentStartValue)
  2669. + script->set_run_location(UserScript::DOCUMENT_START);
  2670. + else if (value == kRunAtDocumentEndValue)
  2671. + script->set_run_location(UserScript::DOCUMENT_END);
  2672. + else if (value == kRunAtDocumentIdleValue)
  2673. + script->set_run_location(UserScript::DOCUMENT_IDLE);
  2674. + else {
  2675. + error_message = "Invalid RunAtDeclaration " + value;
  2676. + return false;
  2677. + }
  2678. + } else if(GetDeclarationValue(line, kUrlSourceDeclaration, &value)) {
  2679. + script->set_url_source(value);
  2680. + }
  2681. +
  2682. + // TODO(aa): Handle more types of metadata.
  2683. + }
  2684. +
  2685. + line_start = line_end + 1;
  2686. + }
  2687. +
  2688. + // If no patterns were specified, default to @include *. This is what
  2689. + // Greasemonkey does.
  2690. + if (script->globs().empty() && script->url_patterns().is_empty())
  2691. + script->add_glob("*");
  2692. +
  2693. + return true;
  2694. +}
  2695. +
  2696. +// static
  2697. +bool LoadUserScriptFromFile(
  2698. + const base::FilePath& user_script_path, const GURL& original_url,
  2699. + std::unique_ptr<UserScript>& script,
  2700. + base::string16* error) {
  2701. +
  2702. + std::string script_key = user_script_path.BaseName().value();
  2703. +
  2704. + std::string content;
  2705. + if (user_script_path.IsContentUri()) {
  2706. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  2707. + LOG(INFO) << "UserScriptLoader: path " << user_script_path << " is a content uri";
  2708. +
  2709. + base::FilePath tempFilePath;
  2710. + if( base::CreateTemporaryFile(&tempFilePath) == false ) {
  2711. + *error = base::ASCIIToUTF16("Could not read create temp file.");
  2712. + return false;
  2713. + }
  2714. +
  2715. + if( base::CopyFile(user_script_path, tempFilePath) == false ) {
  2716. + *error = base::ASCIIToUTF16("Could not copy file to temp file.");
  2717. + return false;
  2718. + }
  2719. +
  2720. + if (!base::ReadFileToString(tempFilePath, &content)) {
  2721. + *error = base::ASCIIToUTF16("Could not read source file from temp path.");
  2722. + return false;
  2723. + }
  2724. + } else {
  2725. + if (!base::ReadFileToString(user_script_path, &content)) {
  2726. + *error = base::ASCIIToUTF16("Could not read source file.");
  2727. + return false;
  2728. + }
  2729. + }
  2730. +
  2731. + if (!base::IsStringUTF8(content)) {
  2732. + *error = base::ASCIIToUTF16("User script must be UTF8 encoded.");
  2733. + return false;
  2734. + }
  2735. +
  2736. + std::string detailed_error;
  2737. + if (!UserScriptLoader::ParseMetadataHeader(content, script, detailed_error)) {
  2738. + *error = base::ASCIIToUTF16("Invalid script header. " + detailed_error);
  2739. + return false;
  2740. + }
  2741. +
  2742. + // add into key the filename
  2743. + // this value is used in ui to discriminate scripts
  2744. + script->set_key(script_key);
  2745. +
  2746. + script->set_match_origin_as_fallback(MatchOriginAsFallbackBehavior::kNever);
  2747. +
  2748. + // remove unicode chars and set content into File
  2749. + stripUnicode(content);
  2750. + std::unique_ptr<UserScript::File> file(new UserScript::File());
  2751. + file->set_content(content);
  2752. + file->set_url(GURL(/*script_key*/ "script.js")); // name doesn't matter
  2753. +
  2754. + // create SHA256 of file
  2755. + char raw[crypto::kSHA256Length] = {0};
  2756. + std::string key;
  2757. + crypto::SHA256HashString(content, raw, crypto::kSHA256Length);
  2758. + base::Base64Encode(base::StringPiece(raw, crypto::kSHA256Length), &key);
  2759. + file->set_key(key);
  2760. +
  2761. + script->js_scripts().push_back(std::move(file));
  2762. +
  2763. + return true;
  2764. +}
  2765. +
  2766. +// static
  2767. +bool GetOrCreatePath(base::FilePath& path) {
  2768. + base::PathService::Get(base::DIR_ANDROID_APP_DATA, &path);
  2769. + path = path.AppendASCII("userscripts");
  2770. +
  2771. + // create snippets directory if not exists
  2772. + if(!base::PathExists(path)) {
  2773. + LOG(INFO) << "Path " << path << " doesn't exists. Creating";
  2774. + base::File::Error error = base::File::FILE_OK;
  2775. + if( !base::CreateDirectoryAndGetError(path, &error) ) {
  2776. + LOG(ERROR) <<
  2777. + "UserScriptLoader: failed to create directory: " << path
  2778. + << " with error code " << error;
  2779. + return false;
  2780. + }
  2781. + }
  2782. + return true;
  2783. +}
  2784. +
  2785. +// static
  2786. +void LoadUserScripts(UserScriptList* user_scripts_list) {
  2787. + base::FilePath path;
  2788. + if (GetOrCreatePath(path) == false) return;
  2789. +
  2790. + // enumerate all files from script path
  2791. + // we accept all files, but we check if it's a real
  2792. + // userscript
  2793. + base::FileEnumerator dir_enum(
  2794. + path,
  2795. + /*recursive=*/false, base::FileEnumerator::FILES);
  2796. + base::FilePath full_name;
  2797. + while (full_name = dir_enum.Next(), !full_name.empty()) {
  2798. + std::unique_ptr<UserScript> userscript(new UserScript());
  2799. +
  2800. + base::string16 error;
  2801. + if (LoadUserScriptFromFile(full_name, GURL(), userscript, &error)) {
  2802. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  2803. + LOG(INFO) << "UserScriptLoader: Found user script " << userscript->name() <<
  2804. + "-" << userscript->version() <<
  2805. + "-" << userscript->description();
  2806. +
  2807. + userscript->set_file_path(full_name.AsUTF8Unsafe());
  2808. + user_scripts_list->push_back(std::move(userscript));
  2809. + } else {
  2810. + LOG(ERROR) << "UserScriptLoader: load error " << error;
  2811. + }
  2812. + }
  2813. +}
  2814. +
  2815. +UserScriptLoader::UserScriptLoader(BrowserContext* browser_context,
  2816. + UserScriptsPrefs* prefs)
  2817. + : loaded_scripts_(new UserScriptList()),
  2818. + ready_(false),
  2819. + browser_context_(browser_context),
  2820. + prefs_(prefs) {}
  2821. +
  2822. +UserScriptLoader::~UserScriptLoader() {
  2823. + for (auto& observer : observers_)
  2824. + observer.OnUserScriptLoaderDestroyed(this);
  2825. +}
  2826. +
  2827. +void UserScriptLoader::OnRenderProcessHostCreated(
  2828. + content::RenderProcessHost* process_host) {
  2829. + if (initial_load_complete()) {
  2830. + SendUpdate(process_host, shared_memory_);
  2831. + }
  2832. +}
  2833. +
  2834. +void UserScriptLoader::AttemptLoad() {
  2835. + int tryOut = prefs_->GetCurrentStartupTryout();
  2836. + if (tryOut >= 3) {
  2837. + LOG(INFO) << "UserScriptLoader: Possible crash detected. UserScript disabled";
  2838. + prefs_->SetEnabled(false);
  2839. + } else {
  2840. + prefs_->StartupTryout(tryOut+1);
  2841. + StartLoad();
  2842. + }
  2843. +}
  2844. +
  2845. +void UserScriptLoader::StartLoad() {
  2846. + DCHECK_CURRENTLY_ON(BrowserThread::UI);
  2847. +
  2848. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  2849. + LOG(INFO) << "UserScriptLoader: StartLoad";
  2850. +
  2851. + // Reload any loaded scripts, and clear out |loaded_scripts_| to indicate that
  2852. + // the scripts aren't currently ready.
  2853. + std::unique_ptr<UserScriptList> scripts_to_load = std::move(loaded_scripts_);
  2854. + scripts_to_load->clear();
  2855. +
  2856. + LoadScripts(std::move(scripts_to_load),
  2857. + base::BindOnce(&UserScriptLoader::OnScriptsLoaded,
  2858. + weak_factory_.GetWeakPtr()));
  2859. +}
  2860. +
  2861. +// static
  2862. +base::ReadOnlySharedMemoryRegion UserScriptLoader::Serialize(
  2863. + const UserScriptList& scripts) {
  2864. + base::Pickle pickle;
  2865. + pickle.WriteUInt32(scripts.size());
  2866. + for (const std::unique_ptr<UserScript>& script : scripts) {
  2867. + // TODO(aa): This can be replaced by sending content script metadata to
  2868. + // renderers along with other extension data in ExtensionMsg_Loaded.
  2869. + // See crbug.com/70516.
  2870. + script->Pickle(&pickle);
  2871. + // Write scripts as 'data' so that we can read it out in the slave without
  2872. + // allocating a new string.
  2873. + for (const std::unique_ptr<UserScript::File>& js_file :
  2874. + script->js_scripts()) {
  2875. + base::StringPiece contents = js_file->GetContent();
  2876. + pickle.WriteData(contents.data(), contents.length());
  2877. + }
  2878. + for (const std::unique_ptr<UserScript::File>& css_file :
  2879. + script->css_scripts()) {
  2880. + base::StringPiece contents = css_file->GetContent();
  2881. + pickle.WriteData(contents.data(), contents.length());
  2882. + }
  2883. + }
  2884. +
  2885. + // Create the shared memory object.
  2886. + base::MappedReadOnlyRegion shared_memory =
  2887. + base::ReadOnlySharedMemoryRegion::Create(pickle.size());
  2888. + if (!shared_memory.IsValid())
  2889. + return {};
  2890. +
  2891. + // Copy the pickle to shared memory.
  2892. + memcpy(shared_memory.mapping.memory(), pickle.data(), pickle.size());
  2893. + return std::move(shared_memory.region);
  2894. +}
  2895. +
  2896. +void UserScriptLoader::AddObserver(Observer* observer) {
  2897. + observers_.AddObserver(observer);
  2898. +}
  2899. +
  2900. +void UserScriptLoader::RemoveObserver(Observer* observer) {
  2901. + observers_.RemoveObserver(observer);
  2902. +}
  2903. +
  2904. +void UserScriptLoader::SetReady(bool ready) {
  2905. + bool was_ready = ready_;
  2906. + ready_ = ready;
  2907. + if (ready_ && !was_ready)
  2908. + AttemptLoad();
  2909. +}
  2910. +
  2911. +void UserScriptLoader::OnScriptsLoaded(
  2912. + std::unique_ptr<UserScriptList> user_scripts,
  2913. + base::ReadOnlySharedMemoryRegion shared_memory) {
  2914. +
  2915. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  2916. + LOG(INFO) << "UserScriptLoader: OnScriptsLoaded";
  2917. +
  2918. + // Check user preferences for loaded user scripts
  2919. + prefs_->CompareWithPrefs(*user_scripts);
  2920. + loaded_scripts_ = std::move(user_scripts);
  2921. +
  2922. + shared_memory =
  2923. + UserScriptLoader::Serialize(*loaded_scripts_);
  2924. +
  2925. + if (!shared_memory.IsValid()) {
  2926. + // This can happen if we run out of file descriptors. In that case, we
  2927. + // have a choice between silently omitting all user scripts for new tabs,
  2928. + // by nulling out shared_memory_, or only silently omitting new ones by
  2929. + // leaving the existing object in place. The second seems less bad, even
  2930. + // though it removes the possibility that freeing the shared memory block
  2931. + // would open up enough FDs for long enough for a retry to succeed.
  2932. +
  2933. + // Pretend the extension change didn't happen.
  2934. + return;
  2935. + }
  2936. +
  2937. + // We've got scripts ready to go.
  2938. + shared_memory_ = std::move(shared_memory);
  2939. +
  2940. + for (content::RenderProcessHost::iterator i(
  2941. + content::RenderProcessHost::AllHostsIterator());
  2942. + !i.IsAtEnd(); i.Advance()) {
  2943. + SendUpdate(i.GetCurrentValue(), shared_memory_);
  2944. + }
  2945. +
  2946. + // DCHECK(false); trying crash
  2947. + prefs_->StartupTryout(0);
  2948. +
  2949. + for (auto& observer : observers_)
  2950. + observer.OnScriptsLoaded(this, browser_context_);
  2951. +}
  2952. +
  2953. +void UserScriptLoader::SendUpdate(
  2954. + content::RenderProcessHost* process,
  2955. + const base::ReadOnlySharedMemoryRegion& shared_memory) {
  2956. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  2957. + LOG(INFO) << "UserScriptLoader: SendUpdate";
  2958. +
  2959. + // If the process is being started asynchronously, early return. We'll end up
  2960. + // calling InitUserScripts when it's created which will call this again.
  2961. + base::ProcessHandle handle = process->GetProcess().Handle();
  2962. + if (!handle)
  2963. + return;
  2964. +
  2965. + base::ReadOnlySharedMemoryRegion region_for_process =
  2966. + shared_memory.Duplicate();
  2967. + if (!region_for_process.IsValid())
  2968. + return;
  2969. +
  2970. + process->Send(new ExtensionMsg_UpdateUserScripts(
  2971. + std::move(region_for_process)));
  2972. +}
  2973. +
  2974. +void LoadScriptsOnFileTaskRunner(
  2975. + std::unique_ptr<UserScriptList> user_scripts,
  2976. + UserScriptLoader::LoadScriptsCallback callback) {
  2977. + DCHECK(GetUserScriptsFileTaskRunner()->RunsTasksInCurrentSequence());
  2978. + DCHECK(user_scripts.get());
  2979. +
  2980. + // load user scripts from path
  2981. + LoadUserScripts(user_scripts.get());
  2982. +
  2983. + base::ReadOnlySharedMemoryRegion memory;
  2984. +
  2985. + // Explicit priority to prevent unwanted task priority inheritance.
  2986. + content::GetUIThreadTaskRunner({base::TaskPriority::USER_BLOCKING})
  2987. + ->PostTask(FROM_HERE,
  2988. + base::BindOnce(std::move(callback), std::move(user_scripts),
  2989. + std::move(memory)));
  2990. +}
  2991. +
  2992. +void UserScriptLoader::LoadScripts(
  2993. + std::unique_ptr<UserScriptList> user_scripts,
  2994. + LoadScriptsCallback callback) {
  2995. + DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  2996. +
  2997. + GetUserScriptsFileTaskRunner()->PostTask(
  2998. + FROM_HERE,
  2999. + base::BindOnce(&LoadScriptsOnFileTaskRunner, std::move(user_scripts),
  3000. + std::move(callback)));
  3001. +}
  3002. +
  3003. +void RemoveScriptsOnFileTaskRunner(
  3004. + const std::string& script_id,
  3005. + UserScriptLoader::RemoveScriptCallback callback) {
  3006. + DCHECK(GetUserScriptsFileTaskRunner()->RunsTasksInCurrentSequence());
  3007. +
  3008. + base::FilePath path;
  3009. + if (GetOrCreatePath(path)) {
  3010. + base::FilePath file = path.Append(script_id);
  3011. + if( base::DeleteFile(file) == false ) {
  3012. + LOG(ERROR) <<
  3013. + "ERROR: failed to delete file : " << path;
  3014. + }
  3015. + }
  3016. +
  3017. + content::GetUIThreadTaskRunner({base::TaskPriority::USER_BLOCKING})
  3018. + ->PostTask(FROM_HERE,
  3019. + base::BindOnce(std::move(callback)));
  3020. +}
  3021. +
  3022. +void UserScriptLoader::OnScriptRemoved() {
  3023. + StartLoad();
  3024. +}
  3025. +
  3026. +void UserScriptLoader::RemoveScript(const std::string& script_id) {
  3027. + prefs_->RemoveScriptFromPrefs(script_id);
  3028. +
  3029. + GetUserScriptsFileTaskRunner()->PostTask(
  3030. + FROM_HERE,
  3031. + base::BindOnce(&RemoveScriptsOnFileTaskRunner,
  3032. + std::move(script_id),
  3033. + base::BindOnce(&UserScriptLoader::OnScriptRemoved,
  3034. + weak_factory_.GetWeakPtr())));
  3035. +}
  3036. +
  3037. +void UserScriptLoader::SetScriptEnabled(const std::string& script_id, bool is_enabled) {
  3038. + prefs_->SetScriptEnabled(script_id, is_enabled);
  3039. + StartLoad();
  3040. +}
  3041. +
  3042. +void UserScriptLoader::SelectAndAddScriptFromFile(ui::WindowAndroid* nativeWindow) {
  3043. + DCHECK_CURRENTLY_ON(BrowserThread::UI);
  3044. +
  3045. + dialog_ = ui::SelectFileDialog::Create(
  3046. + this, std::make_unique<ChromeSelectFilePolicy>(nullptr /*web_contents*/));
  3047. +
  3048. + ui::SelectFileDialog::FileTypeInfo allowed_file_info;
  3049. + allowed_file_info.extensions = {{FILE_PATH_LITERAL("js")}};
  3050. + allowed_file_info.allowed_paths =
  3051. + ui::SelectFileDialog::FileTypeInfo::ANY_PATH;
  3052. + base::FilePath suggested_name;
  3053. +
  3054. + std::vector<base::string16> types;
  3055. + types.push_back(base::ASCIIToUTF16("*/*")); /*= java SelectFileDialog.ALL_TYPES*/
  3056. + std::pair<std::vector<base::string16>, bool> accept_types = std::make_pair(
  3057. + types, false /*use_media_capture*/);
  3058. +
  3059. + dialog_->SelectFile(
  3060. + ui::SelectFileDialog::SELECT_OPEN_FILE,
  3061. + base::string16() /* dialog title*/, suggested_name, &allowed_file_info,
  3062. + 0 /* file type index */, std::string() /* default file extension */,
  3063. + nativeWindow,
  3064. + &accept_types /* params */);
  3065. +}
  3066. +
  3067. +
  3068. +void LoadScriptFromPathOnFileTaskRunner(
  3069. + const base::FilePath& path,
  3070. + const std::string& display_name,
  3071. + UserScriptLoader::LoadSingleScriptCallback callback ) {
  3072. + DCHECK(GetUserScriptsFileTaskRunner()->RunsTasksInCurrentSequence());
  3073. +
  3074. + std::unique_ptr<UserScript> userscript(new UserScript());
  3075. + base::string16 error;
  3076. + bool result = LoadUserScriptFromFile(path, GURL(), userscript, &error);
  3077. +
  3078. + if(result) {
  3079. + if (display_name.empty() == false) {
  3080. + userscript->set_key(display_name);
  3081. + }
  3082. +
  3083. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  3084. + LOG(INFO) << "UserScriptLoader: Loaded " << userscript->name() <<
  3085. + "-" << userscript->version() <<
  3086. + "-" << userscript->description();
  3087. + base::FilePath destination;
  3088. + result = GetOrCreatePath(destination);
  3089. + if( result == false ) {
  3090. + error = base::ASCIIToUTF16("Cannot create destination.");
  3091. + } else {
  3092. + destination = destination.Append(userscript->key());
  3093. + result = base::CopyFile(path, destination);
  3094. + if (result == false) {
  3095. + error = base::ASCIIToUTF16("Copy error.");
  3096. + }
  3097. + }
  3098. + } else {
  3099. + LOG(ERROR) << "UserScriptLoader: load error " << error;
  3100. + }
  3101. +
  3102. + const std::string string_error = base::UTF16ToASCII(error);
  3103. +
  3104. + content::GetUIThreadTaskRunner({base::TaskPriority::USER_BLOCKING})
  3105. + ->PostTask(FROM_HERE,
  3106. + base::BindOnce(std::move(callback), result,
  3107. + std::move(string_error)));
  3108. +}
  3109. +
  3110. +void UserScriptLoader::TryToInstall(const base::FilePath& script_path) {
  3111. + base::string16 file_display_name;
  3112. + base::MaybeGetFileDisplayName(script_path, &file_display_name);
  3113. +
  3114. + std::string display_name = script_path.BaseName().value();
  3115. + if (base::IsStringASCII(file_display_name))
  3116. + display_name = base::UTF16ToASCII(file_display_name);
  3117. +
  3118. + GetUserScriptsFileTaskRunner()->PostTask(
  3119. + FROM_HERE,
  3120. + base::BindOnce(
  3121. + &LoadScriptFromPathOnFileTaskRunner,
  3122. + script_path, display_name,
  3123. + base::BindOnce(
  3124. + &UserScriptLoader::LoadScriptFromPathOnFileTaskRunnerCallback,
  3125. + weak_factory_.GetWeakPtr()
  3126. + )
  3127. + ));
  3128. +}
  3129. +
  3130. +void UserScriptLoader::FileSelected(
  3131. + const base::FilePath& path, int index, void* params) {
  3132. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  3133. + LOG(INFO) << "UserScriptLoader: FileSelected " << path;
  3134. +
  3135. + UserScriptLoader::TryToInstall(path);
  3136. +}
  3137. +
  3138. +void UserScriptLoader::LoadScriptFromPathOnFileTaskRunnerCallback(
  3139. + bool result, const std::string& error) {
  3140. + for (auto& observer : observers_)
  3141. + observer.OnUserScriptLoaded(this, result, error);
  3142. +
  3143. + StartLoad();
  3144. +}
  3145. +
  3146. +void UserScriptLoader::FileSelectionCanceled(
  3147. + void* params) {
  3148. +}
  3149. +
  3150. +} // namespace extensions
  3151. diff --git a/components/user_scripts/browser/user_script_loader.h b/components/user_scripts/browser/user_script_loader.h
  3152. new file mode 100755
  3153. --- /dev/null
  3154. +++ b/components/user_scripts/browser/user_script_loader.h
  3155. @@ -0,0 +1,172 @@
  3156. +/*
  3157. + This file is part of Bromite.
  3158. +
  3159. + Bromite is free software: you can redistribute it and/or modify
  3160. + it under the terms of the GNU General Public License as published by
  3161. + the Free Software Foundation, either version 3 of the License, or
  3162. + (at your option) any later version.
  3163. +
  3164. + Bromite is distributed in the hope that it will be useful,
  3165. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  3166. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  3167. + GNU General Public License for more details.
  3168. +
  3169. + You should have received a copy of the GNU General Public License
  3170. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  3171. +*/
  3172. +
  3173. +#ifndef USERSCRIPTS_BROWSER_USER_SCRIPT_LOADER_H_
  3174. +#define USERSCRIPTS_BROWSER_USER_SCRIPT_LOADER_H_
  3175. +
  3176. +#include <map>
  3177. +#include <memory>
  3178. +#include <set>
  3179. +
  3180. +#include "base/callback_forward.h"
  3181. +#include "base/compiler_specific.h"
  3182. +#include "base/macros.h"
  3183. +#include "base/memory/read_only_shared_memory_region.h"
  3184. +#include "base/memory/weak_ptr.h"
  3185. +#include "base/observer_list.h"
  3186. +#include "base/scoped_observer.h"
  3187. +#include "content/public/browser/render_process_host_creation_observer.h"
  3188. +#include "ui/shell_dialogs/select_file_dialog.h"
  3189. +#include "content/browser/file_system_access/file_system_chooser.h"
  3190. +#include "ui/android/window_android.h"
  3191. +
  3192. +#include "../common/host_id.h"
  3193. +#include "../common/user_script.h"
  3194. +#include "user_script_prefs.h"
  3195. +
  3196. +namespace base {
  3197. +class ReadOnlySharedMemoryRegion;
  3198. +}
  3199. +
  3200. +namespace content {
  3201. +class BrowserContext;
  3202. +class RenderProcessHost;
  3203. +}
  3204. +
  3205. +namespace user_scripts {
  3206. +
  3207. +// Manages one "logical unit" of user scripts in shared memory by constructing a
  3208. +// new shared memory region when the set of scripts changes. Also notifies
  3209. +// renderers of new shared memory region when new renderers appear, or when
  3210. +// script reloading completes. Script loading lives on the file thread.
  3211. +class UserScriptLoader : public content::RenderProcessHostCreationObserver,
  3212. + public ui::SelectFileDialog::Listener {
  3213. + public:
  3214. + using LoadScriptsCallback =
  3215. + base::OnceCallback<void(std::unique_ptr<UserScriptList>,
  3216. + base::ReadOnlySharedMemoryRegion shared_memory)>;
  3217. + using LoadSingleScriptCallback =
  3218. + base::OnceCallback<void(bool result, const std::string& error)>;
  3219. +
  3220. + using RemoveScriptCallback =
  3221. + base::OnceCallback<void()>;
  3222. + class Observer {
  3223. + public:
  3224. + virtual void OnScriptsLoaded(UserScriptLoader* loader,
  3225. + content::BrowserContext* browser_context) = 0;
  3226. + virtual void OnUserScriptLoaderDestroyed(UserScriptLoader* loader) = 0;
  3227. + virtual void OnUserScriptLoaded(UserScriptLoader* loader,
  3228. + bool result, const std::string& error) = 0;
  3229. + };
  3230. +
  3231. + // Parses the includes out of |script| and returns them in |includes|.
  3232. + static bool ParseMetadataHeader(const base::StringPiece& script_text,
  3233. + std::unique_ptr<UserScript>& script,
  3234. + std::string& error_message);
  3235. +
  3236. + UserScriptLoader(content::BrowserContext* browser_context,
  3237. + UserScriptsPrefs* prefs);
  3238. + //const HostID& host_id);
  3239. + ~UserScriptLoader() override;
  3240. +
  3241. + // Initiates procedure to start loading scripts on the file thread.
  3242. + void StartLoad();
  3243. +
  3244. + // Returns true if we have any scripts ready.
  3245. + bool initial_load_complete() const { return shared_memory_.IsValid(); }
  3246. +
  3247. + // Pickle user scripts and return pointer to the shared memory.
  3248. + static base::ReadOnlySharedMemoryRegion Serialize(
  3249. + const user_scripts::UserScriptList& scripts);
  3250. +
  3251. + // Adds or removes observers.
  3252. + void AddObserver(Observer* observer);
  3253. + void RemoveObserver(Observer* observer);
  3254. +
  3255. + // Sets the flag if the initial set of hosts has finished loading; if it's
  3256. + // set to be true, calls AttempLoad() to bootstrap.
  3257. + void SetReady(bool ready);
  3258. +
  3259. + void RemoveScript(const std::string& script_id);
  3260. + void SetScriptEnabled(const std::string& script_id, bool is_enabled);
  3261. +
  3262. + void SelectAndAddScriptFromFile(ui::WindowAndroid* wa);
  3263. + void TryToInstall(const base::FilePath& script_path);
  3264. +
  3265. + void LoadScripts(std::unique_ptr<UserScriptList> user_scripts,
  3266. + LoadScriptsCallback callback);
  3267. +
  3268. + protected:
  3269. + content::BrowserContext* browser_context() const { return browser_context_; }
  3270. +
  3271. + UserScriptsPrefs* prefs() const { return prefs_; }
  3272. +
  3273. + private:
  3274. + void OnRenderProcessHostCreated(
  3275. + content::RenderProcessHost* process_host) override;
  3276. +
  3277. + // Attempts to initiate a load.
  3278. + void AttemptLoad();
  3279. +
  3280. + // Called once we have finished loading the scripts on the file thread.
  3281. + void OnScriptsLoaded(std::unique_ptr<UserScriptList> user_scripts,
  3282. + base::ReadOnlySharedMemoryRegion shared_memory);
  3283. +
  3284. + // Sends the renderer process a new set of user scripts. If
  3285. + // |changed_hosts| is not empty, this signals that only the scripts from
  3286. + // those hosts should be updated. Otherwise, all hosts will be
  3287. + // updated.
  3288. + void SendUpdate(content::RenderProcessHost* process,
  3289. + const base::ReadOnlySharedMemoryRegion& shared_memory);
  3290. +
  3291. + // Contains the scripts that were found the last time scripts were updated.
  3292. + base::ReadOnlySharedMemoryRegion shared_memory_;
  3293. +
  3294. + // List of scripts that are currently loaded. This is null when a load is in
  3295. + // progress.
  3296. + std::unique_ptr<UserScriptList> loaded_scripts_;
  3297. +
  3298. + // If the initial set of hosts has finished loading.
  3299. + bool ready_;
  3300. +
  3301. + // The browser_context for which the scripts managed here are installed.
  3302. + content::BrowserContext* browser_context_;
  3303. +
  3304. + // Manage load and store from preferences
  3305. + UserScriptsPrefs* prefs_;
  3306. +
  3307. + // The associated observers.
  3308. + base::ObserverList<Observer>::Unchecked observers_;
  3309. +
  3310. + void OnScriptRemoved();
  3311. +
  3312. + // Manage file dialog requests
  3313. + scoped_refptr<ui::SelectFileDialog> dialog_;
  3314. + void FileSelected(const base::FilePath& path,
  3315. + int index, void* params) override;
  3316. + void FileSelectionCanceled(void* params) override;
  3317. + void LoadScriptFromPathOnFileTaskRunnerCallback(
  3318. + bool result, const std::string& error );
  3319. +
  3320. + base::WeakPtrFactory<UserScriptLoader> weak_factory_{this};
  3321. +
  3322. + DISALLOW_COPY_AND_ASSIGN(UserScriptLoader);
  3323. +};
  3324. +
  3325. +} // namespace extensions
  3326. +
  3327. +#endif // USERSCRIPTS_BROWSER_USER_SCRIPT_LOADER_H_
  3328. diff --git a/components/user_scripts/browser/user_script_pref_info.cc b/components/user_scripts/browser/user_script_pref_info.cc
  3329. new file mode 100644
  3330. --- /dev/null
  3331. +++ b/components/user_scripts/browser/user_script_pref_info.cc
  3332. @@ -0,0 +1,34 @@
  3333. +/*
  3334. + This file is part of Bromite.
  3335. +
  3336. + Bromite is free software: you can redistribute it and/or modify
  3337. + it under the terms of the GNU General Public License as published by
  3338. + the Free Software Foundation, either version 3 of the License, or
  3339. + (at your option) any later version.
  3340. +
  3341. + Bromite is distributed in the hope that it will be useful,
  3342. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  3343. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  3344. + GNU General Public License for more details.
  3345. +
  3346. + You should have received a copy of the GNU General Public License
  3347. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  3348. +*/
  3349. +
  3350. +#include "user_script_pref_info.h"
  3351. +
  3352. +namespace user_scripts {
  3353. +
  3354. +UserScriptsListPrefs::ScriptInfo::ScriptInfo(const std::string& name,
  3355. + const std::string& description,
  3356. + const base::Time& install_time,
  3357. + bool enabled)
  3358. + : install_time(install_time),
  3359. + enabled(enabled),
  3360. + name_(name),
  3361. + description_(description) {}
  3362. +
  3363. +UserScriptsListPrefs::ScriptInfo::ScriptInfo(const ScriptInfo& other) = default;
  3364. +UserScriptsListPrefs::ScriptInfo::~ScriptInfo() = default;
  3365. +
  3366. +}
  3367. \ No newline at end of file
  3368. diff --git a/components/user_scripts/browser/user_script_pref_info.h b/components/user_scripts/browser/user_script_pref_info.h
  3369. new file mode 100644
  3370. --- /dev/null
  3371. +++ b/components/user_scripts/browser/user_script_pref_info.h
  3372. @@ -0,0 +1,66 @@
  3373. +/*
  3374. + This file is part of Bromite.
  3375. +
  3376. + Bromite is free software: you can redistribute it and/or modify
  3377. + it under the terms of the GNU General Public License as published by
  3378. + the Free Software Foundation, either version 3 of the License, or
  3379. + (at your option) any later version.
  3380. +
  3381. + Bromite is distributed in the hope that it will be useful,
  3382. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  3383. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  3384. + GNU General Public License for more details.
  3385. +
  3386. + You should have received a copy of the GNU General Public License
  3387. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  3388. +*/
  3389. +
  3390. +#ifndef USERSCRIPTS_BROWSER_USERSCRIPT_PREF_INFO_H_
  3391. +#define USERSCRIPTS_BROWSER_USERSCRIPT_PREF_INFO_H_
  3392. +
  3393. +#include "base/values.h"
  3394. +#include "base/time/time.h"
  3395. +#include "components/keyed_service/core/keyed_service.h"
  3396. +
  3397. +namespace user_scripts {
  3398. +
  3399. +class UserScriptsListPrefs : public KeyedService {
  3400. + public:
  3401. + struct ScriptInfo {
  3402. + ScriptInfo(const std::string& name,
  3403. + const std::string& description,
  3404. + const base::Time& install_time,
  3405. + bool enabled);
  3406. + ScriptInfo(const ScriptInfo& other);
  3407. + ~ScriptInfo();
  3408. +
  3409. + const std::string& name() const { return name_; }
  3410. + void set_name(const std::string& name) { name_ = name; }
  3411. +
  3412. + const std::string& description() const { return description_; }
  3413. + void set_description(const std::string& description) { description_ = description; }
  3414. +
  3415. + const std::string& version() const { return version_; }
  3416. + void set_version(const std::string& version) { version_ = version; }
  3417. +
  3418. + const std::string& file_path() const { return file_path_; }
  3419. + void set_file_path(const std::string& file_path) { file_path_ = file_path; }
  3420. +
  3421. + const std::string& url_source() const { return url_source_; }
  3422. + void set_url_source(const std::string& url_source) { url_source_ = url_source; }
  3423. +
  3424. + base::Time install_time;
  3425. + bool enabled;
  3426. +
  3427. + private:
  3428. + std::string name_;
  3429. + std::string description_;
  3430. + std::string version_;
  3431. + std::string file_path_;
  3432. + std::string url_source_;
  3433. + };
  3434. +};
  3435. +
  3436. +}
  3437. +
  3438. +#endif // USERSCRIPTS_BROWSER_USERSCRIPT_PREF_INFO_H_
  3439. \ No newline at end of file
  3440. diff --git a/components/user_scripts/browser/user_script_prefs.cc b/components/user_scripts/browser/user_script_prefs.cc
  3441. new file mode 100644
  3442. --- /dev/null
  3443. +++ b/components/user_scripts/browser/user_script_prefs.cc
  3444. @@ -0,0 +1,262 @@
  3445. +/*
  3446. + This file is part of Bromite.
  3447. +
  3448. + Bromite is free software: you can redistribute it and/or modify
  3449. + it under the terms of the GNU General Public License as published by
  3450. + the Free Software Foundation, either version 3 of the License, or
  3451. + (at your option) any later version.
  3452. +
  3453. + Bromite is distributed in the hope that it will be useful,
  3454. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  3455. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  3456. + GNU General Public License for more details.
  3457. +
  3458. + You should have received a copy of the GNU General Public License
  3459. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  3460. +*/
  3461. +
  3462. +#include <map>
  3463. +
  3464. +#include "base/values.h"
  3465. +#include "base/strings/string_number_conversions.h"
  3466. +#include "base/json/json_writer.h"
  3467. +
  3468. +#include "chrome/browser/browser_process.h"
  3469. +#include "chrome/browser/profiles/profile.h"
  3470. +#include "chrome/browser/profiles/profile_manager.h"
  3471. +
  3472. +#include "components/prefs/pref_service.h"
  3473. +#include "components/prefs/scoped_user_pref_update.h"
  3474. +#include "components/pref_registry/pref_registry_syncable.h"
  3475. +#include "user_script_prefs.h"
  3476. +#include "user_script_pref_info.h"
  3477. +#include "../common/user_script.h"
  3478. +#include "../common/user_scripts_features.h"
  3479. +
  3480. +namespace user_scripts {
  3481. +
  3482. +namespace {
  3483. +
  3484. +const char kUserScriptsEnabled[] = "userscripts.enabled";
  3485. +const char kUserScriptsStartup[] = "userscripts.startup";
  3486. +
  3487. +const char kUserScriptsList[] = "userscripts.scripts";
  3488. +const char kScriptIsEnabled[] = "enabled";
  3489. +const char kScriptName[] = "name";
  3490. +const char kScriptDescription[] = "description";
  3491. +const char kScriptVersion[] = "version";
  3492. +const char kScriptInstallTime[] = "install_time";
  3493. +const char kScriptFilePath[] = "file_path";
  3494. +const char kScriptUrlSource[] = "url_source";
  3495. +
  3496. +class PrefUpdate : public DictionaryPrefUpdate {
  3497. + public:
  3498. + PrefUpdate(PrefService* service,
  3499. + const std::string& id,
  3500. + const std::string& path)
  3501. + : DictionaryPrefUpdate(service, path), id_(id) {}
  3502. +
  3503. + ~PrefUpdate() override = default;
  3504. +
  3505. + base::DictionaryValue* Get() override {
  3506. + base::DictionaryValue* dict = DictionaryPrefUpdate::Get();
  3507. + base::Value* dict_item =
  3508. + dict->FindKeyOfType(id_, base::Value::Type::DICTIONARY);
  3509. + if (!dict_item)
  3510. + dict_item = dict->SetKey(id_, base::Value(base::Value::Type::DICTIONARY));
  3511. + return static_cast<base::DictionaryValue*>(dict_item);
  3512. + }
  3513. +
  3514. + private:
  3515. + const std::string id_;
  3516. +
  3517. + DISALLOW_COPY_AND_ASSIGN(PrefUpdate);
  3518. +};
  3519. +
  3520. +bool GetInt64FromPref(const base::DictionaryValue* dict,
  3521. + const std::string& key,
  3522. + int64_t* value) {
  3523. + DCHECK(dict);
  3524. + std::string value_str;
  3525. + if (!dict->GetStringWithoutPathExpansion(key, &value_str)) {
  3526. + VLOG(2) << "Can't find key in local pref dictionary. Invalid key: " << key
  3527. + << ".";
  3528. + return false;
  3529. + }
  3530. +
  3531. + if (!base::StringToInt64(value_str, value)) {
  3532. + VLOG(2) << "Can't change string to int64_t. Invalid string value: "
  3533. + << value_str << ".";
  3534. + return false;
  3535. + }
  3536. +
  3537. + return true;
  3538. +}
  3539. +
  3540. +}
  3541. +
  3542. +UserScriptsPrefs::UserScriptsPrefs(
  3543. + PrefService* prefs)
  3544. + : prefs_(prefs) {
  3545. +}
  3546. +
  3547. +// static
  3548. +void UserScriptsPrefs::RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
  3549. + registry->RegisterBooleanPref(kUserScriptsEnabled, false);
  3550. + registry->RegisterIntegerPref(kUserScriptsStartup, 0);
  3551. + registry->RegisterDictionaryPref(kUserScriptsList);
  3552. +}
  3553. +
  3554. +bool UserScriptsPrefs::IsEnabled() {
  3555. + return prefs_->GetBoolean(kUserScriptsEnabled);
  3556. +}
  3557. +
  3558. +void UserScriptsPrefs::SetEnabled(bool enabled) {
  3559. + prefs_->SetBoolean(kUserScriptsEnabled, enabled);
  3560. + prefs_->CommitPendingWrite();
  3561. +}
  3562. +
  3563. +void UserScriptsPrefs::StartupTryout(int number) {
  3564. + prefs_->SetInteger(kUserScriptsStartup, number);
  3565. + prefs_->CommitPendingWrite();
  3566. +}
  3567. +
  3568. +int UserScriptsPrefs::GetCurrentStartupTryout() {
  3569. + return prefs_->GetInteger(kUserScriptsStartup);
  3570. +}
  3571. +
  3572. +void UserScriptsPrefs::CompareWithPrefs(UserScriptList& user_scripts) {
  3573. + if( IsEnabled() == false ) {
  3574. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  3575. + LOG(INFO) << "UserScriptsPrefs: disabled by user";
  3576. +
  3577. + user_scripts.clear();
  3578. + return;
  3579. + }
  3580. +
  3581. + std::vector<std::string> all_scripts;
  3582. +
  3583. + auto it = user_scripts.begin();
  3584. + while (it != user_scripts.end())
  3585. + {
  3586. + std::string key = it->get()->key();
  3587. + all_scripts.push_back(key);
  3588. +
  3589. + std::unique_ptr<UserScriptsListPrefs::ScriptInfo> scriptInfo =
  3590. + UserScriptsPrefs::CreateScriptInfoFromPrefs(key);
  3591. +
  3592. + // add or update prefs
  3593. + scriptInfo->set_name(it->get()->name());
  3594. + scriptInfo->set_description(it->get()->description());
  3595. + scriptInfo->set_version(it->get()->version());
  3596. + scriptInfo->set_file_path(it->get()->file_path());
  3597. + scriptInfo->set_url_source(it->get()->url_source());
  3598. +
  3599. + PrefUpdate update(prefs_, key, kUserScriptsList);
  3600. + base::DictionaryValue* script_dict = update.Get();
  3601. +
  3602. + script_dict->SetString(kScriptName, scriptInfo->name());
  3603. + script_dict->SetString(kScriptDescription, scriptInfo->description());
  3604. + script_dict->SetBoolean(kScriptIsEnabled, scriptInfo->enabled);
  3605. + script_dict->SetString(kScriptVersion, scriptInfo->version());
  3606. + script_dict->SetString(kScriptFilePath, scriptInfo->file_path());
  3607. + script_dict->SetString(kScriptUrlSource, scriptInfo->url_source());
  3608. +
  3609. + std::string install_time_str =
  3610. + base::NumberToString(scriptInfo->install_time.ToInternalValue());
  3611. + script_dict->SetString(kScriptInstallTime, install_time_str);
  3612. +
  3613. + if (!scriptInfo->enabled) {
  3614. + it = user_scripts.erase(it);
  3615. + } else {
  3616. + ++it;
  3617. + }
  3618. + }
  3619. +
  3620. + // remove script from prefs if no more present
  3621. + std::vector<std::string> all_scripts_to_remove;
  3622. + const base::DictionaryValue* dict =
  3623. + prefs_->GetDictionary(kUserScriptsList);
  3624. + for (base::DictionaryValue::Iterator script_it(*dict); !script_it.IsAtEnd();
  3625. + script_it.Advance()) {
  3626. + const std::string& key = script_it.key();
  3627. +
  3628. + if (std::find(all_scripts.begin(), all_scripts.end(), key) == all_scripts.end()) {
  3629. + all_scripts_to_remove.push_back(key);
  3630. + }
  3631. + }
  3632. +
  3633. + DictionaryPrefUpdate update(prefs_, kUserScriptsList);
  3634. + base::DictionaryValue* const update_dict = update.Get();
  3635. + for (auto key : all_scripts_to_remove) {
  3636. + update_dict->RemoveKey(key);
  3637. + }
  3638. +
  3639. + return;
  3640. +}
  3641. +
  3642. +std::string UserScriptsPrefs::GetScriptsInfo() {
  3643. + std::string json_string;
  3644. +
  3645. + const base::DictionaryValue* dict =
  3646. + prefs_->GetDictionary(kUserScriptsList);
  3647. +
  3648. + if (dict) {
  3649. + base::JSONWriter::WriteWithOptions(
  3650. + *dict, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json_string);
  3651. + base::TrimWhitespaceASCII(json_string, base::TRIM_ALL, &json_string);
  3652. + }
  3653. +
  3654. + return json_string;
  3655. +}
  3656. +
  3657. +std::unique_ptr<UserScriptsListPrefs::ScriptInfo> UserScriptsPrefs::CreateScriptInfoFromPrefs(
  3658. + const std::string& script_id) const {
  3659. +
  3660. + auto scriptInfo = std::make_unique<UserScriptsListPrefs::ScriptInfo>(
  3661. + script_id, "", base::Time::Now(), false);
  3662. +
  3663. + const base::DictionaryValue* scripts =
  3664. + prefs_->GetDictionary(kUserScriptsList);
  3665. + if (!scripts)
  3666. + return scriptInfo;
  3667. +
  3668. + const base::DictionaryValue* script = static_cast<const base::DictionaryValue*>(
  3669. + scripts->FindDictKey(script_id));
  3670. + if (!script)
  3671. + return scriptInfo;
  3672. +
  3673. + const std::string* name = script->FindStringKey(kScriptName);
  3674. + const std::string* description = script->FindStringKey(kScriptDescription);
  3675. + const std::string* version = script->FindStringKey(kScriptVersion);
  3676. + const std::string* file_path = script->FindStringKey(kScriptFilePath);
  3677. + const std::string* url_source = script->FindStringKey(kScriptUrlSource);
  3678. +
  3679. + scriptInfo->set_name( name ? *name : "no name" );
  3680. + scriptInfo->set_description( description ? *description : "no description" );
  3681. + scriptInfo->set_version( version ? *version : "no version" );
  3682. + scriptInfo->enabled = script->FindBoolKey(kScriptIsEnabled).value_or(false);
  3683. + scriptInfo->set_file_path( file_path ? *file_path : "no file path" );
  3684. + scriptInfo->set_url_source( url_source ? *url_source : "" );
  3685. +
  3686. + int64_t time_interval = 0;
  3687. + if (GetInt64FromPref(script, kScriptInstallTime, &time_interval)) {
  3688. + scriptInfo->install_time = base::Time::FromInternalValue(time_interval);
  3689. + }
  3690. +
  3691. + return scriptInfo;
  3692. +}
  3693. +
  3694. +void UserScriptsPrefs::RemoveScriptFromPrefs(const std::string& script_id) {
  3695. + DictionaryPrefUpdate update(prefs_, kUserScriptsList);
  3696. + base::DictionaryValue* const update_dict = update.Get();
  3697. + update_dict->RemoveKey(script_id);
  3698. +}
  3699. +
  3700. +void UserScriptsPrefs::SetScriptEnabled(const std::string& script_id, bool is_enabled) {
  3701. + PrefUpdate update(prefs_, script_id, kUserScriptsList);
  3702. + base::DictionaryValue* script_dict = update.Get();
  3703. + script_dict->SetBoolean(kScriptIsEnabled, is_enabled);
  3704. +}
  3705. +
  3706. +}
  3707. diff --git a/components/user_scripts/browser/user_script_prefs.h b/components/user_scripts/browser/user_script_prefs.h
  3708. new file mode 100644
  3709. --- /dev/null
  3710. +++ b/components/user_scripts/browser/user_script_prefs.h
  3711. @@ -0,0 +1,58 @@
  3712. +/*
  3713. + This file is part of Bromite.
  3714. +
  3715. + Bromite is free software: you can redistribute it and/or modify
  3716. + it under the terms of the GNU General Public License as published by
  3717. + the Free Software Foundation, either version 3 of the License, or
  3718. + (at your option) any later version.
  3719. +
  3720. + Bromite is distributed in the hope that it will be useful,
  3721. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  3722. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  3723. + GNU General Public License for more details.
  3724. +
  3725. + You should have received a copy of the GNU General Public License
  3726. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  3727. +*/
  3728. +
  3729. +#ifndef USERSCRIPTS_BROWSER_USERSCRIPT_PREFS_H_
  3730. +#define USERSCRIPTS_BROWSER_USERSCRIPT_PREFS_H_
  3731. +
  3732. +#include "content/public/browser/browser_context.h"
  3733. +#include "components/prefs/pref_service.h"
  3734. +#include "components/pref_registry/pref_registry_syncable.h"
  3735. +
  3736. +#include "user_script_pref_info.h"
  3737. +#include "../common/user_script.h"
  3738. +
  3739. +namespace user_scripts {
  3740. +
  3741. +class UserScriptsPrefs {
  3742. + public:
  3743. + UserScriptsPrefs(
  3744. + PrefService* prefs);
  3745. +
  3746. + static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
  3747. +
  3748. + bool IsEnabled();
  3749. + void SetEnabled(bool enabled);
  3750. +
  3751. + void StartupTryout(int number);
  3752. + int GetCurrentStartupTryout();
  3753. +
  3754. + void CompareWithPrefs(UserScriptList& user_scripts);
  3755. +
  3756. + std::string GetScriptsInfo();
  3757. + void RemoveScriptFromPrefs(const std::string& script_id);
  3758. + void SetScriptEnabled(const std::string& script_id, bool is_enabled);
  3759. +
  3760. + std::unique_ptr<UserScriptsListPrefs::ScriptInfo> CreateScriptInfoFromPrefs(
  3761. + const std::string& script_id) const;
  3762. +
  3763. + private:
  3764. + PrefService* prefs_;
  3765. +};
  3766. +
  3767. +}
  3768. +
  3769. +#endif // USERSCRIPTS_BROWSER_USERSCRIPT_PREFS_H_
  3770. \ No newline at end of file
  3771. diff --git a/components/user_scripts/browser/userscripts_browser_client.cc b/components/user_scripts/browser/userscripts_browser_client.cc
  3772. new file mode 100755
  3773. --- /dev/null
  3774. +++ b/components/user_scripts/browser/userscripts_browser_client.cc
  3775. @@ -0,0 +1,79 @@
  3776. +/*
  3777. + This file is part of Bromite.
  3778. +
  3779. + Bromite is free software: you can redistribute it and/or modify
  3780. + it under the terms of the GNU General Public License as published by
  3781. + the Free Software Foundation, either version 3 of the License, or
  3782. + (at your option) any later version.
  3783. +
  3784. + Bromite is distributed in the hope that it will be useful,
  3785. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  3786. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  3787. + GNU General Public License for more details.
  3788. +
  3789. + You should have received a copy of the GNU General Public License
  3790. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  3791. +*/
  3792. +
  3793. +#include "userscripts_browser_client.h"
  3794. +
  3795. +#include "base/logging.h"
  3796. +
  3797. +#include "chrome/browser/browser_process.h"
  3798. +
  3799. +#include "chrome/browser/profiles/profile.h"
  3800. +#include "chrome/browser/profiles/profile_manager.h"
  3801. +
  3802. +#include "../common/user_scripts_features.h"
  3803. +#include "user_script_loader.h"
  3804. +#include "file_task_runner.h"
  3805. +#include "user_script_prefs.h"
  3806. +
  3807. +namespace user_scripts {
  3808. +
  3809. +namespace {
  3810. +
  3811. +// remember: was ExtensionsBrowserClient
  3812. +UserScriptsBrowserClient* g_userscripts_browser_client = NULL;
  3813. +
  3814. +} // namespace
  3815. +
  3816. +UserScriptsBrowserClient::UserScriptsBrowserClient() {}
  3817. +
  3818. +UserScriptsBrowserClient::~UserScriptsBrowserClient() = default;
  3819. +
  3820. +// static
  3821. +UserScriptsBrowserClient* UserScriptsBrowserClient::GetInstance() {
  3822. + // only for browser process
  3823. + if(!g_browser_process)
  3824. + return NULL;
  3825. +
  3826. + if (base::FeatureList::IsEnabled(features::kEnableUserScripts) == false)
  3827. + return NULL;
  3828. +
  3829. + // singleton
  3830. + if(g_userscripts_browser_client)
  3831. + return g_userscripts_browser_client;
  3832. +
  3833. + // make file task runner
  3834. + GetUserScriptsFileTaskRunner().get();
  3835. +
  3836. + // new instance singleton
  3837. + g_userscripts_browser_client = new UserScriptsBrowserClient();
  3838. +
  3839. + return g_userscripts_browser_client;
  3840. +}
  3841. +
  3842. +void UserScriptsBrowserClient::SetProfile(content::BrowserContext* context) {
  3843. + browser_context_ = context;
  3844. +
  3845. + prefs_ =
  3846. + std::make_unique<user_scripts::UserScriptsPrefs>(
  3847. + static_cast<Profile*>(context)->GetPrefs());
  3848. +
  3849. + userscript_loader_ =
  3850. + std::make_unique<user_scripts::UserScriptLoader>(browser_context_, prefs_.get());
  3851. + userscript_loader_->SetReady(true);
  3852. +}
  3853. +
  3854. +} // namespace user_scripts
  3855. diff --git a/components/user_scripts/browser/userscripts_browser_client.h b/components/user_scripts/browser/userscripts_browser_client.h
  3856. new file mode 100755
  3857. --- /dev/null
  3858. +++ b/components/user_scripts/browser/userscripts_browser_client.h
  3859. @@ -0,0 +1,62 @@
  3860. +/*
  3861. + This file is part of Bromite.
  3862. +
  3863. + Bromite is free software: you can redistribute it and/or modify
  3864. + it under the terms of the GNU General Public License as published by
  3865. + the Free Software Foundation, either version 3 of the License, or
  3866. + (at your option) any later version.
  3867. +
  3868. + Bromite is distributed in the hope that it will be useful,
  3869. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  3870. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  3871. + GNU General Public License for more details.
  3872. +
  3873. + You should have received a copy of the GNU General Public License
  3874. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  3875. +*/
  3876. +
  3877. +#ifndef USERSCRIPTS_BROWSER_USERSCRIPTS_BROWSER_CLIENT_H_
  3878. +#define USERSCRIPTS_BROWSER_USERSCRIPTS_BROWSER_CLIENT_H_
  3879. +
  3880. +#include <memory>
  3881. +#include <string>
  3882. +#include <vector>
  3883. +
  3884. +#include "content/public/browser/browser_context.h"
  3885. +
  3886. +#include "../common/user_script.h"
  3887. +#include "user_script_loader.h"
  3888. +#include "user_script_prefs.h"
  3889. +
  3890. +namespace user_scripts {
  3891. +
  3892. +class UserScriptsBrowserClient {
  3893. + public:
  3894. + UserScriptsBrowserClient();
  3895. + UserScriptsBrowserClient(const UserScriptsBrowserClient&) = delete;
  3896. + UserScriptsBrowserClient& operator=(const UserScriptsBrowserClient&) = delete;
  3897. + virtual ~UserScriptsBrowserClient();
  3898. +
  3899. + // Returns the single instance of |this|.
  3900. + static UserScriptsBrowserClient* GetInstance();
  3901. +
  3902. + void SetProfile(content::BrowserContext* context);
  3903. +
  3904. + user_scripts::UserScriptsPrefs* GetPrefs() {
  3905. + return prefs_.get();
  3906. + }
  3907. +
  3908. + user_scripts::UserScriptLoader* GetLoader() {
  3909. + return userscript_loader_.get();
  3910. + }
  3911. +
  3912. + private:
  3913. + std::unique_ptr<UserScriptList> scripts_;
  3914. + content::BrowserContext* browser_context_;
  3915. + std::unique_ptr<user_scripts::UserScriptsPrefs> prefs_;
  3916. + std::unique_ptr<user_scripts::UserScriptLoader> userscript_loader_;
  3917. +};
  3918. +
  3919. +} // namespace extensions
  3920. +
  3921. +#endif // USERSCRIPTS_BROWSER_USERSCRIPTS_BROWSER_CLIENT_H_
  3922. diff --git a/components/user_scripts/common/BUILD.gn b/components/user_scripts/common/BUILD.gn
  3923. new file mode 100755
  3924. --- /dev/null
  3925. +++ b/components/user_scripts/common/BUILD.gn
  3926. @@ -0,0 +1,52 @@
  3927. +# Copyright 2014 The Chromium Authors. All rights reserved.
  3928. +# Use of this source code is governed by a BSD-style license that can be
  3929. +# found in the LICENSE file.
  3930. +
  3931. +import("//build/config/features.gni")
  3932. +import("//mojo/public/tools/bindings/mojom.gni")
  3933. +
  3934. +static_library("common") {
  3935. + sources = [
  3936. + "user_scripts_features.cc",
  3937. + "user_scripts_features.h",
  3938. + "constants.h",
  3939. + "host_id.cc",
  3940. + "host_id.h",
  3941. + "script_constants.h",
  3942. + "url_pattern_set.cc",
  3943. + "url_pattern_set.h",
  3944. + "url_pattern.cc",
  3945. + "url_pattern.h",
  3946. + "user_script.cc",
  3947. + "user_script.h",
  3948. + "view_type.cc",
  3949. + "view_type.h",
  3950. + "extension_messages.cc",
  3951. + "extension_messages.h",
  3952. + "extension_message_generator.cc",
  3953. + "extension_message_generator.h",
  3954. + ]
  3955. +
  3956. + configs += [
  3957. + "//build/config:precompiled_headers",
  3958. +
  3959. + # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
  3960. + "//build/config/compiler:no_size_t_to_int_warning",
  3961. + "//build/config/compiler:wexit_time_destructors",
  3962. + ]
  3963. +
  3964. + public_deps = [
  3965. + "//components/services/app_service/public/cpp:app_file_handling",
  3966. + "//content/public/common",
  3967. + "//ipc",
  3968. + "//skia",
  3969. + ]
  3970. +
  3971. + deps = [
  3972. + "//base",
  3973. + "//components/url_formatter",
  3974. + "//components/url_matcher",
  3975. + "//components/version_info",
  3976. + "//crypto",
  3977. + ]
  3978. +}
  3979. diff --git a/components/user_scripts/common/constants.h b/components/user_scripts/common/constants.h
  3980. new file mode 100755
  3981. --- /dev/null
  3982. +++ b/components/user_scripts/common/constants.h
  3983. @@ -0,0 +1,21 @@
  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. +#ifndef USERSCRIPTS_COMMON_CONSTANTS_H_
  3989. +#define USERSCRIPTS_COMMON_CONSTANTS_H_
  3990. +
  3991. +#include "base/files/file_path.h"
  3992. +#include "base/strings/string_piece_forward.h"
  3993. +#include "components/services/app_service/public/mojom/types.mojom.h"
  3994. +#include "components/version_info/channel.h"
  3995. +#include "ui/base/layout.h"
  3996. +
  3997. +namespace user_scripts {
  3998. +
  3999. +// The origin of injected CSS.
  4000. +enum CSSOrigin { /*CSS_ORIGIN_AUTHOR,*/ CSS_ORIGIN_USER };
  4001. +
  4002. +} // namespace user_scripts
  4003. +
  4004. +#endif // USERSCRIPTS_COMMON_CONSTANTS_H_
  4005. diff --git a/components/user_scripts/common/error_utils.cc b/components/user_scripts/common/error_utils.cc
  4006. new file mode 100755
  4007. --- /dev/null
  4008. +++ b/components/user_scripts/common/error_utils.cc
  4009. @@ -0,0 +1,54 @@
  4010. +// Copyright (c) 2011 The Chromium Authors. All rights reserved.
  4011. +// Use of this source code is governed by a BSD-style license that can be
  4012. +// found in the LICENSE file.
  4013. +
  4014. +#include "error_utils.h"
  4015. +
  4016. +#include <initializer_list>
  4017. +
  4018. +#include "base/check_op.h"
  4019. +#include "base/strings/string_tokenizer.h"
  4020. +#include "base/strings/string_util.h"
  4021. +#include "base/strings/utf_string_conversions.h"
  4022. +
  4023. +namespace user_scripts {
  4024. +
  4025. +namespace {
  4026. +
  4027. +std::string FormatErrorMessageInternal(
  4028. + base::StringPiece format,
  4029. + std::initializer_list<base::StringPiece> args) {
  4030. + std::string format_str = format.as_string();
  4031. + base::StringTokenizer tokenizer(format_str, "*");
  4032. + tokenizer.set_options(base::StringTokenizer::RETURN_DELIMS);
  4033. +
  4034. + std::vector<base::StringPiece> result_pieces;
  4035. + auto* args_it = args.begin();
  4036. + while (tokenizer.GetNext()) {
  4037. + if (!tokenizer.token_is_delim()) {
  4038. + result_pieces.push_back(tokenizer.token_piece());
  4039. + continue;
  4040. + }
  4041. +
  4042. + CHECK_NE(args_it, args.end())
  4043. + << "More placeholders (*) than substitutions.";
  4044. +
  4045. + // Substitute the argument.
  4046. + result_pieces.push_back(*args_it);
  4047. + args_it++;
  4048. + }
  4049. +
  4050. + // Not all substitutions were consumed.
  4051. + CHECK_EQ(args_it, args.end()) << "Fewer placeholders (*) than substitutions.";
  4052. +
  4053. + return base::JoinString(result_pieces, "" /* separator */);
  4054. +}
  4055. +
  4056. +} // namespace
  4057. +
  4058. +std::string ErrorUtils::FormatErrorMessage(base::StringPiece format,
  4059. + base::StringPiece s1) {
  4060. + return FormatErrorMessageInternal(format, {s1});
  4061. +}
  4062. +
  4063. +} // namespace user_scripts
  4064. diff --git a/components/user_scripts/common/error_utils.h b/components/user_scripts/common/error_utils.h
  4065. new file mode 100755
  4066. --- /dev/null
  4067. +++ b/components/user_scripts/common/error_utils.h
  4068. @@ -0,0 +1,25 @@
  4069. +// Copyright (c) 2011 The Chromium Authors. All rights reserved.
  4070. +// Use of this source code is governed by a BSD-style license that can be
  4071. +// found in the LICENSE file.
  4072. +
  4073. +#ifndef USERSCRIPTS_COMMON_ERROR_UTILS_H_
  4074. +#define USERSCRIPTS_COMMON_ERROR_UTILS_H_
  4075. +
  4076. +#include <string>
  4077. +
  4078. +#include "base/strings/string16.h"
  4079. +#include "base/strings/string_piece.h"
  4080. +
  4081. +namespace user_scripts {
  4082. +
  4083. +class ErrorUtils {
  4084. + public:
  4085. + // Creates an error messages from a pattern.
  4086. + static std::string FormatErrorMessage(base::StringPiece format,
  4087. + base::StringPiece s1);
  4088. +
  4089. +};
  4090. +
  4091. +} // namespace extensions
  4092. +
  4093. +#endif // USERSCRIPTS_COMMON_ERROR_UTILS_H_
  4094. diff --git a/components/user_scripts/common/extension_message_generator.cc b/components/user_scripts/common/extension_message_generator.cc
  4095. new file mode 100755
  4096. --- /dev/null
  4097. +++ b/components/user_scripts/common/extension_message_generator.cc
  4098. @@ -0,0 +1,29 @@
  4099. +// Copyright 2014 The Chromium Authors. All rights reserved.
  4100. +// Use of this source code is governed by a BSD-style license that can be
  4101. +// found in the LICENSE file.
  4102. +
  4103. +// Get basic type definitions.
  4104. +#define IPC_MESSAGE_IMPL
  4105. +#include "components/user_scripts/common/extension_message_generator.h"
  4106. +
  4107. +// Generate constructors.
  4108. +#include "ipc/struct_constructor_macros.h"
  4109. +#include "components/user_scripts/common/extension_message_generator.h"
  4110. +
  4111. +// Generate param traits write methods.
  4112. +#include "ipc/param_traits_write_macros.h"
  4113. +namespace IPC {
  4114. +#include "components/user_scripts/common/extension_message_generator.h"
  4115. +} // namespace IPC
  4116. +
  4117. +// Generate param traits read methods.
  4118. +#include "ipc/param_traits_read_macros.h"
  4119. +namespace IPC {
  4120. +#include "components/user_scripts/common/extension_message_generator.h"
  4121. +} // namespace IPC
  4122. +
  4123. +// Generate param traits log methods.
  4124. +#include "ipc/param_traits_log_macros.h"
  4125. +namespace IPC {
  4126. +#include "components/user_scripts/common/extension_message_generator.h"
  4127. +} // namespace IPC
  4128. diff --git a/components/user_scripts/common/extension_message_generator.h b/components/user_scripts/common/extension_message_generator.h
  4129. new file mode 100755
  4130. --- /dev/null
  4131. +++ b/components/user_scripts/common/extension_message_generator.h
  4132. @@ -0,0 +1,11 @@
  4133. +// Copyright 2014 The Chromium Authors. All rights reserved.
  4134. +// Use of this source code is governed by a BSD-style license that can be
  4135. +// found in the LICENSE file.
  4136. +
  4137. +// Multiply-included file, hence no include guard.
  4138. +
  4139. +#undef EXTENSIONS_COMMON_EXTENSION_MESSAGES_H_
  4140. +#include "extension_messages.h"
  4141. +#ifndef EXTENSIONS_COMMON_EXTENSION_MESSAGES_H_
  4142. +#error "Failed to include header extension_messages.h"
  4143. +#endif
  4144. diff --git a/components/user_scripts/common/extension_messages.cc b/components/user_scripts/common/extension_messages.cc
  4145. new file mode 100755
  4146. --- /dev/null
  4147. +++ b/components/user_scripts/common/extension_messages.cc
  4148. @@ -0,0 +1,40 @@
  4149. +// Copyright 2014 The Chromium Authors. All rights reserved.
  4150. +// Use of this source code is governed by a BSD-style license that can be
  4151. +// found in the LICENSE file.
  4152. +
  4153. +#include "extension_messages.h"
  4154. +
  4155. +#include <stddef.h>
  4156. +
  4157. +#include <memory>
  4158. +#include <utility>
  4159. +
  4160. +#include "content/public/common/common_param_traits.h"
  4161. +
  4162. +namespace IPC {
  4163. +
  4164. +void ParamTraits<HostID>::Write(base::Pickle* m, const param_type& p) {
  4165. + WriteParam(m, p.type());
  4166. + WriteParam(m, p.id());
  4167. +}
  4168. +
  4169. +bool ParamTraits<HostID>::Read(const base::Pickle* m,
  4170. + base::PickleIterator* iter,
  4171. + param_type* r) {
  4172. + HostID::HostType type;
  4173. + std::string id;
  4174. + if (!ReadParam(m, iter, &type))
  4175. + return false;
  4176. + if (!ReadParam(m, iter, &id))
  4177. + return false;
  4178. + *r = HostID(type, id);
  4179. + return true;
  4180. +}
  4181. +
  4182. +void ParamTraits<HostID>::Log(
  4183. + const param_type& p, std::string* l) {
  4184. + LogParam(p.type(), l);
  4185. + LogParam(p.id(), l);
  4186. +}
  4187. +
  4188. +} // namespace IPC
  4189. diff --git a/components/user_scripts/common/extension_messages.h b/components/user_scripts/common/extension_messages.h
  4190. new file mode 100755
  4191. --- /dev/null
  4192. +++ b/components/user_scripts/common/extension_messages.h
  4193. @@ -0,0 +1,70 @@
  4194. +// Copyright 2014 The Chromium Authors. All rights reserved.
  4195. +// Use of this source code is governed by a BSD-style license that can be
  4196. +// found in the LICENSE file.
  4197. +
  4198. +// IPC messages for extensions.
  4199. +
  4200. +#ifndef EXTENSIONS_COMMON_EXTENSION_MESSAGES_H_
  4201. +#define EXTENSIONS_COMMON_EXTENSION_MESSAGES_H_
  4202. +
  4203. +#include <stdint.h>
  4204. +
  4205. +#include <map>
  4206. +#include <memory>
  4207. +#include <set>
  4208. +#include <string>
  4209. +#include <vector>
  4210. +
  4211. +#include "base/macros.h"
  4212. +#include "base/memory/read_only_shared_memory_region.h"
  4213. +#include "base/values.h"
  4214. +#include "content/public/common/common_param_traits.h"
  4215. +#include "constants.h"
  4216. +#include "host_id.h"
  4217. +#include "ipc/ipc_message_macros.h"
  4218. +#include "url/gurl.h"
  4219. +#include "url/origin.h"
  4220. +
  4221. +#define IPC_MESSAGE_START ExtensionMsgStart
  4222. +
  4223. +IPC_ENUM_TRAITS_MAX_VALUE(HostID::HostType, HostID::HOST_TYPE_LAST)
  4224. +
  4225. +// Singly-included section for custom IPC traits.
  4226. +#ifndef INTERNAL_EXTENSIONS_COMMON_EXTENSION_MESSAGES_H_
  4227. +#define INTERNAL_EXTENSIONS_COMMON_EXTENSION_MESSAGES_H_
  4228. +
  4229. +namespace IPC {
  4230. +
  4231. +template <>
  4232. +struct ParamTraits<HostID> {
  4233. + typedef HostID param_type;
  4234. + static void Write(base::Pickle* m, const param_type& p);
  4235. + static bool Read(const base::Pickle* m,
  4236. + base::PickleIterator* iter,
  4237. + param_type* r);
  4238. + static void Log(const param_type& p, std::string* l);
  4239. +};
  4240. +
  4241. +
  4242. +} // namespace IPC
  4243. +
  4244. +#endif // INTERNAL_EXTENSIONS_COMMON_EXTENSION_MESSAGES_H_
  4245. +
  4246. +// Notification that the user scripts have been updated. It has one
  4247. +// ReadOnlySharedMemoryRegion argument consisting of the pickled script data.
  4248. +// This memory region is valid in the context of the renderer.
  4249. +// If |owner| is not empty, then the shared memory handle refers to |owner|'s
  4250. +// programmatically-defined scripts. Otherwise, the handle refers to all
  4251. +// hosts' statically defined scripts. So far, only extension-hosts support
  4252. +// statically defined scripts; WebUI-hosts don't.
  4253. +// If |changed_hosts| is not empty, only the host in that set will
  4254. +// be updated. Otherwise, all hosts that have scripts in the shared memory
  4255. +// region will be updated. Note that the empty set => all hosts case is not
  4256. +// supported for per-extension programmatically-defined script regions; in such
  4257. +// regions, the owner is expected to list itself as the only changed host.
  4258. +// If |whitelisted_only| is true, this process should only run whitelisted
  4259. +// scripts and not all user scripts.
  4260. +IPC_MESSAGE_CONTROL1(ExtensionMsg_UpdateUserScripts,
  4261. + base::ReadOnlySharedMemoryRegion)
  4262. +
  4263. +#endif // EXTENSIONS_COMMON_EXTENSION_MESSAGES_H_
  4264. diff --git a/components/user_scripts/common/host_id.cc b/components/user_scripts/common/host_id.cc
  4265. new file mode 100755
  4266. --- /dev/null
  4267. +++ b/components/user_scripts/common/host_id.cc
  4268. @@ -0,0 +1,31 @@
  4269. +// Copyright 2015 The Chromium Authors. All rights reserved.
  4270. +// Use of this source code is governed by a BSD-style license that can be
  4271. +// found in the LICENSE file.
  4272. +
  4273. +#include "host_id.h"
  4274. +
  4275. +#include <tuple>
  4276. +
  4277. +HostID::HostID()
  4278. + : type_(HostType::EXTENSIONS) {
  4279. +}
  4280. +
  4281. +HostID::HostID(HostType type, const std::string& id)
  4282. + : type_(type), id_(id) {
  4283. +}
  4284. +
  4285. +HostID::HostID(const HostID& host_id)
  4286. + : type_(host_id.type()),
  4287. + id_(host_id.id()) {
  4288. +}
  4289. +
  4290. +HostID::~HostID() {
  4291. +}
  4292. +
  4293. +bool HostID::operator<(const HostID& host_id) const {
  4294. + return std::tie(type_, id_) < std::tie(host_id.type_, host_id.id_);
  4295. +}
  4296. +
  4297. +bool HostID::operator==(const HostID& host_id) const {
  4298. + return type_ == host_id.type_ && id_ == host_id.id_;
  4299. +}
  4300. diff --git a/components/user_scripts/common/host_id.h b/components/user_scripts/common/host_id.h
  4301. new file mode 100755
  4302. --- /dev/null
  4303. +++ b/components/user_scripts/common/host_id.h
  4304. @@ -0,0 +1,35 @@
  4305. +// Copyright 2015 The Chromium Authors. All rights reserved.
  4306. +// Use of this source code is governed by a BSD-style license that can be
  4307. +// found in the LICENSE file.
  4308. +
  4309. +#ifndef USERSCRIPTS_COMMON_HOST_ID_H_
  4310. +#define USERSCRIPTS_COMMON_HOST_ID_H_
  4311. +
  4312. +#include <string>
  4313. +
  4314. +// IDs of hosts who own user scripts.
  4315. +// A HostID is immutable after creation.
  4316. +struct HostID {
  4317. + enum HostType { EXTENSIONS, WEBUI, HOST_TYPE_LAST = WEBUI };
  4318. +
  4319. + HostID();
  4320. + HostID(HostType type, const std::string& id);
  4321. + HostID(const HostID& host_id);
  4322. + ~HostID();
  4323. +
  4324. + bool operator<(const HostID& host_id) const;
  4325. + bool operator==(const HostID& host_id) const;
  4326. +
  4327. + HostType type() const { return type_; }
  4328. + const std::string& id() const { return id_; }
  4329. +
  4330. + private:
  4331. + // The type of the host.
  4332. + HostType type_;
  4333. +
  4334. + // Similar to extension_id, host_id is a unique indentifier for a host,
  4335. + // e.g., an Extension or WebUI.
  4336. + std::string id_;
  4337. +};
  4338. +
  4339. +#endif // USERSCRIPTS_COMMON_HOST_ID_H_
  4340. diff --git a/components/user_scripts/common/script_constants.h b/components/user_scripts/common/script_constants.h
  4341. new file mode 100755
  4342. --- /dev/null
  4343. +++ b/components/user_scripts/common/script_constants.h
  4344. @@ -0,0 +1,33 @@
  4345. +// Copyright 2020 The Chromium Authors. All rights reserved.
  4346. +// Use of this source code is governed by a BSD-style license that can be
  4347. +// found in the LICENSE file.
  4348. +
  4349. +#ifndef USERSCRIPTS_COMMON_SCRIPT_CONSTANTS_H_
  4350. +#define USERSCRIPTS_COMMON_SCRIPT_CONSTANTS_H_
  4351. +
  4352. +namespace user_scripts {
  4353. +
  4354. +// Whether to fall back to matching the origin for frames where the URL
  4355. +// cannot be matched directly, such as those with about: or data: schemes.
  4356. +enum class MatchOriginAsFallbackBehavior {
  4357. + // Never fall back on the origin; this means scripts will never match on
  4358. + // these frames.
  4359. + kNever,
  4360. + // Match the origin only for about:-scheme frames, and then climb the frame
  4361. + // tree to find an appropriate ancestor to get a full URL (including path).
  4362. + // This is for supporting the "match_about_blank" key.
  4363. + // TODO(devlin): I wonder if we could simplify this to be "MatchForAbout",
  4364. + // and not worry about climbing the frame tree. It would be a behavior
  4365. + // change, but I wonder how many extensions it would impact in practice.
  4366. + kMatchForAboutSchemeAndClimbTree,
  4367. + // Match the origin as a fallback whenever applicable. This won't have a
  4368. + // corresponding path.
  4369. + kAlways,
  4370. +};
  4371. +
  4372. +// TODO(devlin): Move the other non-UserScript-specific constants like
  4373. +// RunLocation and InjectionType from UserScript into here.
  4374. +
  4375. +}
  4376. +
  4377. +#endif // USERSCRIPTS_COMMON_SCRIPT_CONSTANTS_H_
  4378. diff --git a/components/user_scripts/common/url_pattern.cc b/components/user_scripts/common/url_pattern.cc
  4379. new file mode 100755
  4380. --- /dev/null
  4381. +++ b/components/user_scripts/common/url_pattern.cc
  4382. @@ -0,0 +1,807 @@
  4383. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  4384. +// Use of this source code is governed by a BSD-style license that can be
  4385. +// found in the LICENSE file.
  4386. +
  4387. +#include "url_pattern.h"
  4388. +
  4389. +#include <stddef.h>
  4390. +
  4391. +#include <ostream>
  4392. +
  4393. +#include "base/logging.h"
  4394. +#include "base/stl_util.h"
  4395. +#include "base/strings/pattern.h"
  4396. +#include "base/strings/strcat.h"
  4397. +#include "base/strings/string_number_conversions.h"
  4398. +#include "base/strings/string_split.h"
  4399. +#include "base/strings/string_util.h"
  4400. +#include "base/strings/stringprintf.h"
  4401. +#include "content/public/common/url_constants.h"
  4402. +#include "constants.h"
  4403. +#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
  4404. +#include "net/base/url_util.h"
  4405. +#include "url/gurl.h"
  4406. +#include "url/url_util.h"
  4407. +
  4408. +const char URLPattern::kAllUrlsPattern[] = "<all_urls>";
  4409. +
  4410. +namespace {
  4411. +
  4412. +// TODO(aa): What about more obscure schemes like javascript: ?
  4413. +// Note: keep this array in sync with kValidSchemeMasks.
  4414. +const char* const kValidSchemes[] = {
  4415. + url::kHttpScheme, url::kHttpsScheme,
  4416. + url::kFileScheme, url::kFtpScheme,
  4417. + /*content::kChromeUIScheme,*/ /*extensions::kExtensionScheme,*/
  4418. + url::kFileSystemScheme, url::kWsScheme,
  4419. + url::kWssScheme, url::kDataScheme,
  4420. +};
  4421. +
  4422. +const int kValidSchemeMasks[] = {
  4423. + URLPattern::SCHEME_HTTP, URLPattern::SCHEME_HTTPS,
  4424. + URLPattern::SCHEME_FILE, URLPattern::SCHEME_FTP,
  4425. + /*URLPattern::SCHEME_CHROMEUI,*/ /*URLPattern::SCHEME_EXTENSION,*/
  4426. + URLPattern::SCHEME_FILESYSTEM, URLPattern::SCHEME_WS,
  4427. + URLPattern::SCHEME_WSS, URLPattern::SCHEME_DATA,
  4428. +};
  4429. +
  4430. +static_assert(base::size(kValidSchemes) == base::size(kValidSchemeMasks),
  4431. + "must keep these arrays in sync");
  4432. +
  4433. +const char kParseSuccess[] = "Success.";
  4434. +const char kParseErrorMissingSchemeSeparator[] = "Missing scheme separator.";
  4435. +const char kParseErrorInvalidScheme[] = "Invalid scheme.";
  4436. +const char kParseErrorWrongSchemeType[] = "Wrong scheme type.";
  4437. +const char kParseErrorEmptyHost[] = "Host can not be empty.";
  4438. +const char kParseErrorInvalidHostWildcard[] = "Invalid host wildcard.";
  4439. +const char kParseErrorEmptyPath[] = "Empty path.";
  4440. +const char kParseErrorInvalidPort[] = "Invalid port.";
  4441. +const char kParseErrorInvalidHost[] = "Invalid host.";
  4442. +
  4443. +// Message explaining each URLPattern::ParseResult.
  4444. +const char* const kParseResultMessages[] = {
  4445. + kParseSuccess,
  4446. + kParseErrorMissingSchemeSeparator,
  4447. + kParseErrorInvalidScheme,
  4448. + kParseErrorWrongSchemeType,
  4449. + kParseErrorEmptyHost,
  4450. + kParseErrorInvalidHostWildcard,
  4451. + kParseErrorEmptyPath,
  4452. + kParseErrorInvalidPort,
  4453. + kParseErrorInvalidHost,
  4454. +};
  4455. +
  4456. +static_assert(static_cast<int>(URLPattern::ParseResult::kNumParseResults) ==
  4457. + base::size(kParseResultMessages),
  4458. + "must add message for each parse result");
  4459. +
  4460. +const char kPathSeparator[] = "/";
  4461. +
  4462. +bool IsStandardScheme(base::StringPiece scheme) {
  4463. + // "*" gets the same treatment as a standard scheme.
  4464. + if (scheme == "*")
  4465. + return true;
  4466. +
  4467. + return url::IsStandard(scheme.data(),
  4468. + url::Component(0, static_cast<int>(scheme.length())));
  4469. +}
  4470. +
  4471. +bool IsValidPortForScheme(base::StringPiece scheme, base::StringPiece port) {
  4472. + if (port == "*")
  4473. + return true;
  4474. +
  4475. + // Only accept non-wildcard ports if the scheme uses ports.
  4476. + if (url::DefaultPortForScheme(scheme.data(), scheme.length()) ==
  4477. + url::PORT_UNSPECIFIED) {
  4478. + return false;
  4479. + }
  4480. +
  4481. + int parsed_port = url::PORT_UNSPECIFIED;
  4482. + if (!base::StringToInt(port, &parsed_port))
  4483. + return false;
  4484. + return (parsed_port >= 0) && (parsed_port < 65536);
  4485. +}
  4486. +
  4487. +// Returns |path| with the trailing wildcard stripped if one existed.
  4488. +//
  4489. +// The functions that rely on this (OverlapsWith and Contains) are only
  4490. +// called for the patterns inside URLPatternSet. In those cases, we know that
  4491. +// the path will have only a single wildcard at the end. This makes figuring
  4492. +// out overlap much easier. It seems like there is probably a computer-sciency
  4493. +// way to solve the general case, but we don't need that yet.
  4494. +base::StringPiece StripTrailingWildcard(base::StringPiece path) {
  4495. + if (base::EndsWith(path, "*"))
  4496. + path.remove_suffix(1);
  4497. + return path;
  4498. +}
  4499. +
  4500. +// Removes trailing dot from |host_piece| if any.
  4501. +base::StringPiece CanonicalizeHostForMatching(base::StringPiece host_piece) {
  4502. + if (base::EndsWith(host_piece, "."))
  4503. + host_piece.remove_suffix(1);
  4504. + return host_piece;
  4505. +}
  4506. +
  4507. +} // namespace
  4508. +
  4509. +// static
  4510. +bool URLPattern::IsValidSchemeForExtensions(base::StringPiece scheme) {
  4511. + for (size_t i = 0; i < base::size(kValidSchemes); ++i) {
  4512. + if (scheme == kValidSchemes[i])
  4513. + return true;
  4514. + }
  4515. + return false;
  4516. +}
  4517. +
  4518. +// static
  4519. +int URLPattern::GetValidSchemeMaskForExtensions() {
  4520. + int result = 0;
  4521. + for (size_t i = 0; i < base::size(kValidSchemeMasks); ++i)
  4522. + result |= kValidSchemeMasks[i];
  4523. + return result;
  4524. +}
  4525. +
  4526. +URLPattern::URLPattern()
  4527. + : valid_schemes_(SCHEME_NONE),
  4528. + match_all_urls_(false),
  4529. + match_subdomains_(false),
  4530. + port_("*") {}
  4531. +
  4532. +URLPattern::URLPattern(int valid_schemes)
  4533. + : valid_schemes_(valid_schemes),
  4534. + match_all_urls_(false),
  4535. + match_subdomains_(false),
  4536. + port_("*") {}
  4537. +
  4538. +URLPattern::URLPattern(int valid_schemes, base::StringPiece pattern)
  4539. + // Strict error checking is used, because this constructor is only
  4540. + // appropriate when we know |pattern| is valid.
  4541. + : valid_schemes_(valid_schemes),
  4542. + match_all_urls_(false),
  4543. + match_subdomains_(false),
  4544. + port_("*") {
  4545. + ParseResult result = Parse(pattern);
  4546. + if (result != ParseResult::kSuccess) {
  4547. + const char* error_string = GetParseResultString(result);
  4548. + // Temporarily add more logging to investigate why this code path is
  4549. + // reached. For http://crbug.com/856948
  4550. + LOG(ERROR) << "Invalid pattern was given " << pattern << " result "
  4551. + << error_string;
  4552. + NOTREACHED() << "URLPattern invalid: '" << pattern
  4553. + << "'; error: " << error_string;
  4554. + }
  4555. +}
  4556. +
  4557. +URLPattern::URLPattern(const URLPattern& other) = default;
  4558. +
  4559. +URLPattern::URLPattern(URLPattern&& other) = default;
  4560. +
  4561. +URLPattern::~URLPattern() {
  4562. +}
  4563. +
  4564. +URLPattern& URLPattern::operator=(const URLPattern& other) = default;
  4565. +
  4566. +URLPattern& URLPattern::operator=(URLPattern&& other) = default;
  4567. +
  4568. +bool URLPattern::operator<(const URLPattern& other) const {
  4569. + return GetAsString() < other.GetAsString();
  4570. +}
  4571. +
  4572. +bool URLPattern::operator>(const URLPattern& other) const {
  4573. + return GetAsString() > other.GetAsString();
  4574. +}
  4575. +
  4576. +bool URLPattern::operator==(const URLPattern& other) const {
  4577. + return GetAsString() == other.GetAsString();
  4578. +}
  4579. +
  4580. +std::ostream& operator<<(std::ostream& out, const URLPattern& url_pattern) {
  4581. + return out << '"' << url_pattern.GetAsString() << '"';
  4582. +}
  4583. +
  4584. +URLPattern::ParseResult URLPattern::Parse(base::StringPiece pattern) {
  4585. + spec_.clear();
  4586. + SetMatchAllURLs(false);
  4587. + SetMatchSubdomains(false);
  4588. + SetPort("*");
  4589. +
  4590. + // Special case pattern to match every valid URL.
  4591. + if (pattern == kAllUrlsPattern) {
  4592. + SetMatchAllURLs(true);
  4593. + return ParseResult::kSuccess;
  4594. + }
  4595. +
  4596. + // Parse out the scheme.
  4597. + size_t scheme_end_pos = pattern.find(url::kStandardSchemeSeparator);
  4598. + bool has_standard_scheme_separator = true;
  4599. +
  4600. + // Some urls also use ':' alone as the scheme separator.
  4601. + if (scheme_end_pos == base::StringPiece::npos) {
  4602. + scheme_end_pos = pattern.find(':');
  4603. + has_standard_scheme_separator = false;
  4604. + }
  4605. +
  4606. + if (scheme_end_pos == base::StringPiece::npos)
  4607. + return ParseResult::kMissingSchemeSeparator;
  4608. +
  4609. + if (!SetScheme(pattern.substr(0, scheme_end_pos)))
  4610. + return ParseResult::kInvalidScheme;
  4611. +
  4612. + bool standard_scheme = IsStandardScheme(scheme_);
  4613. + if (standard_scheme != has_standard_scheme_separator)
  4614. + return ParseResult::kWrongSchemeSeparator;
  4615. +
  4616. + // Advance past the scheme separator.
  4617. + scheme_end_pos +=
  4618. + (standard_scheme ? strlen(url::kStandardSchemeSeparator) : 1);
  4619. + if (scheme_end_pos >= pattern.size())
  4620. + return ParseResult::kEmptyHost;
  4621. +
  4622. + // Parse out the host and path.
  4623. + size_t host_start_pos = scheme_end_pos;
  4624. + size_t path_start_pos = 0;
  4625. +
  4626. + if (!standard_scheme) {
  4627. + path_start_pos = host_start_pos;
  4628. + } else if (scheme_ == url::kFileScheme) {
  4629. + size_t host_end_pos = pattern.find(kPathSeparator, host_start_pos);
  4630. + if (host_end_pos == base::StringPiece::npos) {
  4631. + // Allow hostname omission.
  4632. + // e.g. file://* is interpreted as file:///*,
  4633. + // file://foo* is interpreted as file:///foo*.
  4634. + path_start_pos = host_start_pos - 1;
  4635. + } else {
  4636. + // Ignore hostname if scheme is file://.
  4637. + // e.g. file://localhost/foo is equal to file:///foo.
  4638. + path_start_pos = host_end_pos;
  4639. + }
  4640. + } else {
  4641. + size_t host_end_pos = pattern.find(kPathSeparator, host_start_pos);
  4642. +
  4643. + // Host is required.
  4644. + if (host_start_pos == host_end_pos)
  4645. + return ParseResult::kEmptyHost;
  4646. +
  4647. + if (host_end_pos == base::StringPiece::npos)
  4648. + return ParseResult::kEmptyPath;
  4649. +
  4650. + base::StringPiece host_and_port =
  4651. + pattern.substr(host_start_pos, host_end_pos - host_start_pos);
  4652. +
  4653. + size_t port_separator_pos = base::StringPiece::npos;
  4654. + if (host_and_port[0] != '[') {
  4655. + // Not IPv6 (either IPv4 or just a normal address).
  4656. + port_separator_pos = host_and_port.find(':');
  4657. + } else { // IPv6.
  4658. + size_t host_end_pos = host_and_port.find(']');
  4659. + if (host_end_pos == base::StringPiece::npos)
  4660. + return ParseResult::kInvalidHost;
  4661. + if (host_end_pos == 1)
  4662. + return ParseResult::kEmptyHost;
  4663. +
  4664. + if (host_end_pos < host_and_port.length() - 1) {
  4665. + // The host isn't the only component. Check for a port. This would
  4666. + // require a ':' to follow the closing ']' from the host.
  4667. + if (host_and_port[host_end_pos + 1] != ':')
  4668. + return ParseResult::kInvalidHost;
  4669. +
  4670. + port_separator_pos = host_end_pos + 1;
  4671. + }
  4672. + }
  4673. +
  4674. + if (port_separator_pos != base::StringPiece::npos &&
  4675. + !SetPort(host_and_port.substr(port_separator_pos + 1))) {
  4676. + return ParseResult::kInvalidPort;
  4677. + }
  4678. +
  4679. + // Note: this substr() will be the entire string if the port position
  4680. + // wasn't found.
  4681. + base::StringPiece host_piece = host_and_port.substr(0, port_separator_pos);
  4682. +
  4683. + if (host_piece.empty())
  4684. + return ParseResult::kEmptyHost;
  4685. +
  4686. + if (host_piece == "*") {
  4687. + match_subdomains_ = true;
  4688. + host_piece = base::StringPiece();
  4689. + } else if (base::StartsWith(host_piece, "*.")) {
  4690. + if (host_piece.length() == 2) {
  4691. + // We don't allow just '*.' as a host.
  4692. + return ParseResult::kEmptyHost;
  4693. + }
  4694. + match_subdomains_ = true;
  4695. + host_piece = host_piece.substr(2);
  4696. + }
  4697. +
  4698. + host_ = host_piece.as_string();
  4699. +
  4700. + path_start_pos = host_end_pos;
  4701. + }
  4702. +
  4703. + SetPath(pattern.substr(path_start_pos));
  4704. +
  4705. + // No other '*' can occur in the host, though. This isn't necessary, but is
  4706. + // done as a convenience to developers who might otherwise be confused and
  4707. + // think '*' works as a glob in the host.
  4708. + if (host_.find('*') != std::string::npos)
  4709. + return ParseResult::kInvalidHostWildcard;
  4710. +
  4711. + if (!host_.empty()) {
  4712. + // If |host_| is present (i.e., isn't a wildcard), we need to canonicalize
  4713. + // it.
  4714. + url::CanonHostInfo host_info;
  4715. + host_ = net::CanonicalizeHost(host_, &host_info);
  4716. + // net::CanonicalizeHost() returns an empty string on failure.
  4717. + if (host_.empty())
  4718. + return ParseResult::kInvalidHost;
  4719. + }
  4720. +
  4721. + // Null characters are not allowed in hosts.
  4722. + if (host_.find('\0') != std::string::npos)
  4723. + return ParseResult::kInvalidHost;
  4724. +
  4725. + return ParseResult::kSuccess;
  4726. +}
  4727. +
  4728. +void URLPattern::SetValidSchemes(int valid_schemes) {
  4729. + // TODO(devlin): Should we check that valid_schemes agrees with |scheme_|
  4730. + // here? Otherwise, valid_schemes_ and schemes_ may stop agreeing with each
  4731. + // other (e.g., in the case of `*://*/*`, where the scheme should only be
  4732. + // http or https).
  4733. + spec_.clear();
  4734. + valid_schemes_ = valid_schemes;
  4735. +}
  4736. +
  4737. +void URLPattern::SetHost(base::StringPiece host) {
  4738. + spec_.clear();
  4739. + host_.assign(host.data(), host.size());
  4740. +}
  4741. +
  4742. +void URLPattern::SetMatchAllURLs(bool val) {
  4743. + spec_.clear();
  4744. + match_all_urls_ = val;
  4745. +
  4746. + if (val) {
  4747. + match_subdomains_ = true;
  4748. + scheme_ = "*";
  4749. + host_.clear();
  4750. + SetPath("/*");
  4751. + }
  4752. +}
  4753. +
  4754. +void URLPattern::SetMatchSubdomains(bool val) {
  4755. + spec_.clear();
  4756. + match_subdomains_ = val;
  4757. +}
  4758. +
  4759. +bool URLPattern::SetScheme(base::StringPiece scheme) {
  4760. + spec_.clear();
  4761. + scheme_.assign(scheme.data(), scheme.size());
  4762. + if (scheme_ == "*") {
  4763. + valid_schemes_ &= (SCHEME_HTTP | SCHEME_HTTPS);
  4764. + } else if (!IsValidScheme(scheme_)) {
  4765. + return false;
  4766. + }
  4767. + return true;
  4768. +}
  4769. +
  4770. +bool URLPattern::IsValidScheme(base::StringPiece scheme) const {
  4771. + if (valid_schemes_ == SCHEME_ALL)
  4772. + return true;
  4773. +
  4774. + for (size_t i = 0; i < base::size(kValidSchemes); ++i) {
  4775. + if (scheme == kValidSchemes[i] && (valid_schemes_ & kValidSchemeMasks[i]))
  4776. + return true;
  4777. + }
  4778. +
  4779. + return false;
  4780. +}
  4781. +
  4782. +void URLPattern::SetPath(base::StringPiece path) {
  4783. + spec_.clear();
  4784. + path_.assign(path.data(), path.size());
  4785. + path_escaped_ = path_;
  4786. + base::ReplaceSubstringsAfterOffset(&path_escaped_, 0, "\\", "\\\\");
  4787. + base::ReplaceSubstringsAfterOffset(&path_escaped_, 0, "?", "\\?");
  4788. +}
  4789. +
  4790. +bool URLPattern::SetPort(base::StringPiece port) {
  4791. + spec_.clear();
  4792. + if (IsValidPortForScheme(scheme_, port)) {
  4793. + port_.assign(port.data(), port.size());
  4794. + return true;
  4795. + }
  4796. + return false;
  4797. +}
  4798. +
  4799. +bool URLPattern::MatchesURL(const GURL& test) const {
  4800. + // Invalid URLs can never match.
  4801. + if (!test.is_valid())
  4802. + return false;
  4803. +
  4804. + const GURL* test_url = &test;
  4805. + bool has_inner_url = test.inner_url() != nullptr;
  4806. +
  4807. + if (has_inner_url) {
  4808. + if (!test.SchemeIsFileSystem())
  4809. + return false; // The only nested URLs we handle are filesystem URLs.
  4810. + test_url = test.inner_url();
  4811. + }
  4812. +
  4813. + // Ensure the scheme matches first, since <all_urls> may not match this URL if
  4814. + // the scheme is excluded.
  4815. + if (!MatchesScheme(test_url->scheme_piece()))
  4816. + return false;
  4817. +
  4818. + if (match_all_urls_)
  4819. + return true;
  4820. +
  4821. + // Unless |match_all_urls_| is true, the grammar only permits matching
  4822. + // URLs with nonempty paths.
  4823. + if (!test.has_path())
  4824. + return false;
  4825. +
  4826. + std::string path_for_request = test.PathForRequest();
  4827. + if (has_inner_url) {
  4828. + path_for_request = base::StringPrintf("%s%s", test_url->path_piece().data(),
  4829. + path_for_request.c_str());
  4830. + }
  4831. +
  4832. + return MatchesSecurityOriginHelper(*test_url) &&
  4833. + MatchesPath(path_for_request);
  4834. +}
  4835. +
  4836. +bool URLPattern::MatchesSecurityOrigin(const GURL& test) const {
  4837. + const GURL* test_url = &test;
  4838. + bool has_inner_url = test.inner_url() != NULL;
  4839. +
  4840. + if (has_inner_url) {
  4841. + if (!test.SchemeIsFileSystem())
  4842. + return false; // The only nested URLs we handle are filesystem URLs.
  4843. + test_url = test.inner_url();
  4844. + }
  4845. +
  4846. + if (!MatchesScheme(test_url->scheme()))
  4847. + return false;
  4848. +
  4849. + if (match_all_urls_)
  4850. + return true;
  4851. +
  4852. + return MatchesSecurityOriginHelper(*test_url);
  4853. +}
  4854. +
  4855. +bool URLPattern::MatchesScheme(base::StringPiece test) const {
  4856. + if (!IsValidScheme(test))
  4857. + return false;
  4858. +
  4859. + return scheme_ == "*" || test == scheme_;
  4860. +}
  4861. +
  4862. +bool URLPattern::MatchesHost(base::StringPiece host) const {
  4863. + // TODO(devlin): This is a bit sad. Parsing urls is expensive. However, it's
  4864. + // important that we do this conversion to a GURL in order to canonicalize the
  4865. + // host (the pattern's host_ already is canonicalized from Parse()). We can't
  4866. + // just do string comparison.
  4867. + return MatchesHost(
  4868. + GURL(base::StringPrintf("%s%s%s/", url::kHttpScheme,
  4869. + url::kStandardSchemeSeparator, host.data())));
  4870. +}
  4871. +
  4872. +bool URLPattern::MatchesHost(const GURL& test) const {
  4873. + base::StringPiece test_host(CanonicalizeHostForMatching(test.host_piece()));
  4874. + const base::StringPiece pattern_host(CanonicalizeHostForMatching(host_));
  4875. +
  4876. + // If the hosts are exactly equal, we have a match.
  4877. + if (test_host == pattern_host)
  4878. + return true;
  4879. +
  4880. + // If we're matching subdomains, and we have no host in the match pattern,
  4881. + // that means that we're matching all hosts, which means we have a match no
  4882. + // matter what the test host is.
  4883. + if (match_subdomains_ && pattern_host.empty())
  4884. + return true;
  4885. +
  4886. + // Otherwise, we can only match if our match pattern matches subdomains.
  4887. + if (!match_subdomains_)
  4888. + return false;
  4889. +
  4890. + // We don't do subdomain matching against IP addresses, so we can give up now
  4891. + // if the test host is an IP address.
  4892. + if (test.HostIsIPAddress())
  4893. + return false;
  4894. +
  4895. + // Check if the test host is a subdomain of our host.
  4896. + if (test_host.length() <= (pattern_host.length() + 1))
  4897. + return false;
  4898. +
  4899. + if (!base::EndsWith(test_host, pattern_host))
  4900. + return false;
  4901. +
  4902. + return test_host[test_host.length() - pattern_host.length() - 1] == '.';
  4903. +}
  4904. +
  4905. +bool URLPattern::MatchesEffectiveTld(
  4906. + net::registry_controlled_domains::PrivateRegistryFilter private_filter,
  4907. + net::registry_controlled_domains::UnknownRegistryFilter unknown_filter)
  4908. + const {
  4909. + // Check if it matches all urls or is a pattern like http://*/*.
  4910. + if (match_all_urls_ || (match_subdomains_ && host_.empty()))
  4911. + return true;
  4912. +
  4913. + // If this doesn't even match subdomains, it can't possibly be a TLD wildcard.
  4914. + if (!match_subdomains_)
  4915. + return false;
  4916. +
  4917. + // If there was more than just a TLD in the host (e.g., *.foobar.com), it
  4918. + // doesn't match all hosts in an effective TLD.
  4919. + if (net::registry_controlled_domains::HostHasRegistryControlledDomain(
  4920. + host_, unknown_filter, private_filter)) {
  4921. + return false;
  4922. + }
  4923. +
  4924. + // At this point the host could either be just a TLD ("com") or some unknown
  4925. + // TLD-like string ("notatld"). To disambiguate between them construct a
  4926. + // fake URL, and check the registry.
  4927. + //
  4928. + // If we recognized this TLD, then this is a pattern like *.com, and it
  4929. + // matches an effective TLD.
  4930. + return net::registry_controlled_domains::HostHasRegistryControlledDomain(
  4931. + "notatld." + host_, unknown_filter, private_filter);
  4932. +}
  4933. +
  4934. +bool URLPattern::MatchesSingleOrigin() const {
  4935. + // Strictly speaking, the port is part of the origin, but in URLPattern it
  4936. + // defaults to *. It's not very interesting anyway, so leave it out.
  4937. + return !MatchesEffectiveTld() && scheme_ != "*" && !match_subdomains_;
  4938. +}
  4939. +
  4940. +bool URLPattern::MatchesPath(base::StringPiece test) const {
  4941. + // Make the behaviour of OverlapsWith consistent with MatchesURL, which is
  4942. + // need to match hosted apps on e.g. 'google.com' also run on 'google.com/'.
  4943. + // The below if is a no-copy way of doing (test + "/*" == path_escaped_).
  4944. + if (path_escaped_.length() == test.length() + 2 &&
  4945. + base::StartsWith(path_escaped_.c_str(), test) &&
  4946. + base::EndsWith(path_escaped_, "/*")) {
  4947. + return true;
  4948. + }
  4949. +
  4950. + return base::MatchPattern(test, path_escaped_);
  4951. +}
  4952. +
  4953. +const std::string& URLPattern::GetAsString() const {
  4954. + if (!spec_.empty())
  4955. + return spec_;
  4956. +
  4957. + if (match_all_urls_) {
  4958. + spec_ = kAllUrlsPattern;
  4959. + return spec_;
  4960. + }
  4961. +
  4962. + bool standard_scheme = IsStandardScheme(scheme_);
  4963. +
  4964. + std::string spec = scheme_ +
  4965. + (standard_scheme ? url::kStandardSchemeSeparator : ":");
  4966. +
  4967. + if (scheme_ != url::kFileScheme && standard_scheme) {
  4968. + if (match_subdomains_) {
  4969. + spec += "*";
  4970. + if (!host_.empty())
  4971. + spec += ".";
  4972. + }
  4973. +
  4974. + if (!host_.empty())
  4975. + spec += host_;
  4976. +
  4977. + if (port_ != "*") {
  4978. + spec += ":";
  4979. + spec += port_;
  4980. + }
  4981. + }
  4982. +
  4983. + if (!path_.empty())
  4984. + spec += path_;
  4985. +
  4986. + spec_ = std::move(spec);
  4987. + return spec_;
  4988. +}
  4989. +
  4990. +bool URLPattern::OverlapsWith(const URLPattern& other) const {
  4991. + if (match_all_urls() || other.match_all_urls())
  4992. + return true;
  4993. + return (MatchesAnyScheme(other.GetExplicitSchemes()) ||
  4994. + other.MatchesAnyScheme(GetExplicitSchemes()))
  4995. + && (MatchesHost(other.host()) || other.MatchesHost(host()))
  4996. + && (MatchesPortPattern(other.port()) || other.MatchesPortPattern(port()))
  4997. + && (MatchesPath(StripTrailingWildcard(other.path())) ||
  4998. + other.MatchesPath(StripTrailingWildcard(path())));
  4999. +}
  5000. +
  5001. +bool URLPattern::Contains(const URLPattern& other) const {
  5002. + // Important: it's not enough to just check match_all_urls(); we also need to
  5003. + // make sure that the schemes in this pattern are a superset of those in
  5004. + // |other|.
  5005. + if (match_all_urls() &&
  5006. + (valid_schemes_ & other.valid_schemes_) == other.valid_schemes_) {
  5007. + return true;
  5008. + }
  5009. +
  5010. + return MatchesAllSchemes(other.GetExplicitSchemes()) &&
  5011. + MatchesHost(other.host()) &&
  5012. + (!other.match_subdomains_ || match_subdomains_) &&
  5013. + MatchesPortPattern(other.port()) &&
  5014. + MatchesPath(StripTrailingWildcard(other.path()));
  5015. +}
  5016. +
  5017. +base::Optional<URLPattern> URLPattern::CreateIntersection(
  5018. + const URLPattern& other) const {
  5019. + // Easy case: Schemes don't overlap. Return nullopt.
  5020. + int intersection_schemes = URLPattern::SCHEME_NONE;
  5021. + if (valid_schemes_ == URLPattern::SCHEME_ALL)
  5022. + intersection_schemes = other.valid_schemes_;
  5023. + else if (other.valid_schemes_ == URLPattern::SCHEME_ALL)
  5024. + intersection_schemes = valid_schemes_;
  5025. + else
  5026. + intersection_schemes = valid_schemes_ & other.valid_schemes_;
  5027. +
  5028. + if (intersection_schemes == URLPattern::SCHEME_NONE)
  5029. + return base::nullopt;
  5030. +
  5031. + {
  5032. + // In a few cases, we can (mostly) return a copy of one of the patterns.
  5033. + // This can happen when either:
  5034. + // - The URLPattern's are identical (possibly excluding valid_schemes_)
  5035. + // - One of the patterns has match_all_urls() equal to true.
  5036. + // NOTE(devlin): Theoretically, we could use Contains() instead of
  5037. + // match_all_urls() here. However, Contains() strips the trailing wildcard
  5038. + // from the path, which could yield the incorrect result.
  5039. + const URLPattern* copy_source = nullptr;
  5040. + if (*this == other || other.match_all_urls())
  5041. + copy_source = this;
  5042. + else if (match_all_urls())
  5043. + copy_source = &other;
  5044. +
  5045. + if (copy_source) {
  5046. + // NOTE: equality checks don't take into account valid_schemes_, and
  5047. + // schemes can be different in the case of match_all_urls() as well, so
  5048. + // we can't always just return *copy_source.
  5049. + if (intersection_schemes == copy_source->valid_schemes_)
  5050. + return *copy_source;
  5051. + URLPattern result(intersection_schemes);
  5052. + ParseResult parse_result = result.Parse(copy_source->GetAsString());
  5053. + CHECK_EQ(ParseResult::kSuccess, parse_result);
  5054. + return result;
  5055. + }
  5056. + }
  5057. +
  5058. + // No more easy cases. Go through component by component to find the patterns
  5059. + // that intersect.
  5060. +
  5061. + // Note: Alias the function type (rather than using auto) because
  5062. + // MatchesHost() is overloaded.
  5063. + using match_function_type = bool (URLPattern::*)(base::StringPiece) const;
  5064. +
  5065. + auto get_intersection = [this, &other](base::StringPiece own_str,
  5066. + base::StringPiece other_str,
  5067. + match_function_type match_function,
  5068. + base::StringPiece* out) {
  5069. + if ((this->*match_function)(other_str)) {
  5070. + *out = other_str;
  5071. + return true;
  5072. + }
  5073. + if ((other.*match_function)(own_str)) {
  5074. + *out = own_str;
  5075. + return true;
  5076. + }
  5077. + return false;
  5078. + };
  5079. +
  5080. + base::StringPiece scheme;
  5081. + base::StringPiece host;
  5082. + base::StringPiece port;
  5083. + base::StringPiece path;
  5084. + // If any pieces fail to overlap, then there is no intersection.
  5085. + if (!get_intersection(scheme_, other.scheme_, &URLPattern::MatchesScheme,
  5086. + &scheme) ||
  5087. + !get_intersection(host_, other.host_, &URLPattern::MatchesHost, &host) ||
  5088. + !get_intersection(port_, other.port_, &URLPattern::MatchesPortPattern,
  5089. + &port) ||
  5090. + !get_intersection(path_, other.path_, &URLPattern::MatchesPath, &path)) {
  5091. + return base::nullopt;
  5092. + }
  5093. +
  5094. + // Only match subdomains if both patterns match subdomains.
  5095. + base::StringPiece subdomains;
  5096. + if (match_subdomains_ && other.match_subdomains_) {
  5097. + // The host may be empty (e.g., in the case of *://*/* - in that case, only
  5098. + // append '*' instead of '*.'.
  5099. + subdomains = host.empty() ? "*" : "*.";
  5100. + }
  5101. +
  5102. + base::StringPiece scheme_separator =
  5103. + IsStandardScheme(scheme) ? url::kStandardSchemeSeparator : ":";
  5104. +
  5105. + std::string pattern_str = base::StrCat(
  5106. + {scheme, scheme_separator, subdomains, host, ":", port, path});
  5107. +
  5108. + URLPattern pattern(intersection_schemes);
  5109. + ParseResult result = pattern.Parse(pattern_str);
  5110. + // TODO(devlin): I don't think there's any way this should ever fail, but
  5111. + // use a CHECK() to flush any cases out. If nothing crops up, downgrade this
  5112. + // to a DCHECK in M72.
  5113. + CHECK_EQ(ParseResult::kSuccess, result);
  5114. +
  5115. + return pattern;
  5116. +}
  5117. +
  5118. +bool URLPattern::MatchesAnyScheme(
  5119. + const std::vector<std::string>& schemes) const {
  5120. + for (auto i = schemes.cbegin(); i != schemes.cend(); ++i) {
  5121. + if (MatchesScheme(*i))
  5122. + return true;
  5123. + }
  5124. +
  5125. + return false;
  5126. +}
  5127. +
  5128. +bool URLPattern::MatchesAllSchemes(
  5129. + const std::vector<std::string>& schemes) const {
  5130. + for (auto i = schemes.cbegin(); i != schemes.cend(); ++i) {
  5131. + if (!MatchesScheme(*i))
  5132. + return false;
  5133. + }
  5134. +
  5135. + return true;
  5136. +}
  5137. +
  5138. +bool URLPattern::MatchesSecurityOriginHelper(const GURL& test) const {
  5139. + // Ignore hostname if scheme is file://.
  5140. + if (scheme_ != url::kFileScheme && !MatchesHost(test))
  5141. + return false;
  5142. +
  5143. + if (!MatchesPortPattern(base::NumberToString(test.EffectiveIntPort())))
  5144. + return false;
  5145. +
  5146. + return true;
  5147. +}
  5148. +
  5149. +bool URLPattern::MatchesPortPattern(base::StringPiece port) const {
  5150. + return port_ == "*" || port_ == port;
  5151. +}
  5152. +
  5153. +std::vector<std::string> URLPattern::GetExplicitSchemes() const {
  5154. + std::vector<std::string> result;
  5155. +
  5156. + if (scheme_ != "*" && !match_all_urls_ && IsValidScheme(scheme_)) {
  5157. + result.push_back(scheme_);
  5158. + return result;
  5159. + }
  5160. +
  5161. + for (size_t i = 0; i < base::size(kValidSchemes); ++i) {
  5162. + if (MatchesScheme(kValidSchemes[i])) {
  5163. + result.push_back(kValidSchemes[i]);
  5164. + }
  5165. + }
  5166. +
  5167. + return result;
  5168. +}
  5169. +
  5170. +std::vector<URLPattern> URLPattern::ConvertToExplicitSchemes() const {
  5171. + std::vector<std::string> explicit_schemes = GetExplicitSchemes();
  5172. + std::vector<URLPattern> result;
  5173. +
  5174. + for (std::vector<std::string>::const_iterator i = explicit_schemes.begin();
  5175. + i != explicit_schemes.end(); ++i) {
  5176. + URLPattern temp = *this;
  5177. + temp.SetScheme(*i);
  5178. + temp.SetMatchAllURLs(false);
  5179. + result.push_back(temp);
  5180. + }
  5181. +
  5182. + return result;
  5183. +}
  5184. +
  5185. +// static
  5186. +const char* URLPattern::GetParseResultString(
  5187. + URLPattern::ParseResult parse_result) {
  5188. + return kParseResultMessages[static_cast<int>(parse_result)];
  5189. +}
  5190. diff --git a/components/user_scripts/common/url_pattern.h b/components/user_scripts/common/url_pattern.h
  5191. new file mode 100755
  5192. --- /dev/null
  5193. +++ b/components/user_scripts/common/url_pattern.h
  5194. @@ -0,0 +1,301 @@
  5195. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  5196. +// Use of this source code is governed by a BSD-style license that can be
  5197. +// found in the LICENSE file.
  5198. +#ifndef USERSCRIPTS_COMMON_URL_PATTERN_H_
  5199. +#define USERSCRIPTS_COMMON_URL_PATTERN_H_
  5200. +
  5201. +#include <functional>
  5202. +#include <iosfwd>
  5203. +#include <string>
  5204. +#include <vector>
  5205. +
  5206. +#include "base/strings/string_piece.h"
  5207. +#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
  5208. +
  5209. +class GURL;
  5210. +
  5211. +// A pattern that can be used to match URLs. A URLPattern is a very restricted
  5212. +// subset of URL syntax:
  5213. +//
  5214. +// <url-pattern> := <scheme>://<host><port><path> | '<all_urls>'
  5215. +// <scheme> := '*' | 'http' | 'https' | 'file' | 'ftp' | 'chrome' |
  5216. +// 'chrome-extension' | 'filesystem'
  5217. +// <host> := '*' | <IPv4 address> | [<IPv6 address>] |
  5218. +// '*.' <anychar except '/' and '*'>+
  5219. +// <port> := [':' ('*' | <port number between 0 and 65535>)]
  5220. +// <path> := '/' <any chars>
  5221. +//
  5222. +// * Host is not used when the scheme is 'file'.
  5223. +// * The path can have embedded '*' characters which act as glob wildcards.
  5224. +// * '<all_urls>' is a special pattern that matches any valid URL that contains
  5225. +// a valid scheme (as specified by valid_schemes_).
  5226. +// * The '*' scheme pattern excludes file URLs.
  5227. +//
  5228. +// Examples of valid patterns:
  5229. +// - http://*/*
  5230. +// - http://*/foo*
  5231. +// - https://*.google.com/foo*bar
  5232. +// - file://monkey*
  5233. +// - http://127.0.0.1/*
  5234. +// - http://[2607:f8b0:4005:805::200e]/*
  5235. +//
  5236. +// Examples of invalid patterns:
  5237. +// - http://* -- path not specified
  5238. +// - http://*foo/bar -- * not allowed as substring of host component
  5239. +// - http://foo.*.bar/baz -- * must be first component
  5240. +// - http:/bar -- scheme separator not found
  5241. +// - foo://* -- invalid scheme
  5242. +// - chrome:// -- we don't support chrome internal URLs
  5243. +class URLPattern {
  5244. + public:
  5245. + // A collection of scheme bitmasks for use with valid_schemes.
  5246. + enum SchemeMasks {
  5247. + SCHEME_NONE = 0,
  5248. + SCHEME_HTTP = 1 << 0,
  5249. + SCHEME_HTTPS = 1 << 1,
  5250. + SCHEME_FILE = 1 << 2,
  5251. + SCHEME_FTP = 1 << 3,
  5252. + SCHEME_CHROMEUI = 1 << 4,
  5253. + SCHEME_EXTENSION = 1 << 5,
  5254. + SCHEME_FILESYSTEM = 1 << 6,
  5255. + SCHEME_WS = 1 << 7,
  5256. + SCHEME_WSS = 1 << 8,
  5257. + SCHEME_DATA = 1 << 9,
  5258. +
  5259. + // IMPORTANT!
  5260. + // SCHEME_ALL will match every scheme, including chrome://, chrome-
  5261. + // extension://, about:, etc. Because this has lots of security
  5262. + // implications, third-party extensions should usually not be able to get
  5263. + // access to URL patterns initialized this way. If there is a reason
  5264. + // for violating this general rule, document why this it safe.
  5265. + SCHEME_ALL = -1,
  5266. + };
  5267. +
  5268. + // Error codes returned from Parse().
  5269. + enum class ParseResult {
  5270. + kSuccess = 0,
  5271. + kMissingSchemeSeparator,
  5272. + kInvalidScheme,
  5273. + kWrongSchemeSeparator,
  5274. + kEmptyHost,
  5275. + kInvalidHostWildcard,
  5276. + kEmptyPath,
  5277. + kInvalidPort,
  5278. + kInvalidHost,
  5279. + kNumParseResults,
  5280. + };
  5281. +
  5282. + // The <all_urls> string pattern.
  5283. + static const char kAllUrlsPattern[];
  5284. +
  5285. + // Returns true if the given |scheme| is considered valid for extensions.
  5286. + static bool IsValidSchemeForExtensions(base::StringPiece scheme);
  5287. +
  5288. + // Returns the mask for all schemes considered valid for extensions.
  5289. + static int GetValidSchemeMaskForExtensions();
  5290. +
  5291. + explicit URLPattern(int valid_schemes);
  5292. +
  5293. + // Convenience to construct a URLPattern from a string. If the string is not
  5294. + // known ahead of time, use Parse() instead, which returns success or failure.
  5295. + URLPattern(int valid_schemes, base::StringPiece pattern);
  5296. +
  5297. + URLPattern();
  5298. + URLPattern(const URLPattern& other);
  5299. + URLPattern(URLPattern&& other);
  5300. + ~URLPattern();
  5301. +
  5302. + URLPattern& operator=(const URLPattern& other);
  5303. + URLPattern& operator=(URLPattern&& other);
  5304. +
  5305. + bool operator<(const URLPattern& other) const;
  5306. + bool operator>(const URLPattern& other) const;
  5307. + bool operator==(const URLPattern& other) const;
  5308. +
  5309. + // Initializes this instance by parsing the provided string. Returns
  5310. + // URLPattern::ParseResult::kSuccess on success, or an error code otherwise.
  5311. + // On failure, this instance will have some intermediate values and is in an
  5312. + // invalid state.
  5313. + ParseResult Parse(base::StringPiece pattern_str);
  5314. +
  5315. + // Gets the bitmask of valid schemes.
  5316. + int valid_schemes() const { return valid_schemes_; }
  5317. + void SetValidSchemes(int valid_schemes);
  5318. +
  5319. + // Gets the host the pattern matches. This can be an empty string if the
  5320. + // pattern matches all hosts (the input was <scheme>://*/<whatever>).
  5321. + const std::string& host() const { return host_; }
  5322. + void SetHost(base::StringPiece host);
  5323. +
  5324. + // Gets whether to match subdomains of host().
  5325. + bool match_subdomains() const { return match_subdomains_; }
  5326. + void SetMatchSubdomains(bool val);
  5327. +
  5328. + // Gets the path the pattern matches with the leading slash. This can have
  5329. + // embedded asterisks which are interpreted using glob rules.
  5330. + const std::string& path() const { return path_; }
  5331. + void SetPath(base::StringPiece path);
  5332. +
  5333. + // Returns true if this pattern matches all (valid) urls.
  5334. + bool match_all_urls() const { return match_all_urls_; }
  5335. + void SetMatchAllURLs(bool val);
  5336. +
  5337. + // Sets the scheme for pattern matches. This can be a single '*' if the
  5338. + // pattern matches all valid schemes (as defined by the valid_schemes_
  5339. + // property). Returns false on failure (if the scheme is not valid).
  5340. + bool SetScheme(base::StringPiece scheme);
  5341. + // Note: You should use MatchesScheme() instead of this getter unless you
  5342. + // absolutely need the exact scheme. This is exposed for testing.
  5343. + const std::string& scheme() const { return scheme_; }
  5344. +
  5345. + // Returns true if the specified scheme can be used in this URL pattern, and
  5346. + // false otherwise. Uses valid_schemes_ to determine validity.
  5347. + bool IsValidScheme(base::StringPiece scheme) const;
  5348. +
  5349. + // Returns true if this instance matches the specified URL. Always returns
  5350. + // false for invalid URLs.
  5351. + bool MatchesURL(const GURL& test) const;
  5352. +
  5353. + // Returns true if this instance matches the specified security origin.
  5354. + bool MatchesSecurityOrigin(const GURL& test) const;
  5355. +
  5356. + // Returns true if |test| matches our scheme.
  5357. + // Note that if test is "filesystem", this may fail whereas MatchesURL
  5358. + // may succeed. MatchesURL is smart enough to look at the inner_url instead
  5359. + // of the outer "filesystem:" part.
  5360. + bool MatchesScheme(base::StringPiece test) const;
  5361. +
  5362. + // Returns true if |test| matches our host.
  5363. + bool MatchesHost(base::StringPiece test) const;
  5364. + bool MatchesHost(const GURL& test) const;
  5365. +
  5366. + // Returns true if |test| matches our path.
  5367. + bool MatchesPath(base::StringPiece test) const;
  5368. +
  5369. + // Returns true if the pattern matches all patterns in an (e)TLD. This
  5370. + // includes patterns like *://*.com/*, *://*.co.uk/*, etc. A pattern that
  5371. + // matches all domains (e.g., *://*/*) will return true.
  5372. + // |private_filter| specifies whether private registries (like appspot.com)
  5373. + // should be considered; if included, patterns like *://*.appspot.com/* will
  5374. + // return true. By default, we exclude private registries (so *.appspot.com
  5375. + // returns false).
  5376. + // Note: This is an expensive method, and should be used sparingly!
  5377. + // You should probably use URLPatternSet::ShouldWarnAllHosts(), which is
  5378. + // cached.
  5379. + bool MatchesEffectiveTld(
  5380. + net::registry_controlled_domains::PrivateRegistryFilter private_filter =
  5381. + net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES,
  5382. + net::registry_controlled_domains::UnknownRegistryFilter unknown_filter =
  5383. + net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES) const;
  5384. +
  5385. + // Returns true if the pattern only matches a single origin. The pattern may
  5386. + // include a path.
  5387. + bool MatchesSingleOrigin() const;
  5388. +
  5389. + // Sets the port. Returns false if the port is invalid.
  5390. + bool SetPort(base::StringPiece port);
  5391. + const std::string& port() const { return port_; }
  5392. +
  5393. + // Returns a string representing this instance.
  5394. + const std::string& GetAsString() const;
  5395. +
  5396. + // Determines whether there is a URL that would match this instance and
  5397. + // another instance. This method is symmetrical: Calling
  5398. + // other.OverlapsWith(this) would result in the same answer.
  5399. + bool OverlapsWith(const URLPattern& other) const;
  5400. +
  5401. + // Returns true if this pattern matches all possible URLs that |other| can
  5402. + // match. For example, http://*.google.com encompasses http://www.google.com.
  5403. + bool Contains(const URLPattern& other) const;
  5404. +
  5405. + // Creates a new URLPattern that represents the intersection of this
  5406. + // URLPattern with the |other|, or base::nullopt if no intersection exists.
  5407. + // For instance, given the patterns http://*.google.com/* and
  5408. + // *://maps.google.com/*, the intersection is http://maps.google.com/*.
  5409. + // NOTES:
  5410. + // - Though scheme intersections are supported, the serialization of
  5411. + // URLPatternSet does not record them. Be sure that this is safe for your
  5412. + // use cases.
  5413. + // - Path intersection is done on a best-effort basis. If one path clearly
  5414. + // contains another, it will be handled correctly, but this method does not
  5415. + // deal with cases like /*a* and /*b* (where technically the intersection
  5416. + // is /*a*b*|/*b*a*); the intersection returned for that case will be empty.
  5417. + base::Optional<URLPattern> CreateIntersection(const URLPattern& other) const;
  5418. +
  5419. + // Converts this URLPattern into an equivalent set of URLPatterns that don't
  5420. + // use a wildcard in the scheme component. If this URLPattern doesn't use a
  5421. + // wildcard scheme, then the returned set will contain one element that is
  5422. + // equivalent to this instance.
  5423. + std::vector<URLPattern> ConvertToExplicitSchemes() const;
  5424. +
  5425. + static bool EffectiveHostCompare(const URLPattern& a, const URLPattern& b) {
  5426. + if (a.match_all_urls_ && b.match_all_urls_)
  5427. + return false;
  5428. + return a.host_.compare(b.host_) < 0;
  5429. + }
  5430. +
  5431. + // Used for origin comparisons in a std::set.
  5432. + class EffectiveHostCompareFunctor {
  5433. + public:
  5434. + bool operator()(const URLPattern& a, const URLPattern& b) const {
  5435. + return EffectiveHostCompare(a, b);
  5436. + }
  5437. + };
  5438. +
  5439. + // Get an error string for a ParseResult.
  5440. + static const char* GetParseResultString(URLPattern::ParseResult parse_result);
  5441. +
  5442. + private:
  5443. + // Returns true if any of the |schemes| items matches our scheme.
  5444. + bool MatchesAnyScheme(const std::vector<std::string>& schemes) const;
  5445. +
  5446. + // Returns true if all of the |schemes| items matches our scheme.
  5447. + bool MatchesAllSchemes(const std::vector<std::string>& schemes) const;
  5448. +
  5449. + bool MatchesSecurityOriginHelper(const GURL& test) const;
  5450. +
  5451. + // Returns true if our port matches the |port| pattern (it may be "*").
  5452. + bool MatchesPortPattern(base::StringPiece port) const;
  5453. +
  5454. + // If the URLPattern contains a wildcard scheme, returns a list of
  5455. + // equivalent literal schemes, otherwise returns the current scheme.
  5456. + std::vector<std::string> GetExplicitSchemes() const;
  5457. +
  5458. + // A bitmask containing the schemes which are considered valid for this
  5459. + // pattern. Parse() uses this to decide whether a pattern contains a valid
  5460. + // scheme.
  5461. + int valid_schemes_;
  5462. +
  5463. + // True if this is a special-case "<all_urls>" pattern.
  5464. + bool match_all_urls_;
  5465. +
  5466. + // The scheme for the pattern.
  5467. + std::string scheme_;
  5468. +
  5469. + // The host without any leading "*" components.
  5470. + std::string host_;
  5471. +
  5472. + // Whether we should match subdomains of the host. This is true if the first
  5473. + // component of the pattern's host was "*".
  5474. + bool match_subdomains_;
  5475. +
  5476. + // The port.
  5477. + std::string port_;
  5478. +
  5479. + // The path to match. This is everything after the host of the URL, or
  5480. + // everything after the scheme in the case of file:// URLs.
  5481. + std::string path_;
  5482. +
  5483. + // The path with "?" and "\" characters escaped for use with the
  5484. + // MatchPattern() function.
  5485. + std::string path_escaped_;
  5486. +
  5487. + // A string representing this URLPattern.
  5488. + mutable std::string spec_;
  5489. +};
  5490. +
  5491. +std::ostream& operator<<(std::ostream& out, const URLPattern& url_pattern);
  5492. +
  5493. +typedef std::vector<URLPattern> URLPatternList;
  5494. +
  5495. +#endif // USERSCRIPTS_COMMON_URL_PATTERN_H_
  5496. diff --git a/components/user_scripts/common/url_pattern_set.cc b/components/user_scripts/common/url_pattern_set.cc
  5497. new file mode 100755
  5498. --- /dev/null
  5499. +++ b/components/user_scripts/common/url_pattern_set.cc
  5500. @@ -0,0 +1,330 @@
  5501. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  5502. +// Use of this source code is governed by a BSD-style license that can be
  5503. +// found in the LICENSE file.
  5504. +
  5505. +#include "url_pattern_set.h"
  5506. +
  5507. +#include <iterator>
  5508. +#include <ostream>
  5509. +
  5510. +#include "base/logging.h"
  5511. +#include "base/stl_util.h"
  5512. +#include "base/values.h"
  5513. +#include "error_utils.h"
  5514. +#include "url_pattern.h"
  5515. +#include "url/gurl.h"
  5516. +#include "url/origin.h"
  5517. +#include "url/url_constants.h"
  5518. +#include "user_scripts_features.h"
  5519. +
  5520. +namespace user_scripts {
  5521. +
  5522. +namespace {
  5523. +
  5524. +const char kInvalidURLPatternError[] = "Invalid url pattern '*'";
  5525. +
  5526. +} // namespace
  5527. +
  5528. +// static
  5529. +URLPatternSet URLPatternSet::CreateDifference(const URLPatternSet& set1,
  5530. + const URLPatternSet& set2) {
  5531. + return URLPatternSet(base::STLSetDifference<std::set<URLPattern>>(
  5532. + set1.patterns_, set2.patterns_));
  5533. +}
  5534. +
  5535. +// static
  5536. +URLPatternSet URLPatternSet::CreateIntersection(
  5537. + const URLPatternSet& set1,
  5538. + const URLPatternSet& set2,
  5539. + IntersectionBehavior intersection_behavior) {
  5540. + // Note: leverage return value optimization; always return the same object.
  5541. + URLPatternSet result;
  5542. +
  5543. + if (intersection_behavior == IntersectionBehavior::kStringComparison) {
  5544. + // String comparison just relies on STL set behavior, which looks at the
  5545. + // string representation.
  5546. + result = URLPatternSet(base::STLSetIntersection<std::set<URLPattern>>(
  5547. + set1.patterns_, set2.patterns_));
  5548. + return result;
  5549. + }
  5550. +
  5551. + // Look for a semantic intersection.
  5552. +
  5553. + // Step 1: Iterate over each set. Find any patterns that are completely
  5554. + // contained by the other (thus being necessarily present in any intersection)
  5555. + // and add them, collecting the others in a set of unique items.
  5556. + // Note: Use a collection of pointers for the uniques to avoid excessive
  5557. + // copies. Since these are owned by the URLPatternSet passed in, which is
  5558. + // const, this should be safe.
  5559. + std::vector<const URLPattern*> unique_set1;
  5560. + for (const URLPattern& pattern : set1) {
  5561. + if (set2.ContainsPattern(pattern))
  5562. + result.patterns_.insert(pattern);
  5563. + else
  5564. + unique_set1.push_back(&pattern);
  5565. + }
  5566. + std::vector<const URLPattern*> unique_set2;
  5567. + for (const URLPattern& pattern : set2) {
  5568. + if (set1.ContainsPattern(pattern))
  5569. + result.patterns_.insert(pattern);
  5570. + else
  5571. + unique_set2.push_back(&pattern);
  5572. + }
  5573. +
  5574. + // If we're just looking for patterns contained by both, we're done.
  5575. + if (intersection_behavior == IntersectionBehavior::kPatternsContainedByBoth)
  5576. + return result;
  5577. +
  5578. + DCHECK_EQ(IntersectionBehavior::kDetailed, intersection_behavior);
  5579. +
  5580. + // Step 2: Iterate over all the unique patterns and find the intersections
  5581. + // they have with the other patterns.
  5582. + for (const auto* pattern : unique_set1) {
  5583. + for (const auto* pattern2 : unique_set2) {
  5584. + base::Optional<URLPattern> intersection =
  5585. + pattern->CreateIntersection(*pattern2);
  5586. + if (intersection)
  5587. + result.patterns_.insert(std::move(*intersection));
  5588. + }
  5589. + }
  5590. +
  5591. + return result;
  5592. +}
  5593. +
  5594. +// static
  5595. +URLPatternSet URLPatternSet::CreateUnion(const URLPatternSet& set1,
  5596. + const URLPatternSet& set2) {
  5597. + return URLPatternSet(
  5598. + base::STLSetUnion<std::set<URLPattern>>(set1.patterns_, set2.patterns_));
  5599. +}
  5600. +
  5601. +// static
  5602. +URLPatternSet URLPatternSet::CreateUnion(
  5603. + const std::vector<URLPatternSet>& sets) {
  5604. + URLPatternSet result;
  5605. + if (sets.empty())
  5606. + return result;
  5607. +
  5608. + // N-way union algorithm is basic O(nlog(n)) merge algorithm.
  5609. + //
  5610. + // Do the first merge step into a working set so that we don't mutate any of
  5611. + // the input.
  5612. + // TODO(devlin): Looks like this creates a bunch of copies; we can probably
  5613. + // clean that up.
  5614. + std::vector<URLPatternSet> working;
  5615. + for (size_t i = 0; i < sets.size(); i += 2) {
  5616. + if (i + 1 < sets.size())
  5617. + working.push_back(CreateUnion(sets[i], sets[i + 1]));
  5618. + else
  5619. + working.push_back(sets[i].Clone());
  5620. + }
  5621. +
  5622. + for (size_t skip = 1; skip < working.size(); skip *= 2) {
  5623. + for (size_t i = 0; i < (working.size() - skip); i += skip) {
  5624. + URLPatternSet u = CreateUnion(working[i], working[i + skip]);
  5625. + working[i].patterns_.swap(u.patterns_);
  5626. + }
  5627. + }
  5628. +
  5629. + result.patterns_.swap(working[0].patterns_);
  5630. + return result;
  5631. +}
  5632. +
  5633. +URLPatternSet::URLPatternSet() = default;
  5634. +
  5635. +URLPatternSet::URLPatternSet(URLPatternSet&& rhs) = default;
  5636. +
  5637. +URLPatternSet::URLPatternSet(const std::set<URLPattern>& patterns)
  5638. + : patterns_(patterns) {}
  5639. +
  5640. +URLPatternSet::~URLPatternSet() = default;
  5641. +
  5642. +URLPatternSet& URLPatternSet::operator=(URLPatternSet&& rhs) = default;
  5643. +
  5644. +bool URLPatternSet::operator==(const URLPatternSet& other) const {
  5645. + return patterns_ == other.patterns_;
  5646. +}
  5647. +
  5648. +std::ostream& operator<<(std::ostream& out,
  5649. + const URLPatternSet& url_pattern_set) {
  5650. + out << "{ ";
  5651. +
  5652. + auto iter = url_pattern_set.patterns().cbegin();
  5653. + if (!url_pattern_set.patterns().empty()) {
  5654. + out << *iter;
  5655. + ++iter;
  5656. + }
  5657. +
  5658. + for (;iter != url_pattern_set.patterns().end(); ++iter)
  5659. + out << ", " << *iter;
  5660. +
  5661. + if (!url_pattern_set.patterns().empty())
  5662. + out << " ";
  5663. +
  5664. + out << "}";
  5665. + return out;
  5666. +}
  5667. +
  5668. +URLPatternSet URLPatternSet::Clone() const {
  5669. + return URLPatternSet(patterns_);
  5670. +}
  5671. +
  5672. +bool URLPatternSet::is_empty() const {
  5673. + return patterns_.empty();
  5674. +}
  5675. +
  5676. +size_t URLPatternSet::size() const {
  5677. + return patterns_.size();
  5678. +}
  5679. +
  5680. +bool URLPatternSet::AddPattern(const URLPattern& pattern) {
  5681. + return patterns_.insert(pattern).second;
  5682. +}
  5683. +
  5684. +void URLPatternSet::AddPatterns(const URLPatternSet& set) {
  5685. + patterns_.insert(set.patterns().begin(),
  5686. + set.patterns().end());
  5687. +}
  5688. +
  5689. +void URLPatternSet::ClearPatterns() {
  5690. + patterns_.clear();
  5691. +}
  5692. +
  5693. +bool URLPatternSet::AddOrigin(int valid_schemes, const GURL& origin) {
  5694. + if (origin.is_empty())
  5695. + return false;
  5696. + const url::Origin real_origin = url::Origin::Create(origin);
  5697. + DCHECK(real_origin.IsSameOriginWith(url::Origin::Create(origin.GetOrigin())));
  5698. + URLPattern origin_pattern(valid_schemes);
  5699. + // Origin adding could fail if |origin| does not match |valid_schemes|.
  5700. + if (origin_pattern.Parse(origin.spec()) !=
  5701. + URLPattern::ParseResult::kSuccess) {
  5702. + return false;
  5703. + }
  5704. + origin_pattern.SetPath("/*");
  5705. + return AddPattern(origin_pattern);
  5706. +}
  5707. +
  5708. +bool URLPatternSet::Contains(const URLPatternSet& other) const {
  5709. + for (auto it = other.begin(); it != other.end(); ++it) {
  5710. + if (!ContainsPattern(*it))
  5711. + return false;
  5712. + }
  5713. +
  5714. + return true;
  5715. +}
  5716. +
  5717. +bool URLPatternSet::ContainsPattern(const URLPattern& pattern) const {
  5718. + for (auto it = begin(); it != end(); ++it) {
  5719. + if (it->Contains(pattern))
  5720. + return true;
  5721. + }
  5722. + return false;
  5723. +}
  5724. +
  5725. +bool URLPatternSet::MatchesURL(const GURL& url) const {
  5726. + for (auto pattern = patterns_.cbegin(); pattern != patterns_.cend();
  5727. + ++pattern) {
  5728. + if (pattern->MatchesURL(url)) {
  5729. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  5730. + LOG(INFO) << "UserScripts: URLPatternSet::MatchesURL true " << url.spec();
  5731. +
  5732. + return true;
  5733. + }
  5734. + }
  5735. +
  5736. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  5737. + LOG(INFO) << "UserScripts: URLPatternSet::MatchesURL false " << url.spec();
  5738. +
  5739. + return false;
  5740. +}
  5741. +
  5742. +bool URLPatternSet::MatchesAllURLs() const {
  5743. + for (auto host = begin(); host != end(); ++host) {
  5744. + if (host->match_all_urls() ||
  5745. + (host->match_subdomains() && host->host().empty()))
  5746. + return true;
  5747. + }
  5748. + return false;
  5749. +}
  5750. +
  5751. +bool URLPatternSet::MatchesSecurityOrigin(const GURL& origin) const {
  5752. + for (auto pattern = patterns_.begin(); pattern != patterns_.end();
  5753. + ++pattern) {
  5754. + if (pattern->MatchesSecurityOrigin(origin))
  5755. + return true;
  5756. + }
  5757. +
  5758. + return false;
  5759. +}
  5760. +
  5761. +bool URLPatternSet::OverlapsWith(const URLPatternSet& other) const {
  5762. + // Two extension extents overlap if there is any one URL that would match at
  5763. + // least one pattern in each of the extents.
  5764. + for (auto i = patterns_.cbegin(); i != patterns_.cend(); ++i) {
  5765. + for (auto j = other.patterns().cbegin(); j != other.patterns().cend();
  5766. + ++j) {
  5767. + if (i->OverlapsWith(*j))
  5768. + return true;
  5769. + }
  5770. + }
  5771. +
  5772. + return false;
  5773. +}
  5774. +
  5775. +std::unique_ptr<base::ListValue> URLPatternSet::ToValue() const {
  5776. + std::unique_ptr<base::ListValue> value(new base::ListValue);
  5777. + for (auto i = patterns_.cbegin(); i != patterns_.cend(); ++i)
  5778. + value->AppendIfNotPresent(std::make_unique<base::Value>(i->GetAsString()));
  5779. + return value;
  5780. +}
  5781. +
  5782. +bool URLPatternSet::Populate(const std::vector<std::string>& patterns,
  5783. + int valid_schemes,
  5784. + bool allow_file_access,
  5785. + std::string* error) {
  5786. + ClearPatterns();
  5787. + for (size_t i = 0; i < patterns.size(); ++i) {
  5788. + URLPattern pattern(valid_schemes);
  5789. + if (pattern.Parse(patterns[i]) != URLPattern::ParseResult::kSuccess) {
  5790. + if (error) {
  5791. + *error = ErrorUtils::FormatErrorMessage(kInvalidURLPatternError,
  5792. + patterns[i]);
  5793. + } else {
  5794. + LOG(ERROR) << "Invalid url pattern: " << patterns[i];
  5795. + }
  5796. + return false;
  5797. + }
  5798. + if (!allow_file_access && pattern.MatchesScheme(url::kFileScheme)) {
  5799. + pattern.SetValidSchemes(
  5800. + pattern.valid_schemes() & ~URLPattern::SCHEME_FILE);
  5801. + }
  5802. + AddPattern(pattern);
  5803. + }
  5804. + return true;
  5805. +}
  5806. +
  5807. +std::unique_ptr<std::vector<std::string>> URLPatternSet::ToStringVector()
  5808. + const {
  5809. + std::unique_ptr<std::vector<std::string>> value(new std::vector<std::string>);
  5810. + for (auto i = patterns_.cbegin(); i != patterns_.cend(); ++i) {
  5811. + value->push_back(i->GetAsString());
  5812. + }
  5813. + return value;
  5814. +}
  5815. +
  5816. +bool URLPatternSet::Populate(const base::ListValue& value,
  5817. + int valid_schemes,
  5818. + bool allow_file_access,
  5819. + std::string* error) {
  5820. + std::vector<std::string> patterns;
  5821. + for (size_t i = 0; i < value.GetSize(); ++i) {
  5822. + std::string item;
  5823. + if (!value.GetString(i, &item))
  5824. + return false;
  5825. + patterns.push_back(item);
  5826. + }
  5827. + return Populate(patterns, valid_schemes, allow_file_access, error);
  5828. +}
  5829. +
  5830. +} // namespace extensions
  5831. diff --git a/components/user_scripts/common/url_pattern_set.h b/components/user_scripts/common/url_pattern_set.h
  5832. new file mode 100755
  5833. --- /dev/null
  5834. +++ b/components/user_scripts/common/url_pattern_set.h
  5835. @@ -0,0 +1,161 @@
  5836. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  5837. +// Use of this source code is governed by a BSD-style license that can be
  5838. +// found in the LICENSE file.
  5839. +
  5840. +#ifndef USERSCRIPTS_COMMON_URL_PATTERN_SET_H_
  5841. +#define USERSCRIPTS_COMMON_URL_PATTERN_SET_H_
  5842. +
  5843. +#include <stddef.h>
  5844. +
  5845. +#include <iosfwd>
  5846. +#include <memory>
  5847. +#include <set>
  5848. +
  5849. +#include "base/macros.h"
  5850. +#include "url_pattern.h"
  5851. +
  5852. +class GURL;
  5853. +
  5854. +namespace base {
  5855. +class ListValue;
  5856. +class Value;
  5857. +}
  5858. +
  5859. +namespace user_scripts {
  5860. +
  5861. +// Represents the set of URLs an extension uses for web content.
  5862. +class URLPatternSet {
  5863. + public:
  5864. + typedef std::set<URLPattern>::const_iterator const_iterator;
  5865. + typedef std::set<URLPattern>::iterator iterator;
  5866. +
  5867. + // Returns |set1| - |set2|.
  5868. + static URLPatternSet CreateDifference(const URLPatternSet& set1,
  5869. + const URLPatternSet& set2);
  5870. +
  5871. + enum class IntersectionBehavior {
  5872. + // For the following descriptions, consider the two URLPatternSets:
  5873. + // Set 1: {"https://example.com/*", "https://*.google.com/*", "http://*/*"}
  5874. + // Set 2: {"https://example.com/*", "https://google.com/maps",
  5875. + // "*://chromium.org/*"}
  5876. +
  5877. + // Only includes patterns that are exactly in both sets. The intersection of
  5878. + // the two sets above is {"https://example.com/*"}, since that is the only
  5879. + // pattern that appears exactly in each.
  5880. + kStringComparison,
  5881. +
  5882. + // Includes patterns that are effectively contained by both sets. The
  5883. + // intersection of the two sets above is
  5884. + // {
  5885. + // "https://example.com/*" (contained exactly by each set)
  5886. + // "https://google.com/maps" (contained exactly by set 2 and a strict
  5887. + // subset of https://*.google.com/* in set 1)
  5888. + // }
  5889. + kPatternsContainedByBoth,
  5890. +
  5891. + // Includes patterns that are contained by both sets and creates new
  5892. + // patterns to represent the intersection of any others. The intersection of
  5893. + // the two sets above is
  5894. + // {
  5895. + // "https://example.com/*" (contained exactly by each set)
  5896. + // "https://google.com/maps" (contained exactly by set 2 and a strict
  5897. + // subset of https://*.google.com/* in set 1)
  5898. + // "http://chromium.org/*" (the overlap between "http://*/*" in set 1 and
  5899. + // *://chromium.org/*" in set 2).
  5900. + // }
  5901. + // Note that this is the most computationally expensive - potentially
  5902. + // O(n^2) - since it can require comparing each pattern in one set to every
  5903. + // pattern in the other set.
  5904. + kDetailed,
  5905. + };
  5906. +
  5907. + // Returns the intersection of |set1| and |set2| according to
  5908. + // |intersection_behavior|.
  5909. + static URLPatternSet CreateIntersection(
  5910. + const URLPatternSet& set1,
  5911. + const URLPatternSet& set2,
  5912. + IntersectionBehavior intersection_behavior);
  5913. +
  5914. + // Returns the union of |set1| and |set2|.
  5915. + static URLPatternSet CreateUnion(const URLPatternSet& set1,
  5916. + const URLPatternSet& set2);
  5917. +
  5918. + // Returns the union of all sets in |sets|.
  5919. + static URLPatternSet CreateUnion(const std::vector<URLPatternSet>& sets);
  5920. +
  5921. + URLPatternSet();
  5922. + URLPatternSet(URLPatternSet&& rhs);
  5923. + explicit URLPatternSet(const std::set<URLPattern>& patterns);
  5924. + ~URLPatternSet();
  5925. +
  5926. + URLPatternSet& operator=(URLPatternSet&& rhs);
  5927. + bool operator==(const URLPatternSet& rhs) const;
  5928. +
  5929. + bool is_empty() const;
  5930. + size_t size() const;
  5931. + const std::set<URLPattern>& patterns() const { return patterns_; }
  5932. + const_iterator begin() const { return patterns_.begin(); }
  5933. + const_iterator end() const { return patterns_.end(); }
  5934. + iterator erase(iterator iter) { return patterns_.erase(iter); }
  5935. +
  5936. + // Returns a copy of this URLPatternSet; not instrumented as a copy
  5937. + // constructor to avoid accidental/unnecessary copies.
  5938. + URLPatternSet Clone() const;
  5939. +
  5940. + // Adds a pattern to the set. Returns true if a new pattern was inserted,
  5941. + // false if the pattern was already in the set.
  5942. + bool AddPattern(const URLPattern& pattern);
  5943. +
  5944. + // Adds all patterns from |set| into this.
  5945. + void AddPatterns(const URLPatternSet& set);
  5946. +
  5947. + void ClearPatterns();
  5948. +
  5949. + // Adds a pattern based on |origin| to the set.
  5950. + bool AddOrigin(int valid_schemes, const GURL& origin);
  5951. +
  5952. + // Returns true if every URL that matches |set| is matched by this. In other
  5953. + // words, if every pattern in |set| is encompassed by a pattern in this.
  5954. + bool Contains(const URLPatternSet& set) const;
  5955. +
  5956. + // Returns true if any pattern in this set encompasses |pattern|.
  5957. + bool ContainsPattern(const URLPattern& pattern) const;
  5958. +
  5959. + // Test if the extent contains a URL.
  5960. + bool MatchesURL(const GURL& url) const;
  5961. +
  5962. + // Test if the extent matches all URLs (for example, <all_urls>).
  5963. + bool MatchesAllURLs() const;
  5964. +
  5965. + bool MatchesSecurityOrigin(const GURL& origin) const;
  5966. +
  5967. + // Returns true if there is a single URL that would be in two extents.
  5968. + bool OverlapsWith(const URLPatternSet& other) const;
  5969. +
  5970. + // Converts to and from Value for serialization to preferences.
  5971. + std::unique_ptr<base::ListValue> ToValue() const;
  5972. + bool Populate(const base::ListValue& value,
  5973. + int valid_schemes,
  5974. + bool allow_file_access,
  5975. + std::string* error);
  5976. +
  5977. + // Converts to and from a vector of strings.
  5978. + std::unique_ptr<std::vector<std::string>> ToStringVector() const;
  5979. + bool Populate(const std::vector<std::string>& patterns,
  5980. + int valid_schemes,
  5981. + bool allow_file_access,
  5982. + std::string* error);
  5983. +
  5984. + private:
  5985. + // The list of URL patterns that comprise the extent.
  5986. + std::set<URLPattern> patterns_;
  5987. +
  5988. + DISALLOW_COPY_AND_ASSIGN(URLPatternSet);
  5989. +};
  5990. +
  5991. +std::ostream& operator<<(std::ostream& out,
  5992. + const URLPatternSet& url_pattern_set);
  5993. +
  5994. +} // namespace extensions
  5995. +
  5996. +#endif // USERSCRIPTS_COMMON_URL_PATTERN_SET_H_
  5997. diff --git a/components/user_scripts/common/user_script.cc b/components/user_scripts/common/user_script.cc
  5998. new file mode 100755
  5999. --- /dev/null
  6000. +++ b/components/user_scripts/common/user_script.cc
  6001. @@ -0,0 +1,317 @@
  6002. +// Copyright 2013 The Chromium Authors. All rights reserved.
  6003. +// Use of this source code is governed by a BSD-style license that can be
  6004. +// found in the LICENSE file.
  6005. +
  6006. +#include "user_script.h"
  6007. +
  6008. +#include <stddef.h>
  6009. +#include <stdint.h>
  6010. +
  6011. +#include <memory>
  6012. +#include <utility>
  6013. +
  6014. +#include "base/atomic_sequence_num.h"
  6015. +#include "base/command_line.h"
  6016. +#include "base/pickle.h"
  6017. +#include "base/strings/pattern.h"
  6018. +#include "base/strings/string_util.h"
  6019. +#include "user_scripts_features.h"
  6020. +
  6021. +namespace {
  6022. +
  6023. +// This cannot be a plain int or int64_t because we need to generate unique IDs
  6024. +// from multiple threads.
  6025. +base::AtomicSequenceNumber g_user_script_id_generator;
  6026. +
  6027. +bool UrlMatchesGlobs(const std::vector<std::string>* globs,
  6028. + const GURL& url) {
  6029. + for (auto glob = globs->cbegin(); glob != globs->cend(); ++glob) {
  6030. + if (base::MatchPattern(url.spec(), *glob))
  6031. + return true;
  6032. + }
  6033. +
  6034. + return false;
  6035. +}
  6036. +
  6037. +} // namespace
  6038. +
  6039. +namespace user_scripts {
  6040. +
  6041. +// The bitmask for valid user script injectable schemes used by URLPattern.
  6042. +enum {
  6043. + kValidUserScriptSchemes = //URLPattern::SCHEME_CHROMEUI |
  6044. + URLPattern::SCHEME_HTTP |
  6045. + URLPattern::SCHEME_HTTPS
  6046. + //| URLPattern::SCHEME_FILE |
  6047. + //URLPattern::SCHEME_FTP
  6048. +};
  6049. +
  6050. +// static
  6051. +const char UserScript::kFileExtension[] = ".user.js";
  6052. +
  6053. +// static
  6054. +int UserScript::GenerateUserScriptID() {
  6055. + return g_user_script_id_generator.GetNext();
  6056. +}
  6057. +
  6058. +bool UserScript::IsURLUserScript(const GURL& url,
  6059. + const std::string& mime_type) {
  6060. + return base::EndsWith(url.ExtractFileName(), kFileExtension,
  6061. + base::CompareCase::INSENSITIVE_ASCII) &&
  6062. + mime_type != "text/html";
  6063. +}
  6064. +
  6065. +// static
  6066. +int UserScript::ValidUserScriptSchemes(bool canExecuteScriptEverywhere) {
  6067. + if (canExecuteScriptEverywhere)
  6068. + return URLPattern::SCHEME_ALL;
  6069. + int valid_schemes = kValidUserScriptSchemes;
  6070. + // if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
  6071. + // switches::kExtensionsOnChromeURLs)) {
  6072. + // valid_schemes &= ~URLPattern::SCHEME_CHROMEUI;
  6073. + // }
  6074. + return valid_schemes;
  6075. +}
  6076. +
  6077. +UserScript::File::File(const base::FilePath& extension_root,
  6078. + const base::FilePath& relative_path,
  6079. + const GURL& url)
  6080. + : extension_root_(extension_root),
  6081. + relative_path_(relative_path),
  6082. + url_(url) {
  6083. +}
  6084. +
  6085. +UserScript::File::File() {}
  6086. +
  6087. +UserScript::File::File(const File& other)
  6088. + : extension_root_(other.extension_root_),
  6089. + relative_path_(other.relative_path_),
  6090. + url_(other.url_),
  6091. + external_content_(other.external_content_),
  6092. + content_(other.content_),
  6093. + key_(other.key_) {}
  6094. +
  6095. +UserScript::File::~File() {}
  6096. +
  6097. +UserScript::UserScript() = default;
  6098. +UserScript::~UserScript() = default;
  6099. +
  6100. +void UserScript::add_url_pattern(const URLPattern& pattern) {
  6101. + url_set_.AddPattern(pattern);
  6102. +}
  6103. +
  6104. +void UserScript::add_exclude_url_pattern(const URLPattern& pattern) {
  6105. + exclude_url_set_.AddPattern(pattern);
  6106. +}
  6107. +
  6108. +bool UserScript::MatchesURL(const GURL& url) const {
  6109. + if (!url_set_.is_empty()) {
  6110. + if (!url_set_.MatchesURL(url)) {
  6111. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  6112. + LOG(INFO) << "UserScripts: No Match for url_set";
  6113. + return false;
  6114. + }
  6115. + }
  6116. +
  6117. + if (!exclude_url_set_.is_empty()) {
  6118. + if (exclude_url_set_.MatchesURL(url)) {
  6119. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  6120. + LOG(INFO) << "UserScripts: No Match for exclude_url_set";
  6121. + return false;
  6122. + }
  6123. + }
  6124. +
  6125. + if (!globs_.empty()) {
  6126. + if (!UrlMatchesGlobs(&globs_, url)) {
  6127. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  6128. + LOG(INFO) << "UserScripts: No Match for globs";
  6129. + return false;
  6130. + }
  6131. + }
  6132. +
  6133. + if (!exclude_globs_.empty()) {
  6134. + if (UrlMatchesGlobs(&exclude_globs_, url)) {
  6135. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  6136. + LOG(INFO) << "UserScripts: No Match for exclude_globs";
  6137. + return false;
  6138. + }
  6139. + }
  6140. +
  6141. + return true;
  6142. +}
  6143. +
  6144. +bool UserScript::MatchesDocument(const GURL& effective_document_url,
  6145. + bool is_subframe) const {
  6146. + if (is_subframe && !match_all_frames())
  6147. + return false;
  6148. +
  6149. + return MatchesURL(effective_document_url);
  6150. +}
  6151. +
  6152. +void UserScript::File::Pickle(base::Pickle* pickle) const {
  6153. + pickle->WriteString(url_.spec());
  6154. + // Do not write path. It's not needed in the renderer.
  6155. + // Do not write content. It will be serialized by other means.
  6156. +}
  6157. +
  6158. +void UserScript::File::Unpickle(const base::Pickle& pickle,
  6159. + base::PickleIterator* iter) {
  6160. + // Read the url from the pickle.
  6161. + std::string url;
  6162. + CHECK(iter->ReadString(&url));
  6163. + set_url(GURL(url));
  6164. +}
  6165. +
  6166. +void UserScript::Pickle(base::Pickle* pickle) const {
  6167. + // Write the simple types to the pickle.
  6168. + pickle->WriteInt(run_location());
  6169. + pickle->WriteInt(user_script_id_);
  6170. + pickle->WriteBool(emulate_greasemonkey());
  6171. + pickle->WriteBool(match_all_frames());
  6172. + pickle->WriteInt(static_cast<int>(match_origin_as_fallback()));
  6173. + pickle->WriteBool(is_incognito_enabled());
  6174. +
  6175. + PickleHostID(pickle, host_id_);
  6176. + pickle->WriteInt(consumer_instance_type());
  6177. + PickleGlobs(pickle, globs_);
  6178. + PickleGlobs(pickle, exclude_globs_);
  6179. + PickleURLPatternSet(pickle, url_set_);
  6180. + PickleURLPatternSet(pickle, exclude_url_set_);
  6181. + PickleScripts(pickle, js_scripts_);
  6182. + PickleScripts(pickle, css_scripts_);
  6183. +}
  6184. +
  6185. +void UserScript::PickleGlobs(base::Pickle* pickle,
  6186. + const std::vector<std::string>& globs) const {
  6187. + pickle->WriteUInt32(globs.size());
  6188. + for (auto glob = globs.cbegin(); glob != globs.cend(); ++glob) {
  6189. + pickle->WriteString(*glob);
  6190. + }
  6191. +}
  6192. +
  6193. +void UserScript::PickleHostID(base::Pickle* pickle,
  6194. + const HostID& host_id) const {
  6195. + pickle->WriteInt(host_id.type());
  6196. + pickle->WriteString(host_id.id());
  6197. +}
  6198. +
  6199. +void UserScript::PickleURLPatternSet(base::Pickle* pickle,
  6200. + const URLPatternSet& pattern_list) const {
  6201. + pickle->WriteUInt32(pattern_list.patterns().size());
  6202. + for (auto pattern = pattern_list.begin(); pattern != pattern_list.end();
  6203. + ++pattern) {
  6204. + pickle->WriteInt(pattern->valid_schemes());
  6205. + pickle->WriteString(pattern->GetAsString());
  6206. + }
  6207. +}
  6208. +
  6209. +void UserScript::PickleScripts(base::Pickle* pickle,
  6210. + const FileList& scripts) const {
  6211. + pickle->WriteUInt32(scripts.size());
  6212. + for (const std::unique_ptr<File>& file : scripts)
  6213. + file->Pickle(pickle);
  6214. +}
  6215. +
  6216. +void UserScript::Unpickle(const base::Pickle& pickle,
  6217. + base::PickleIterator* iter) {
  6218. + // Read the run location.
  6219. + int run_location = 0;
  6220. + CHECK(iter->ReadInt(&run_location));
  6221. + CHECK(run_location >= 0 && run_location < RUN_LOCATION_LAST);
  6222. + run_location_ = static_cast<RunLocation>(run_location);
  6223. +
  6224. + CHECK(iter->ReadInt(&user_script_id_));
  6225. + CHECK(iter->ReadBool(&emulate_greasemonkey_));
  6226. + CHECK(iter->ReadBool(&match_all_frames_));
  6227. + int match_origin_as_fallback_int = 0;
  6228. + CHECK(iter->ReadInt(&match_origin_as_fallback_int));
  6229. + match_origin_as_fallback_ =
  6230. + static_cast<MatchOriginAsFallbackBehavior>(match_origin_as_fallback_int);
  6231. + CHECK(iter->ReadBool(&incognito_enabled_));
  6232. +
  6233. + UnpickleHostID(pickle, iter, &host_id_);
  6234. +
  6235. + int consumer_instance_type = 0;
  6236. + CHECK(iter->ReadInt(&consumer_instance_type));
  6237. + consumer_instance_type_ =
  6238. + static_cast<ConsumerInstanceType>(consumer_instance_type);
  6239. +
  6240. + UnpickleGlobs(pickle, iter, &globs_);
  6241. + UnpickleGlobs(pickle, iter, &exclude_globs_);
  6242. + UnpickleURLPatternSet(pickle, iter, &url_set_);
  6243. + UnpickleURLPatternSet(pickle, iter, &exclude_url_set_);
  6244. + UnpickleScripts(pickle, iter, &js_scripts_);
  6245. + UnpickleScripts(pickle, iter, &css_scripts_);
  6246. +}
  6247. +
  6248. +void UserScript::UnpickleGlobs(const base::Pickle& pickle,
  6249. + base::PickleIterator* iter,
  6250. + std::vector<std::string>* globs) {
  6251. + uint32_t num_globs = 0;
  6252. + CHECK(iter->ReadUInt32(&num_globs));
  6253. + globs->clear();
  6254. + for (uint32_t i = 0; i < num_globs; ++i) {
  6255. + std::string glob;
  6256. + CHECK(iter->ReadString(&glob));
  6257. + globs->push_back(glob);
  6258. + }
  6259. +}
  6260. +
  6261. +void UserScript::UnpickleHostID(const base::Pickle& pickle,
  6262. + base::PickleIterator* iter,
  6263. + HostID* host_id) {
  6264. + int type = 0;
  6265. + std::string id;
  6266. + CHECK(iter->ReadInt(&type));
  6267. + CHECK(iter->ReadString(&id));
  6268. + *host_id = HostID(static_cast<HostID::HostType>(type), id);
  6269. +}
  6270. +
  6271. +void UserScript::UnpickleURLPatternSet(const base::Pickle& pickle,
  6272. + base::PickleIterator* iter,
  6273. + URLPatternSet* pattern_list) {
  6274. + uint32_t num_patterns = 0;
  6275. + CHECK(iter->ReadUInt32(&num_patterns));
  6276. +
  6277. + pattern_list->ClearPatterns();
  6278. + for (uint32_t i = 0; i < num_patterns; ++i) {
  6279. + int valid_schemes;
  6280. + CHECK(iter->ReadInt(&valid_schemes));
  6281. +
  6282. + std::string pattern_str;
  6283. + CHECK(iter->ReadString(&pattern_str));
  6284. +
  6285. + URLPattern pattern(kValidUserScriptSchemes);
  6286. + URLPattern::ParseResult result = pattern.Parse(pattern_str);
  6287. + CHECK(URLPattern::ParseResult::kSuccess == result)
  6288. + << URLPattern::GetParseResultString(result) << " "
  6289. + << pattern_str.c_str();
  6290. +
  6291. + pattern.SetValidSchemes(valid_schemes);
  6292. + pattern_list->AddPattern(pattern);
  6293. + }
  6294. +}
  6295. +
  6296. +void UserScript::UnpickleScripts(const base::Pickle& pickle,
  6297. + base::PickleIterator* iter,
  6298. + FileList* scripts) {
  6299. + uint32_t num_files = 0;
  6300. + CHECK(iter->ReadUInt32(&num_files));
  6301. + scripts->clear();
  6302. + for (uint32_t i = 0; i < num_files; ++i) {
  6303. + std::unique_ptr<File> file(new File());
  6304. + file->Unpickle(pickle, iter);
  6305. + scripts->push_back(std::move(file));
  6306. + }
  6307. +}
  6308. +
  6309. +UserScriptIDPair::UserScriptIDPair(int id, const HostID& host_id)
  6310. + : id(id), host_id(host_id) {}
  6311. +
  6312. +UserScriptIDPair::UserScriptIDPair(int id) : id(id), host_id(HostID()) {}
  6313. +
  6314. +bool operator<(const UserScriptIDPair& a, const UserScriptIDPair& b) {
  6315. + return a.id < b.id;
  6316. +}
  6317. +
  6318. +} // namespace extensions
  6319. diff --git a/components/user_scripts/common/user_script.h b/components/user_scripts/common/user_script.h
  6320. new file mode 100755
  6321. --- /dev/null
  6322. +++ b/components/user_scripts/common/user_script.h
  6323. @@ -0,0 +1,387 @@
  6324. +// Copyright 2013 The Chromium Authors. All rights reserved.
  6325. +// Use of this source code is governed by a BSD-style license that can be
  6326. +// found in the LICENSE file.
  6327. +
  6328. +#ifndef USERSCRIPTS_COMMON_USER_SCRIPT_H_
  6329. +#define USERSCRIPTS_COMMON_USER_SCRIPT_H_
  6330. +
  6331. +#include <memory>
  6332. +#include <string>
  6333. +#include <vector>
  6334. +
  6335. +#include "base/files/file_path.h"
  6336. +#include "base/strings/string_piece.h"
  6337. +#include "script_constants.h"
  6338. +#include "host_id.h"
  6339. +#include "url_pattern.h"
  6340. +#include "url_pattern_set.h"
  6341. +#include "url/gurl.h"
  6342. +
  6343. +namespace base {
  6344. +class Pickle;
  6345. +class PickleIterator;
  6346. +}
  6347. +
  6348. +namespace user_scripts {
  6349. +
  6350. +// Represents a user script, either a standalone one, or one that is part of an
  6351. +// extension.
  6352. +class UserScript {
  6353. + public:
  6354. + // The file extension for standalone user scripts.
  6355. + static const char kFileExtension[];
  6356. +
  6357. + static int GenerateUserScriptID();
  6358. +
  6359. + // Check if a URL should be treated as a user script and converted to an
  6360. + // extension.
  6361. + static bool IsURLUserScript(const GURL& url, const std::string& mime_type);
  6362. +
  6363. + // Get the valid user script schemes for the current process. If
  6364. + // canExecuteScriptEverywhere is true, this will return ALL_SCHEMES.
  6365. + static int ValidUserScriptSchemes(bool canExecuteScriptEverywhere = false);
  6366. +
  6367. + // TODO(rdevlin.cronin) This and RunLocation don't really belong here, since
  6368. + // they are used for more than UserScripts (e.g., tabs.executeScript()).
  6369. + // The type of injected script.
  6370. + enum InjectionType {
  6371. + // A content script specified in the extension's manifest.
  6372. + CONTENT_SCRIPT,
  6373. + // A script injected via, e.g. tabs.executeScript().
  6374. + //PROGRAMMATIC_SCRIPT
  6375. + };
  6376. + // The last type of injected script; used for enum verification in IPC.
  6377. + // Update this if you add more injected script types!
  6378. + static const InjectionType INJECTION_TYPE_LAST = CONTENT_SCRIPT/*PROGRAMMATIC_SCRIPT*/;
  6379. +
  6380. + // Locations that user scripts can be run inside the document.
  6381. + // The three run locations must strictly follow each other in both load order
  6382. + // (i.e., start *always* comes before end) and numerically, as we use
  6383. + // arithmetic checking (e.g., curr == last + 1). So, no bitmasks here!!
  6384. + enum RunLocation {
  6385. + UNDEFINED,
  6386. + DOCUMENT_START, // After the documentElement is created, but before
  6387. + // anything else happens.
  6388. + DOCUMENT_END, // After the entire document is parsed. Same as
  6389. + // DOMContentLoaded.
  6390. + DOCUMENT_IDLE, // Sometime after DOMContentLoaded, as soon as the document
  6391. + // is "idle". Currently this uses the simple heuristic of:
  6392. + // min(DOM_CONTENT_LOADED + TIMEOUT, ONLOAD), but no
  6393. + // particular injection point is guaranteed.
  6394. + RUN_DEFERRED, // The user script's injection was deferred for permissions
  6395. + // reasons, and was executed at a later time.
  6396. + BROWSER_DRIVEN, // The user script will be injected when triggered by an
  6397. + // IPC in the browser process.
  6398. + RUN_LOCATION_LAST // Leave this as the last item.
  6399. + };
  6400. +
  6401. + // Holds script file info.
  6402. + class File {
  6403. + public:
  6404. + File(const base::FilePath& extension_root,
  6405. + const base::FilePath& relative_path,
  6406. + const GURL& url);
  6407. + File();
  6408. + File(const File& other);
  6409. + ~File();
  6410. +
  6411. + const base::FilePath& extension_root() const { return extension_root_; }
  6412. + const base::FilePath& relative_path() const { return relative_path_; }
  6413. +
  6414. + const GURL& url() const { return url_; }
  6415. + void set_url(const GURL& url) { url_ = url; }
  6416. +
  6417. + // If external_content_ is set returns it as content otherwise it returns
  6418. + // content_
  6419. + const base::StringPiece GetContent() const {
  6420. + if (external_content_.data())
  6421. + return external_content_;
  6422. + else
  6423. + return content_;
  6424. + }
  6425. + void set_external_content(const base::StringPiece& content) {
  6426. + external_content_ = content;
  6427. + }
  6428. + void set_content(const base::StringPiece& content) {
  6429. + content_.assign(content.begin(), content.end());
  6430. + }
  6431. +
  6432. + const std::string& key() const { return key_; }
  6433. + void set_key(const std::string& key) {
  6434. + key_ = key;
  6435. + }
  6436. +
  6437. + // Serialization support. The content and FilePath members will not be
  6438. + // serialized!
  6439. + void Pickle(base::Pickle* pickle) const;
  6440. + void Unpickle(const base::Pickle& pickle, base::PickleIterator* iter);
  6441. +
  6442. + private:
  6443. + // Where the script file lives on the disk. We keep the path split so that
  6444. + // it can be localized at will.
  6445. + base::FilePath extension_root_;
  6446. + base::FilePath relative_path_;
  6447. +
  6448. + // The url to this script file.
  6449. + GURL url_;
  6450. +
  6451. + // The script content. It can be set to either loaded_content_ or
  6452. + // externally allocated string.
  6453. + base::StringPiece external_content_;
  6454. +
  6455. + // Set when the content is loaded by LoadContent
  6456. + std::string content_;
  6457. +
  6458. + std::string key_;
  6459. + };
  6460. +
  6461. + using FileList = std::vector<std::unique_ptr<File>>;
  6462. +
  6463. + // Type of a API consumer instance that user scripts will be injected on.
  6464. + enum ConsumerInstanceType { TAB, WEBVIEW };
  6465. +
  6466. + // Constructor. Default the run location to document end, which is like
  6467. + // Greasemonkey and probably more useful for typical scripts.
  6468. + UserScript();
  6469. + ~UserScript();
  6470. +
  6471. + // Performs a copy of all fields except file contents.
  6472. + // static std::unique_ptr<UserScript> CopyMetadataFrom(const UserScript& other);
  6473. +
  6474. + const std::string& name_space() const { return name_space_; }
  6475. + void set_name_space(const std::string& name_space) {
  6476. + name_space_ = name_space;
  6477. + }
  6478. +
  6479. + const std::string& name() const { return name_; }
  6480. + void set_name(const std::string& name) { name_ = name; }
  6481. +
  6482. + const std::string& version() const { return version_; }
  6483. + void set_version(const std::string& version) {
  6484. + version_ = version;
  6485. + }
  6486. +
  6487. + const std::string& key() const { return key_; }
  6488. + void set_key(const std::string& key) {
  6489. + key_ = key;
  6490. + }
  6491. +
  6492. + const std::string& file_path() const { return file_path_; }
  6493. + void set_file_path(const std::string& file_path) {
  6494. + file_path_ = file_path;
  6495. + }
  6496. +
  6497. + const std::string& url_source() const { return url_source_; }
  6498. + void set_url_source(const std::string& url_source) {
  6499. + url_source_ = url_source;
  6500. + }
  6501. +
  6502. + const std::string& description() const { return description_; }
  6503. + void set_description(const std::string& description) {
  6504. + description_ = description;
  6505. + }
  6506. +
  6507. + // The place in the document to run the script.
  6508. + RunLocation run_location() const { return run_location_; }
  6509. + void set_run_location(RunLocation location) { run_location_ = location; }
  6510. +
  6511. + // Whether to emulate greasemonkey when running this script.
  6512. + bool emulate_greasemonkey() const { return emulate_greasemonkey_; }
  6513. + void set_emulate_greasemonkey(bool val) { emulate_greasemonkey_ = val; }
  6514. +
  6515. + // Whether to match all frames, or only the top one.
  6516. + bool match_all_frames() const { return match_all_frames_; }
  6517. + void set_match_all_frames(bool val) { match_all_frames_ = val; }
  6518. +
  6519. + // Whether to match the origin as a fallback if the URL cannot be used
  6520. + // directly.
  6521. + MatchOriginAsFallbackBehavior match_origin_as_fallback() const {
  6522. + return match_origin_as_fallback_;
  6523. + }
  6524. + void set_match_origin_as_fallback(MatchOriginAsFallbackBehavior val) {
  6525. + match_origin_as_fallback_ = val;
  6526. + }
  6527. +
  6528. + // The globs, if any, that determine which pages this script runs against.
  6529. + // These are only used with "standalone" Greasemonkey-like user scripts.
  6530. + const std::vector<std::string>& globs() const { return globs_; }
  6531. + void add_glob(const std::string& glob) { globs_.push_back(glob); }
  6532. + void clear_globs() { globs_.clear(); }
  6533. + const std::vector<std::string>& exclude_globs() const {
  6534. + return exclude_globs_;
  6535. + }
  6536. + void add_exclude_glob(const std::string& glob) {
  6537. + exclude_globs_.push_back(glob);
  6538. + }
  6539. + void clear_exclude_globs() { exclude_globs_.clear(); }
  6540. +
  6541. + // The URLPatterns, if any, that determine which pages this script runs
  6542. + // against.
  6543. + const URLPatternSet& url_patterns() const { return url_set_; }
  6544. + void add_url_pattern(const URLPattern& pattern);
  6545. + const URLPatternSet& exclude_url_patterns() const {
  6546. + return exclude_url_set_;
  6547. + }
  6548. + void add_exclude_url_pattern(const URLPattern& pattern);
  6549. +
  6550. + // List of js scripts for this user script
  6551. + FileList& js_scripts() { return js_scripts_; }
  6552. + const FileList& js_scripts() const { return js_scripts_; }
  6553. +
  6554. + // List of css scripts for this user script
  6555. + FileList& css_scripts() { return css_scripts_; }
  6556. + const FileList& css_scripts() const { return css_scripts_; }
  6557. +
  6558. + const std::string& extension_id() const { return host_id_.id(); }
  6559. +
  6560. + const HostID& host_id() const { return host_id_; }
  6561. + void set_host_id(const HostID& host_id) { host_id_ = host_id; }
  6562. +
  6563. + const ConsumerInstanceType& consumer_instance_type() const {
  6564. + return consumer_instance_type_;
  6565. + }
  6566. + void set_consumer_instance_type(
  6567. + const ConsumerInstanceType& consumer_instance_type) {
  6568. + consumer_instance_type_ = consumer_instance_type;
  6569. + }
  6570. +
  6571. + int id() const { return user_script_id_; }
  6572. + void set_id(int id) { user_script_id_ = id; }
  6573. +
  6574. + // TODO(lazyboy): Incognito information is extension specific, it doesn't
  6575. + // belong here. We should be able to determine this in the renderer/ where it
  6576. + // is used.
  6577. + bool is_incognito_enabled() const { return incognito_enabled_; }
  6578. + void set_incognito_enabled(bool enabled) { incognito_enabled_ = enabled; }
  6579. +
  6580. + // Returns true if the script should be applied to the specified URL, false
  6581. + // otherwise.
  6582. + bool MatchesURL(const GURL& url) const;
  6583. +
  6584. + // Returns true if the script should be applied to the given
  6585. + // |effective_document_url|. It is the caller's responsibility to calculate
  6586. + // |effective_document_url| based on match_origin_as_fallback().
  6587. + bool MatchesDocument(const GURL& effective_document_url,
  6588. + bool is_subframe) const;
  6589. +
  6590. + // Serializes the UserScript into a pickle. The content of the scripts and
  6591. + // paths to UserScript::Files will not be serialized!
  6592. + void Pickle(base::Pickle* pickle) const;
  6593. +
  6594. + // Deserializes the script from a pickle. Note that this always succeeds
  6595. + // because presumably we were the one that pickled it, and we did it
  6596. + // correctly.
  6597. + void Unpickle(const base::Pickle& pickle, base::PickleIterator* iter);
  6598. +
  6599. + private:
  6600. + // base::Pickle helper functions used to pickle the individual types of
  6601. + // components.
  6602. + void PickleGlobs(base::Pickle* pickle,
  6603. + const std::vector<std::string>& globs) const;
  6604. + void PickleHostID(base::Pickle* pickle, const HostID& host_id) const;
  6605. + void PickleURLPatternSet(base::Pickle* pickle,
  6606. + const URLPatternSet& pattern_list) const;
  6607. + void PickleScripts(base::Pickle* pickle, const FileList& scripts) const;
  6608. +
  6609. + // Unpickle helper functions used to unpickle individual types of components.
  6610. + void UnpickleGlobs(const base::Pickle& pickle,
  6611. + base::PickleIterator* iter,
  6612. + std::vector<std::string>* globs);
  6613. + void UnpickleHostID(const base::Pickle& pickle,
  6614. + base::PickleIterator* iter,
  6615. + HostID* host_id);
  6616. + void UnpickleURLPatternSet(const base::Pickle& pickle,
  6617. + base::PickleIterator* iter,
  6618. + URLPatternSet* pattern_list);
  6619. + void UnpickleScripts(const base::Pickle& pickle,
  6620. + base::PickleIterator* iter,
  6621. + FileList* scripts);
  6622. +
  6623. + // The location to run the script inside the document.
  6624. + RunLocation run_location_ = DOCUMENT_IDLE;
  6625. +
  6626. + // The namespace of the script. This is used by Greasemonkey in the same way
  6627. + // as XML namespaces. Only used when parsing Greasemonkey-style scripts.
  6628. + std::string name_space_;
  6629. +
  6630. + // The script's name. Only used when parsing Greasemonkey-style scripts.
  6631. + std::string name_;
  6632. +
  6633. + // A longer description. Only used when parsing Greasemonkey-style scripts.
  6634. + std::string description_;
  6635. +
  6636. + // A version number of the script. Only used when parsing Greasemonkey-style
  6637. + // scripts.
  6638. + std::string version_;
  6639. +
  6640. + // Greasemonkey-style globs that determine pages to inject the script into.
  6641. + // These are only used with standalone scripts.
  6642. + std::vector<std::string> globs_;
  6643. + std::vector<std::string> exclude_globs_;
  6644. +
  6645. + // URLPatterns that determine pages to inject the script into. These are
  6646. + // only used with scripts that are part of extensions.
  6647. + URLPatternSet url_set_;
  6648. + URLPatternSet exclude_url_set_;
  6649. +
  6650. + // List of js scripts defined in content_scripts
  6651. + FileList js_scripts_;
  6652. +
  6653. + // List of css scripts defined in content_scripts
  6654. + FileList css_scripts_;
  6655. +
  6656. + // internal key of scripts
  6657. + std::string key_;
  6658. +
  6659. + std::string file_path_;
  6660. +
  6661. + // url source of script
  6662. + std::string url_source_;
  6663. +
  6664. + // The ID of the host this script is a part of. The |ID| of the
  6665. + // |host_id| can be empty if the script is a "standlone" user script.
  6666. + HostID host_id_;
  6667. +
  6668. + // The type of the consumer instance that the script will be injected.
  6669. + ConsumerInstanceType consumer_instance_type_ = TAB;
  6670. +
  6671. + // The globally-unique id associated with this user script. -1 indicates
  6672. + // "invalid".
  6673. + int user_script_id_ = -1;
  6674. +
  6675. + // Whether we should try to emulate Greasemonkey's APIs when running this
  6676. + // script.
  6677. + bool emulate_greasemonkey_ = false;
  6678. +
  6679. + // Whether the user script should run in all frames, or only just the top one.
  6680. + bool match_all_frames_ = false;
  6681. +
  6682. + // Whether the user script should run in frames whose initiator / precursor
  6683. + // origin matches a match pattern, if an appropriate URL cannot be found for
  6684. + // the frame for matching purposes, such as in the case of about:, data:, and
  6685. + // other schemes.
  6686. + MatchOriginAsFallbackBehavior match_origin_as_fallback_ =
  6687. + MatchOriginAsFallbackBehavior::kNever;
  6688. +
  6689. + // True if the script should be injected into an incognito tab.
  6690. + bool incognito_enabled_ = false;
  6691. +
  6692. + DISALLOW_COPY_AND_ASSIGN(UserScript);
  6693. +};
  6694. +
  6695. +// Information we need while removing scripts from a UserScriptLoader.
  6696. +struct UserScriptIDPair {
  6697. + UserScriptIDPair(int id, const HostID& host_id);
  6698. + explicit UserScriptIDPair(int id);
  6699. +
  6700. + int id;
  6701. + HostID host_id;
  6702. +};
  6703. +
  6704. +bool operator<(const UserScriptIDPair& a, const UserScriptIDPair& b);
  6705. +
  6706. +using UserScriptList = std::vector<std::unique_ptr<UserScript>>;
  6707. +
  6708. +} // namespace extensions
  6709. +
  6710. +#endif // USERSCRIPTS_COMMON_USER_SCRIPT_H_
  6711. diff --git a/components/user_scripts/common/user_scripts_features.cc b/components/user_scripts/common/user_scripts_features.cc
  6712. new file mode 100644
  6713. --- /dev/null
  6714. +++ b/components/user_scripts/common/user_scripts_features.cc
  6715. @@ -0,0 +1,34 @@
  6716. +/*
  6717. + This file is part of Bromite.
  6718. +
  6719. + Bromite is free software: you can redistribute it and/or modify
  6720. + it under the terms of the GNU General Public License as published by
  6721. + the Free Software Foundation, either version 3 of the License, or
  6722. + (at your option) any later version.
  6723. +
  6724. + Bromite is distributed in the hope that it will be useful,
  6725. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  6726. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  6727. + GNU General Public License for more details.
  6728. +
  6729. + You should have received a copy of the GNU General Public License
  6730. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  6731. +*/
  6732. +
  6733. +#include "user_scripts_features.h"
  6734. +
  6735. +#include "build/build_config.h"
  6736. +
  6737. +namespace user_scripts {
  6738. +
  6739. +namespace features {
  6740. +
  6741. +const base::Feature kEnableUserScripts = {"EnableUserScripts",
  6742. + base::FEATURE_DISABLED_BY_DEFAULT};
  6743. +const base::Feature kEnableLoggingUserScripts =
  6744. + {"EnableLoggingUserScripts",
  6745. + base::FEATURE_DISABLED_BY_DEFAULT};
  6746. +
  6747. +}
  6748. +
  6749. +}
  6750. \ No newline at end of file
  6751. diff --git a/components/user_scripts/common/user_scripts_features.h b/components/user_scripts/common/user_scripts_features.h
  6752. new file mode 100644
  6753. --- /dev/null
  6754. +++ b/components/user_scripts/common/user_scripts_features.h
  6755. @@ -0,0 +1,35 @@
  6756. +/*
  6757. + This file is part of Bromite.
  6758. +
  6759. + Bromite is free software: you can redistribute it and/or modify
  6760. + it under the terms of the GNU General Public License as published by
  6761. + the Free Software Foundation, either version 3 of the License, or
  6762. + (at your option) any later version.
  6763. +
  6764. + Bromite is distributed in the hope that it will be useful,
  6765. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  6766. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  6767. + GNU General Public License for more details.
  6768. +
  6769. + You should have received a copy of the GNU General Public License
  6770. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  6771. +*/
  6772. +
  6773. +#ifndef USERSCRIPTS_COMMON_USERSCRIPTS_FEATURES_H_
  6774. +#define USERSCRIPTS_COMMON_USERSCRIPTS_FEATURES_H_
  6775. +
  6776. +// This file defines all the base::FeatureList features for the Password Manager
  6777. +// module.
  6778. +
  6779. +#include "base/feature_list.h"
  6780. +
  6781. +namespace user_scripts {
  6782. +
  6783. +namespace features {
  6784. + extern const base::Feature kEnableUserScripts;
  6785. + extern const base::Feature kEnableLoggingUserScripts;
  6786. +}
  6787. +
  6788. +}
  6789. +
  6790. +#endif
  6791. \ No newline at end of file
  6792. diff --git a/components/user_scripts/common/view_type.cc b/components/user_scripts/common/view_type.cc
  6793. new file mode 100755
  6794. --- /dev/null
  6795. +++ b/components/user_scripts/common/view_type.cc
  6796. @@ -0,0 +1,39 @@
  6797. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  6798. +// Use of this source code is governed by a BSD-style license that can be
  6799. +// found in the LICENSE file.
  6800. +
  6801. +#include "view_type.h"
  6802. +
  6803. +#include "base/strings/string_piece.h"
  6804. +
  6805. +namespace user_scripts {
  6806. +
  6807. +bool GetViewTypeFromString(const std::string& view_type,
  6808. + ViewType* view_type_out) {
  6809. + // TODO(devlin): This map doesn't contain the following values:
  6810. + // - VIEW_TYPE_BACKGROUND_CONTENTS
  6811. + // - VIEW_TYPE_COMPONENT
  6812. + // - VIEW_TYPE_EXTENSION_GUEST
  6813. + // Why? Is it just because we don't expose those types to JS?
  6814. + static const struct {
  6815. + ViewType type;
  6816. + base::StringPiece name;
  6817. + } constexpr kTypeMap[] = {
  6818. + // {VIEW_TYPE_APP_WINDOW, "APP_WINDOW"},
  6819. + // {VIEW_TYPE_EXTENSION_BACKGROUND_PAGE, "BACKGROUND"},
  6820. + // {VIEW_TYPE_EXTENSION_DIALOG, "EXTENSION_DIALOG"},
  6821. + // {VIEW_TYPE_EXTENSION_POPUP, "POPUP"},
  6822. + {VIEW_TYPE_TAB_CONTENTS, "TAB"},
  6823. + };
  6824. +
  6825. + for (const auto& entry : kTypeMap) {
  6826. + if (entry.name == view_type) {
  6827. + *view_type_out = entry.type;
  6828. + return true;
  6829. + }
  6830. + }
  6831. +
  6832. + return false;
  6833. +}
  6834. +
  6835. +} // namespace extensions
  6836. diff --git a/components/user_scripts/common/view_type.h b/components/user_scripts/common/view_type.h
  6837. new file mode 100755
  6838. --- /dev/null
  6839. +++ b/components/user_scripts/common/view_type.h
  6840. @@ -0,0 +1,48 @@
  6841. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  6842. +// Use of this source code is governed by a BSD-style license that can be
  6843. +// found in the LICENSE file.
  6844. +
  6845. +#ifndef USERSCRIPTS_COMMON_VIEW_TYPE_H_
  6846. +#define USERSCRIPTS_COMMON_VIEW_TYPE_H_
  6847. +
  6848. +#include <string>
  6849. +
  6850. +namespace user_scripts {
  6851. +
  6852. +// Icky RTTI used by a few systems to distinguish the host type of a given
  6853. +// WebContents.
  6854. +//
  6855. +// Do not change or reuse the the entry values in this list as this is used in
  6856. +// ExtensionViewType enum in tools/metrics/histograms/enums.xml.
  6857. +//
  6858. +// TODO(aa): Remove this and teach those systems to keep track of their own
  6859. +// data.
  6860. +enum ViewType {
  6861. + VIEW_TYPE_INVALID = 0,
  6862. + // VIEW_TYPE_APP_WINDOW = 1,
  6863. + // VIEW_TYPE_BACKGROUND_CONTENTS = 2,
  6864. +
  6865. + // // For custom parts of Chrome if no other type applies.
  6866. + // VIEW_TYPE_COMPONENT = 3,
  6867. +
  6868. + // VIEW_TYPE_EXTENSION_BACKGROUND_PAGE = 4,
  6869. + // VIEW_TYPE_EXTENSION_DIALOG = 5,
  6870. + // VIEW_TYPE_EXTENSION_GUEST = 6,
  6871. + // VIEW_TYPE_EXTENSION_POPUP = 7,
  6872. +
  6873. + // Panels were removed in https://crbug.com/571511.
  6874. + // DEPRECATED_VIEW_TYPE_PANEL = 8,
  6875. +
  6876. + VIEW_TYPE_TAB_CONTENTS = 9,
  6877. +
  6878. + VIEW_TYPE_LAST = VIEW_TYPE_TAB_CONTENTS
  6879. +};
  6880. +
  6881. +// Matches the |view_type| to the corresponding ViewType, and populates
  6882. +// |view_type_out|. Returns true if a match is found.
  6883. +bool GetViewTypeFromString(const std::string& view_type,
  6884. + ViewType* view_type_out);
  6885. +
  6886. +} // namespace extensions
  6887. +
  6888. +#endif // USERSCRIPTS_COMMON_VIEW_TYPE_H_
  6889. diff --git a/components/user_scripts/renderer/BUILD.gn b/components/user_scripts/renderer/BUILD.gn
  6890. new file mode 100755
  6891. --- /dev/null
  6892. +++ b/components/user_scripts/renderer/BUILD.gn
  6893. @@ -0,0 +1,67 @@
  6894. +# Copyright 2015 The Chromium Authors. All rights reserved.
  6895. +# Use of this source code is governed by a BSD-style license that can be
  6896. +# found in the LICENSE file.
  6897. +
  6898. +import("//tools/grit/grit_rule.gni")
  6899. +import("//tools/grit/repack.gni")
  6900. +
  6901. +group("user_scripts_resources") {
  6902. + public_deps = [
  6903. + ":user_scripts_renderer_resources",
  6904. + ]
  6905. +}
  6906. +
  6907. +grit("user_scripts_renderer_resources") {
  6908. + source = "resources/user_scripts_renderer_resources.grd"
  6909. + outputs = [
  6910. + "grit/user_scripts_renderer_resources.h",
  6911. + "user_scripts_renderer_resources.pak",
  6912. + ]
  6913. + grit_flags = [
  6914. + "-E",
  6915. + "mojom_root=" + rebase_path(root_gen_dir, root_build_dir),
  6916. + ]
  6917. +}
  6918. +
  6919. +static_library("renderer") {
  6920. + sources = [
  6921. + "extension_frame_helper.cc",
  6922. + "extension_frame_helper.h",
  6923. + "injection_host.cc",
  6924. + "injection_host.h",
  6925. + "script_injection_manager.cc",
  6926. + "script_injection_manager.h",
  6927. + "script_injection_callback.cc",
  6928. + "script_injection_callback.h",
  6929. + "script_injection.cc",
  6930. + "script_injection.h",
  6931. + "script_injector.h",
  6932. + "script_context.cc",
  6933. + "script_context.h",
  6934. + "scripts_run_info.cc",
  6935. + "scripts_run_info.h",
  6936. + "user_script_injector.cc",
  6937. + "user_script_injector.h",
  6938. + "user_script_set_manager.cc",
  6939. + "user_script_set_manager.h",
  6940. + "user_script_set.cc",
  6941. + "user_script_set.h",
  6942. + "user_scripts_dispatcher.cc",
  6943. + "user_scripts_dispatcher.h",
  6944. + "user_scripts_renderer_client.cc",
  6945. + "user_scripts_renderer_client.h",
  6946. + "web_ui_injection_host.cc",
  6947. + "web_ui_injection_host.h",
  6948. + ]
  6949. +
  6950. + deps = [
  6951. + ":user_scripts_resources",
  6952. + "//base",
  6953. + "//content/public/common",
  6954. + "//content/public/renderer",
  6955. + "//components/user_scripts/common",
  6956. + "//mojo/public/cpp/bindings",
  6957. + "//third_party/blink/public:blink_headers",
  6958. + "//v8",
  6959. + ]
  6960. +}
  6961. diff --git a/components/user_scripts/renderer/extension_frame_helper.cc b/components/user_scripts/renderer/extension_frame_helper.cc
  6962. new file mode 100755
  6963. --- /dev/null
  6964. +++ b/components/user_scripts/renderer/extension_frame_helper.cc
  6965. @@ -0,0 +1,96 @@
  6966. +// Copyright 2013 The Chromium Authors. All rights reserved.
  6967. +// Use of this source code is governed by a BSD-style license that can be
  6968. +// found in the LICENSE file.
  6969. +
  6970. +#include "extension_frame_helper.h"
  6971. +
  6972. +#include <set>
  6973. +
  6974. +#include "base/metrics/histogram_macros.h"
  6975. +#include "base/strings/string_util.h"
  6976. +#include "base/timer/elapsed_timer.h"
  6977. +#include "content/public/renderer/render_frame.h"
  6978. +#include "content/public/renderer/render_view.h"
  6979. +#include "../common/constants.h"
  6980. +#include "third_party/blink/public/platform/web_security_origin.h"
  6981. +#include "third_party/blink/public/web/web_console_message.h"
  6982. +#include "third_party/blink/public/web/web_document.h"
  6983. +#include "third_party/blink/public/web/web_document_loader.h"
  6984. +#include "third_party/blink/public/web/web_local_frame.h"
  6985. +#include "third_party/blink/public/web/web_settings.h"
  6986. +#include "third_party/blink/public/web/web_view.h"
  6987. +
  6988. +namespace user_scripts {
  6989. +
  6990. +namespace {
  6991. +
  6992. +base::LazyInstance<std::set<const ExtensionFrameHelper*>>::DestructorAtExit
  6993. + g_frame_helpers = LAZY_INSTANCE_INITIALIZER;
  6994. +
  6995. +// Runs every callback in |callbacks_to_be_run_and_cleared| while |frame_helper|
  6996. +// is valid, and clears |callbacks_to_be_run_and_cleared|.
  6997. +void RunCallbacksWhileFrameIsValid(
  6998. + base::WeakPtr<ExtensionFrameHelper> frame_helper,
  6999. + std::vector<base::OnceClosure>* callbacks_to_be_run_and_cleared) {
  7000. + // The JavaScript code can cause re-entrancy. To avoid a deadlock, don't run
  7001. + // callbacks that are added during the iteration.
  7002. + std::vector<base::OnceClosure> callbacks;
  7003. + callbacks_to_be_run_and_cleared->swap(callbacks);
  7004. + for (auto& callback : callbacks) {
  7005. + std::move(callback).Run();
  7006. + if (!frame_helper.get())
  7007. + return; // Frame and ExtensionFrameHelper invalidated by callback.
  7008. + }
  7009. +}
  7010. +
  7011. +} // namespace
  7012. +
  7013. +ExtensionFrameHelper::ExtensionFrameHelper(content::RenderFrame* render_frame)
  7014. + : content::RenderFrameObserver(render_frame),
  7015. + content::RenderFrameObserverTracker<ExtensionFrameHelper>(render_frame),
  7016. + tab_id_(-1) {
  7017. + g_frame_helpers.Get().insert(this);
  7018. +}
  7019. +
  7020. +ExtensionFrameHelper::~ExtensionFrameHelper() {
  7021. + g_frame_helpers.Get().erase(this);
  7022. +}
  7023. +
  7024. +void ExtensionFrameHelper::ScheduleAtDocumentStart(
  7025. + base::OnceClosure callback) {
  7026. + document_element_created_callbacks_.push_back(std::move(callback));
  7027. +}
  7028. +
  7029. +void ExtensionFrameHelper::ScheduleAtDocumentEnd(
  7030. + base::OnceClosure callback) {
  7031. + document_load_finished_callbacks_.push_back(std::move(callback));
  7032. +}
  7033. +
  7034. +void ExtensionFrameHelper::ScheduleAtDocumentIdle(
  7035. + base::OnceClosure callback) {
  7036. + document_idle_callbacks_.push_back(std::move(callback));
  7037. +}
  7038. +
  7039. +void ExtensionFrameHelper::RunScriptsAtDocumentStart() {
  7040. + RunCallbacksWhileFrameIsValid(weak_ptr_factory_.GetWeakPtr(),
  7041. + &document_element_created_callbacks_);
  7042. + // |this| might be dead by now.
  7043. +}
  7044. +
  7045. +void ExtensionFrameHelper::RunScriptsAtDocumentEnd() {
  7046. + RunCallbacksWhileFrameIsValid(weak_ptr_factory_.GetWeakPtr(),
  7047. + &document_load_finished_callbacks_);
  7048. + // |this| might be dead by now.
  7049. +}
  7050. +
  7051. +void ExtensionFrameHelper::RunScriptsAtDocumentIdle() {
  7052. + RunCallbacksWhileFrameIsValid(weak_ptr_factory_.GetWeakPtr(),
  7053. + &document_idle_callbacks_);
  7054. + // |this| might be dead by now.
  7055. +}
  7056. +
  7057. +void ExtensionFrameHelper::OnDestruct() {
  7058. + delete this;
  7059. +}
  7060. +
  7061. +} // namespace user_scripts
  7062. diff --git a/components/user_scripts/renderer/extension_frame_helper.h b/components/user_scripts/renderer/extension_frame_helper.h
  7063. new file mode 100755
  7064. --- /dev/null
  7065. +++ b/components/user_scripts/renderer/extension_frame_helper.h
  7066. @@ -0,0 +1,92 @@
  7067. +// Copyright 2013 The Chromium Authors. All rights reserved.
  7068. +// Use of this source code is governed by a BSD-style license that can be
  7069. +// found in the LICENSE file.
  7070. +
  7071. +#ifndef USERSCRIPTS_RENDERER_EXTENSION_FRAME_HELPER_H_
  7072. +#define USERSCRIPTS_RENDERER_EXTENSION_FRAME_HELPER_H_
  7073. +
  7074. +#include <string>
  7075. +#include <vector>
  7076. +
  7077. +#include "base/callback_forward.h"
  7078. +#include "base/macros.h"
  7079. +#include "base/memory/weak_ptr.h"
  7080. +#include "content/public/renderer/render_frame_observer.h"
  7081. +#include "content/public/renderer/render_frame_observer_tracker.h"
  7082. +#include "../common/view_type.h"
  7083. +#include "third_party/blink/public/mojom/devtools/console_message.mojom.h"
  7084. +#include "v8/include/v8.h"
  7085. +
  7086. +struct ExtensionMsg_ExternalConnectionInfo;
  7087. +struct ExtensionMsg_TabConnectionInfo;
  7088. +
  7089. +namespace base {
  7090. +class ListValue;
  7091. +}
  7092. +
  7093. +namespace user_scripts {
  7094. +
  7095. +class Dispatcher;
  7096. +struct Message;
  7097. +struct PortId;
  7098. +class ScriptContext;
  7099. +
  7100. +// RenderFrame-level plumbing for extension features.
  7101. +class ExtensionFrameHelper
  7102. + : public content::RenderFrameObserver,
  7103. + public content::RenderFrameObserverTracker<ExtensionFrameHelper> {
  7104. + public:
  7105. + ExtensionFrameHelper(content::RenderFrame* render_frame /*,
  7106. + Dispatcher* extension_dispatcher*/);
  7107. + ~ExtensionFrameHelper() override;
  7108. +
  7109. + int tab_id() const { return tab_id_; }
  7110. +
  7111. + // Called when the document element has been inserted in this frame. This
  7112. + // method may invoke untrusted JavaScript code that invalidate the frame and
  7113. + // this ExtensionFrameHelper.
  7114. + void RunScriptsAtDocumentStart();
  7115. +
  7116. + // Called after the DOMContentLoaded event has fired.
  7117. + void RunScriptsAtDocumentEnd();
  7118. +
  7119. + // Called before the window.onload event is fired.
  7120. + void RunScriptsAtDocumentIdle();
  7121. +
  7122. + // Schedule a callback, to be run at the next RunScriptsAtDocumentStart
  7123. + // notification. Only call this when you are certain that there will be such a
  7124. + // notification, e.g. from RenderFrameObserver::DidCreateDocumentElement.
  7125. + // Otherwise the callback is never invoked, or invoked for a document that you
  7126. + // were not expecting.
  7127. + void ScheduleAtDocumentStart(base::OnceClosure callback);
  7128. +
  7129. + // Schedule a callback, to be run at the next RunScriptsAtDocumentEnd call.
  7130. + void ScheduleAtDocumentEnd(base::OnceClosure callback);
  7131. +
  7132. + // Schedule a callback, to be run at the next RunScriptsAtDocumentIdle call.
  7133. + void ScheduleAtDocumentIdle(base::OnceClosure callback);
  7134. +
  7135. + private:
  7136. +
  7137. + void OnDestruct() override;
  7138. +
  7139. + // The id of the tab the render frame is attached to.
  7140. + int tab_id_;
  7141. +
  7142. + // Callbacks to be run at the next RunScriptsAtDocumentStart notification.
  7143. + std::vector<base::OnceClosure> document_element_created_callbacks_;
  7144. +
  7145. + // Callbacks to be run at the next RunScriptsAtDocumentEnd notification.
  7146. + std::vector<base::OnceClosure> document_load_finished_callbacks_;
  7147. +
  7148. + // Callbacks to be run at the next RunScriptsAtDocumentIdle notification.
  7149. + std::vector<base::OnceClosure> document_idle_callbacks_;
  7150. +
  7151. + base::WeakPtrFactory<ExtensionFrameHelper> weak_ptr_factory_{this};
  7152. +
  7153. + DISALLOW_COPY_AND_ASSIGN(ExtensionFrameHelper);
  7154. +};
  7155. +
  7156. +} // namespace extensions
  7157. +
  7158. +#endif // USERSCRIPTS_RENDERER_EXTENSION_FRAME_HELPER_H_
  7159. diff --git a/components/user_scripts/renderer/injection_host.cc b/components/user_scripts/renderer/injection_host.cc
  7160. new file mode 100755
  7161. --- /dev/null
  7162. +++ b/components/user_scripts/renderer/injection_host.cc
  7163. @@ -0,0 +1,12 @@
  7164. +// Copyright 2015 The Chromium Authors. All rights reserved.
  7165. +// Use of this source code is governed by a BSD-style license that can be
  7166. +// found in the LICENSE file.
  7167. +
  7168. +#include "injection_host.h"
  7169. +
  7170. +InjectionHost::InjectionHost(const HostID& host_id) :
  7171. + id_(host_id) {
  7172. +}
  7173. +
  7174. +InjectionHost::~InjectionHost() {
  7175. +}
  7176. diff --git a/components/user_scripts/renderer/injection_host.h b/components/user_scripts/renderer/injection_host.h
  7177. new file mode 100755
  7178. --- /dev/null
  7179. +++ b/components/user_scripts/renderer/injection_host.h
  7180. @@ -0,0 +1,42 @@
  7181. +// Copyright 2015 The Chromium Authors. All rights reserved.
  7182. +// Use of this source code is governed by a BSD-style license that can be
  7183. +// found in the LICENSE file.
  7184. +
  7185. +#ifndef USERSCRIPTS_RENDERER_INJECTION_HOST_H_
  7186. +#define USERSCRIPTS_RENDERER_INJECTION_HOST_H_
  7187. +
  7188. +#include "base/macros.h"
  7189. +#include "../common/host_id.h"
  7190. +#include "url/gurl.h"
  7191. +
  7192. +namespace content {
  7193. +class RenderFrame;
  7194. +}
  7195. +
  7196. +// An interface for all kinds of hosts who own user scripts.
  7197. +class InjectionHost {
  7198. + public:
  7199. + InjectionHost(const HostID& host_id);
  7200. + virtual ~InjectionHost();
  7201. +
  7202. + // Returns the CSP to be used for the isolated world. Currently this only
  7203. + // bypasses the main world CSP. If null is returned, the main world CSP is not
  7204. + // bypassed.
  7205. + virtual const std::string* GetContentSecurityPolicy() const = 0;
  7206. +
  7207. + // The base url for the host.
  7208. + virtual const GURL& url() const = 0;
  7209. +
  7210. + // The human-readable name of the host.
  7211. + virtual const std::string& name() const = 0;
  7212. +
  7213. + const HostID& id() const { return id_; }
  7214. +
  7215. + private:
  7216. + // The ID of the host.
  7217. + HostID id_;
  7218. +
  7219. + DISALLOW_COPY_AND_ASSIGN(InjectionHost);
  7220. +};
  7221. +
  7222. +#endif // USERSCRIPTS_RENDERER_INJECTION_HOST_H_
  7223. diff --git a/components/user_scripts/renderer/resources/greasemonkey_api.js b/components/user_scripts/renderer/resources/greasemonkey_api.js
  7224. new file mode 100755
  7225. --- /dev/null
  7226. +++ b/components/user_scripts/renderer/resources/greasemonkey_api.js
  7227. @@ -0,0 +1,82 @@
  7228. +// Copyright 2014 The Chromium Authors. All rights reserved.
  7229. +// Use of this source code is governed by a BSD-style license that can be
  7230. +// found in the LICENSE file.
  7231. +
  7232. +// -----------------------------------------------------------------------------
  7233. +// NOTE: If you change this file you need to touch renderer_resources.grd to
  7234. +// have your change take effect.
  7235. +// -----------------------------------------------------------------------------
  7236. +
  7237. +// Partial implementation of the Greasemonkey API, see:
  7238. +// http://wiki.greasespot.net/Greasemonkey_Manual:APIs
  7239. +
  7240. +function GM_addStyle(css) {
  7241. + var parent = document.getElementsByTagName("head")[0];
  7242. + if (!parent) {
  7243. + parent = document.documentElement;
  7244. + }
  7245. + var style = document.createElement("style");
  7246. + style.type = "text/css";
  7247. + var textNode = document.createTextNode(css);
  7248. + style.appendChild(textNode);
  7249. + parent.appendChild(style);
  7250. +}
  7251. +
  7252. +function GM_xmlhttpRequest(details) {
  7253. + function setupEvent(xhr, url, eventName, callback) {
  7254. + xhr[eventName] = function () {
  7255. + var isComplete = xhr.readyState == 4;
  7256. + var responseState = {
  7257. + responseText: xhr.responseText,
  7258. + readyState: xhr.readyState,
  7259. + responseHeaders: isComplete ? xhr.getAllResponseHeaders() : "",
  7260. + status: isComplete ? xhr.status : 0,
  7261. + statusText: isComplete ? xhr.statusText : "",
  7262. + finalUrl: isComplete ? url : ""
  7263. + };
  7264. + callback(responseState);
  7265. + };
  7266. + }
  7267. +
  7268. + var xhr = new XMLHttpRequest();
  7269. + var eventNames = ["onload", "onerror", "onreadystatechange"];
  7270. + for (var i = 0; i < eventNames.length; i++ ) {
  7271. + var eventName = eventNames[i];
  7272. + if (eventName in details) {
  7273. + setupEvent(xhr, details.url, eventName, details[eventName]);
  7274. + }
  7275. + }
  7276. +
  7277. + xhr.open(details.method, details.url);
  7278. +
  7279. + if (details.overrideMimeType) {
  7280. + xhr.overrideMimeType(details.overrideMimeType);
  7281. + }
  7282. + if (details.headers) {
  7283. + for (var header in details.headers) {
  7284. + xhr.setRequestHeader(header, details.headers[header]);
  7285. + }
  7286. + }
  7287. + xhr.send(details.data ? details.data : null);
  7288. +}
  7289. +
  7290. +function GM_openInTab(url) {
  7291. + window.open(url, "");
  7292. +}
  7293. +
  7294. +function GM_log(message) {
  7295. + window.console.log(message);
  7296. +}
  7297. +
  7298. +(function() {
  7299. + function generateGreasemonkeyStub(name) {
  7300. + return function() {
  7301. + console.log("%s is not supported.", name);
  7302. + };
  7303. + }
  7304. +
  7305. + var apis = ["GM_getValue", "GM_setValue", "GM_registerMenuCommand"];
  7306. + for (var i = 0, api; api = apis[i]; i++) {
  7307. + window[api] = generateGreasemonkeyStub(api);
  7308. + }
  7309. +})();
  7310. diff --git a/components/user_scripts/renderer/resources/user_scripts_renderer_resources.grd b/components/user_scripts/renderer/resources/user_scripts_renderer_resources.grd
  7311. new file mode 100755
  7312. --- /dev/null
  7313. +++ b/components/user_scripts/renderer/resources/user_scripts_renderer_resources.grd
  7314. @@ -0,0 +1,14 @@
  7315. +<?xml version="1.0" encoding="UTF-8"?>
  7316. +<grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
  7317. + <outputs>
  7318. + <output filename="grit/user_scripts_renderer_resources.h" type="rc_header">
  7319. + <emit emit_type='prepend'></emit>
  7320. + </output>
  7321. + <output filename="user_scripts_renderer_resources.pak" type="data_package" />
  7322. + </outputs>
  7323. + <release seq="1">
  7324. + <includes>
  7325. + <include name="IDR_GREASEMONKEY_API_JS" file="greasemonkey_api.js" type="BINDATA" />
  7326. + </includes>
  7327. + </release>
  7328. +</grit>
  7329. diff --git a/components/user_scripts/renderer/script_context.cc b/components/user_scripts/renderer/script_context.cc
  7330. new file mode 100755
  7331. --- /dev/null
  7332. +++ b/components/user_scripts/renderer/script_context.cc
  7333. @@ -0,0 +1,213 @@
  7334. +// Copyright 2014 The Chromium Authors. All rights reserved.
  7335. +// Use of this source code is governed by a BSD-style license that can be
  7336. +// found in the LICENSE file.
  7337. +
  7338. +#include "script_context.h"
  7339. +
  7340. +#include "base/command_line.h"
  7341. +#include "base/containers/flat_set.h"
  7342. +#include "base/logging.h"
  7343. +#include "base/stl_util.h"
  7344. +#include "base/strings/string_util.h"
  7345. +#include "base/strings/stringprintf.h"
  7346. +#include "base/values.h"
  7347. +#include "content/public/common/content_switches.h"
  7348. +#include "content/public/common/url_constants.h"
  7349. +#include "content/public/renderer/render_frame.h"
  7350. +#include "../common/constants.h"
  7351. +#include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h"
  7352. +#include "third_party/blink/public/platform/web_security_origin.h"
  7353. +#include "third_party/blink/public/web/web_document.h"
  7354. +#include "third_party/blink/public/web/web_document_loader.h"
  7355. +#include "third_party/blink/public/web/web_local_frame.h"
  7356. +#include "third_party/blink/public/web/web_navigation_params.h"
  7357. +#include "v8/include/v8.h"
  7358. +
  7359. +namespace user_scripts {
  7360. +
  7361. +namespace {
  7362. +
  7363. +GURL GetEffectiveDocumentURL(
  7364. + blink::WebLocalFrame* frame,
  7365. + const GURL& document_url,
  7366. + MatchOriginAsFallbackBehavior match_origin_as_fallback,
  7367. + bool allow_inaccessible_parents) {
  7368. + auto should_consider_origin = [document_url, match_origin_as_fallback]() {
  7369. + switch (match_origin_as_fallback) {
  7370. + case MatchOriginAsFallbackBehavior::kNever:
  7371. + return false;
  7372. + case MatchOriginAsFallbackBehavior::kMatchForAboutSchemeAndClimbTree:
  7373. + return document_url.SchemeIs(url::kAboutScheme);
  7374. + case MatchOriginAsFallbackBehavior::kAlways:
  7375. + // TODO(devlin): Add more schemes here - blob, filesystem, etc.
  7376. + return document_url.SchemeIs(url::kAboutScheme) ||
  7377. + document_url.SchemeIs(url::kDataScheme);
  7378. + }
  7379. +
  7380. + NOTREACHED();
  7381. + };
  7382. +
  7383. + // If we don't need to consider the origin, we're done.
  7384. + if (!should_consider_origin())
  7385. + return document_url;
  7386. +
  7387. + // Get the "security origin" for the frame. For about: frames, this is the
  7388. + // origin of that of the controlling frame - e.g., an about:blank frame on
  7389. + // https://example.com will have the security origin of https://example.com.
  7390. + // Other frames, like data: frames, will have an opaque origin. For these,
  7391. + // we can get the precursor origin.
  7392. + const blink::WebSecurityOrigin web_frame_origin = frame->GetSecurityOrigin();
  7393. + const url::Origin frame_origin = web_frame_origin;
  7394. + const url::SchemeHostPort& tuple_or_precursor_tuple =
  7395. + frame_origin.GetTupleOrPrecursorTupleIfOpaque();
  7396. +
  7397. + // When there's no valid tuple (which can happen in the case of e.g. a
  7398. + // browser-initiated navigation to an opaque URL), there's no origin to
  7399. + // fallback to. Bail.
  7400. + if (!tuple_or_precursor_tuple.IsValid())
  7401. + return document_url;
  7402. +
  7403. + const url::Origin origin_or_precursor_origin =
  7404. + url::Origin::Create(tuple_or_precursor_tuple.GetURL());
  7405. +
  7406. + if (!allow_inaccessible_parents &&
  7407. + !web_frame_origin.CanAccess(
  7408. + blink::WebSecurityOrigin(origin_or_precursor_origin))) {
  7409. + // The frame can't access its precursor. Bail.
  7410. + return document_url;
  7411. + }
  7412. +
  7413. + // Looks like the initiator origin is an appropriate fallback!
  7414. +
  7415. + if (match_origin_as_fallback == MatchOriginAsFallbackBehavior::kAlways) {
  7416. + // The easy case! We use the origin directly. We're done.
  7417. + return origin_or_precursor_origin.GetURL();
  7418. + }
  7419. +
  7420. + DCHECK_EQ(MatchOriginAsFallbackBehavior::kMatchForAboutSchemeAndClimbTree,
  7421. + match_origin_as_fallback);
  7422. +
  7423. + // Unfortunately, in this case, we have to climb the frame tree. This is for
  7424. + // match patterns that are associated with paths as well, not just origins.
  7425. + // For instance, if an extension wants to run on google.com/maps/* with
  7426. + // match_about_blank true, then it should run on about:-scheme frames created
  7427. + // by google.com/maps, but not about:-scheme frames created by google.com
  7428. + // (which is what the precursor tuple origin would be).
  7429. +
  7430. + // Traverse the frame/window hierarchy to find the closest non-about:-page
  7431. + // with the same origin as the precursor and return its URL.
  7432. + // Note: This can return the incorrect result, e.g. if a parent frame
  7433. + // navigates a grandchild frame.
  7434. + blink::WebFrame* parent = frame;
  7435. + GURL parent_url;
  7436. + blink::WebDocument parent_document;
  7437. + base::flat_set<blink::WebFrame*> already_visited_frames;
  7438. + do {
  7439. + already_visited_frames.insert(parent);
  7440. + if (parent->Parent())
  7441. + parent = parent->Parent();
  7442. + else
  7443. + parent = parent->Opener();
  7444. +
  7445. + // Avoid an infinite loop - see https://crbug.com/568432 and
  7446. + // https://crbug.com/883526.
  7447. + if (base::Contains(already_visited_frames, parent))
  7448. + return document_url;
  7449. +
  7450. + parent_document = parent && parent->IsWebLocalFrame()
  7451. + ? parent->ToWebLocalFrame()->GetDocument()
  7452. + : blink::WebDocument();
  7453. +
  7454. + // We reached the end of the ancestral chain without finding a valid parent,
  7455. + // or found a remote web frame (in which case, it's a different origin).
  7456. + // Bail and use the original URL.
  7457. + if (parent_document.IsNull())
  7458. + return document_url;
  7459. +
  7460. + url::SchemeHostPort parent_tuple_or_precursor_tuple =
  7461. + url::Origin(parent->GetSecurityOrigin())
  7462. + .GetTupleOrPrecursorTupleIfOpaque();
  7463. + if (!parent_tuple_or_precursor_tuple.IsValid() ||
  7464. + parent_tuple_or_precursor_tuple != tuple_or_precursor_tuple) {
  7465. + // The parent has a different tuple origin than frame; this could happen
  7466. + // in edge cases where a parent navigates an iframe or popup of a child
  7467. + // frame at a different origin. [1] In this case, bail, since we can't
  7468. + // find a full URL (i.e., one including the path) with the same security
  7469. + // origin to use for the frame in question.
  7470. + // [1] Consider a frame tree like:
  7471. + // <html> <!--example.com-->
  7472. + // <iframe id="a" src="a.com">
  7473. + // <iframe id="b" src="b.com"></iframe>
  7474. + // </iframe>
  7475. + // </html>
  7476. + // Frame "a" is cross-origin from the top-level frame, and so the
  7477. + // example.com top-level frame can't directly access frame "b". However,
  7478. + // it can navigate it through
  7479. + // window.frames[0].frames[0].location.href = 'about:blank';
  7480. + // In that case, the precursor origin tuple origin of frame "b" would be
  7481. + // example.com, but the parent tuple origin is a.com.
  7482. + // Note that usually, this would have bailed earlier with a remote frame,
  7483. + // but it may not if we're at the process limit.
  7484. + return document_url;
  7485. + }
  7486. +
  7487. + parent_url = GURL(parent_document.Url());
  7488. + } while (parent_url.SchemeIs(url::kAboutScheme));
  7489. +
  7490. + DCHECK(!parent_url.is_empty());
  7491. + DCHECK(!parent_document.IsNull());
  7492. +
  7493. + // We should know that the frame can access the parent document (unless we
  7494. + // explicitly allow it not to), since it has the same tuple origin as the
  7495. + // frame, and we checked the frame access above.
  7496. + DCHECK(allow_inaccessible_parents ||
  7497. + web_frame_origin.CanAccess(parent_document.GetSecurityOrigin()));
  7498. + return parent_url;
  7499. +}
  7500. +
  7501. +using FrameToDocumentLoader =
  7502. + base::flat_map<blink::WebLocalFrame*, blink::WebDocumentLoader*>;
  7503. +
  7504. +FrameToDocumentLoader& FrameDocumentLoaderMap() {
  7505. + static base::NoDestructor<FrameToDocumentLoader> map;
  7506. + return *map;
  7507. +}
  7508. +
  7509. +blink::WebDocumentLoader* CurrentDocumentLoader(
  7510. + const blink::WebLocalFrame* frame) {
  7511. + auto& map = FrameDocumentLoaderMap();
  7512. + auto it = map.find(frame);
  7513. + return it == map.end() ? frame->GetDocumentLoader() : it->second;
  7514. +}
  7515. +
  7516. +} // namespace
  7517. +
  7518. +// static
  7519. +GURL ScriptContext::GetDocumentLoaderURLForFrame(
  7520. + const blink::WebLocalFrame* frame) {
  7521. + // Normally we would use frame->document().url() to determine the document's
  7522. + // URL, but to decide whether to inject a content script, we use the URL from
  7523. + // the data source. This "quirk" helps prevents content scripts from
  7524. + // inadvertently adding DOM elements to the compose iframe in Gmail because
  7525. + // the compose iframe's dataSource URL is about:blank, but the document URL
  7526. + // changes to match the parent document after Gmail document.writes into
  7527. + // it to create the editor.
  7528. + // http://code.google.com/p/chromium/issues/detail?id=86742
  7529. + blink::WebDocumentLoader* document_loader = CurrentDocumentLoader(frame);
  7530. + return document_loader ? GURL(document_loader->GetUrl()) : GURL();
  7531. +}
  7532. +
  7533. +// static
  7534. +GURL ScriptContext::GetEffectiveDocumentURLForInjection(
  7535. + blink::WebLocalFrame* frame,
  7536. + const GURL& document_url,
  7537. + MatchOriginAsFallbackBehavior match_origin_as_fallback) {
  7538. + // We explicitly allow inaccessible parents here. Extensions should still be
  7539. + // able to inject into a sandboxed iframe if it has access to the embedding
  7540. + // origin.
  7541. + constexpr bool allow_inaccessible_parents = true;
  7542. + return GetEffectiveDocumentURL(frame, document_url, match_origin_as_fallback,
  7543. + allow_inaccessible_parents);
  7544. +}
  7545. +
  7546. +} // namespace extensions
  7547. diff --git a/components/user_scripts/renderer/script_context.h b/components/user_scripts/renderer/script_context.h
  7548. new file mode 100755
  7549. --- /dev/null
  7550. +++ b/components/user_scripts/renderer/script_context.h
  7551. @@ -0,0 +1,70 @@
  7552. +// Copyright 2014 The Chromium Authors. All rights reserved.
  7553. +// Use of this source code is governed by a BSD-style license that can be
  7554. +// found in the LICENSE file.
  7555. +
  7556. +#ifndef USERSCRIPTS_RENDERER_SCRIPT_CONTEXT_H_
  7557. +#define USERSCRIPTS_RENDERER_SCRIPT_CONTEXT_H_
  7558. +
  7559. +#include <memory>
  7560. +#include <string>
  7561. +#include <utility>
  7562. +#include <vector>
  7563. +
  7564. +#include "base/callback.h"
  7565. +#include "base/compiler_specific.h"
  7566. +#include "base/macros.h"
  7567. +#include "base/threading/thread_checker.h"
  7568. +#include "base/unguessable_token.h"
  7569. +#include "../common/script_constants.h"
  7570. +#include "script_injection_callback.h"
  7571. +#include "url/gurl.h"
  7572. +#include "v8/include/v8.h"
  7573. +
  7574. +namespace blink {
  7575. +class WebDocumentLoader;
  7576. +class WebLocalFrame;
  7577. +}
  7578. +
  7579. +namespace content {
  7580. +class RenderFrame;
  7581. +}
  7582. +
  7583. +namespace user_scripts {
  7584. +
  7585. +// Extensions wrapper for a v8::Context.
  7586. +//
  7587. +// v8::Contexts can be constructed on any thread, and must only be accessed or
  7588. +// destroyed that thread.
  7589. +//
  7590. +// Note that ScriptContexts bound to worker threads will not have the full
  7591. +// functionality as those bound to the main RenderThread.
  7592. +class ScriptContext {
  7593. + public:
  7594. + // TODO(devlin): Move all these Get*URL*() methods out of here? While they are
  7595. + // vaguely ScriptContext related, there's enough here that they probably
  7596. + // warrant another class or utility file.
  7597. +
  7598. + // Utility to get the URL we will match against for a frame. If the frame has
  7599. + // committed, this is the commited URL. Otherwise it is the provisional URL.
  7600. + // The returned URL may be invalid.
  7601. + static GURL GetDocumentLoaderURLForFrame(const blink::WebLocalFrame* frame);
  7602. +
  7603. + // Used to determine the "effective" URL for extension script injection.
  7604. + // If |document_url| is an about: or data: URL, returns the URL of the first
  7605. + // frame without an about: or data: URL that matches the initiator origin.
  7606. + // This may not be the immediate parent. Returns |document_url| if it is not
  7607. + // an about: or data: URL, if |match_origin_as_fallback| is set to not match,
  7608. + // or if a suitable parent cannot be found.
  7609. + // Considers parent contexts that cannot be accessed (as is the case for
  7610. + // sandboxed frames).
  7611. + static GURL GetEffectiveDocumentURLForInjection(
  7612. + blink::WebLocalFrame* frame,
  7613. + const GURL& document_url,
  7614. + MatchOriginAsFallbackBehavior match_origin_as_fallback);
  7615. +
  7616. +// DISALLOW_COPY_AND_ASSIGN(ScriptContext);
  7617. +};
  7618. +
  7619. +} // namespace extensions
  7620. +
  7621. +#endif // USERSCRIPTS_RENDERER_SCRIPT_CONTEXT_H_
  7622. diff --git a/components/user_scripts/renderer/script_injection.cc b/components/user_scripts/renderer/script_injection.cc
  7623. new file mode 100755
  7624. --- /dev/null
  7625. +++ b/components/user_scripts/renderer/script_injection.cc
  7626. @@ -0,0 +1,342 @@
  7627. +// Copyright 2014 The Chromium Authors. All rights reserved.
  7628. +// Use of this source code is governed by a BSD-style license that can be
  7629. +// found in the LICENSE file.
  7630. +
  7631. +#include "script_injection.h"
  7632. +
  7633. +#include <map>
  7634. +#include <utility>
  7635. +
  7636. +#include "base/bind.h"
  7637. +#include "base/feature_list.h"
  7638. +#include "base/lazy_instance.h"
  7639. +#include "base/macros.h"
  7640. +#include "base/metrics/histogram_macros.h"
  7641. +#include "base/timer/elapsed_timer.h"
  7642. +#include "base/values.h"
  7643. +#include "base/logging.h"
  7644. +#include "content/public/renderer/render_frame.h"
  7645. +#include "content/public/renderer/render_frame_observer.h"
  7646. +#include "content/public/renderer/v8_value_converter.h"
  7647. +#include "../common/host_id.h"
  7648. +#include "script_injection_callback.h"
  7649. +#include "scripts_run_info.h"
  7650. +#include "third_party/blink/public/platform/web_isolated_world_info.h"
  7651. +#include "third_party/blink/public/platform/web_security_origin.h"
  7652. +#include "third_party/blink/public/platform/web_string.h"
  7653. +#include "third_party/blink/public/web/web_document.h"
  7654. +#include "third_party/blink/public/web/web_local_frame.h"
  7655. +#include "third_party/blink/public/web/web_script_source.h"
  7656. +#include "url/gurl.h"
  7657. +
  7658. +namespace user_scripts {
  7659. +
  7660. +namespace {
  7661. +
  7662. +using IsolatedWorldMap = std::map<std::string, int>;
  7663. +base::LazyInstance<IsolatedWorldMap>::DestructorAtExit g_isolated_worlds =
  7664. + LAZY_INSTANCE_INITIALIZER;
  7665. +
  7666. +const int64_t kInvalidRequestId = -1;
  7667. +
  7668. +// Gets the isolated world ID to use for the given |injection_host|. If no
  7669. +// isolated world has been created for that |injection_host| one will be created
  7670. +// and initialized.
  7671. +int GetIsolatedWorldIdForInstance(const InjectionHost* injection_host) {
  7672. + static int g_next_isolated_world_id = 1; // Embedder isolated worlds can use IDs in [1, 1<<29).
  7673. +
  7674. + IsolatedWorldMap& isolated_worlds = g_isolated_worlds.Get();
  7675. +
  7676. + int id = 0;
  7677. + const std::string& key = injection_host->id().id();
  7678. + auto iter = isolated_worlds.find(key);
  7679. + if (iter != isolated_worlds.end()) {
  7680. + id = iter->second;
  7681. + } else {
  7682. + id = g_next_isolated_world_id++;
  7683. + // This map will tend to pile up over time, but realistically, you're never
  7684. + // going to have enough injection hosts for it to matter.
  7685. + isolated_worlds[key] = id;
  7686. + }
  7687. +
  7688. + blink::WebIsolatedWorldInfo info;
  7689. + info.security_origin =
  7690. + blink::WebSecurityOrigin::Create(injection_host->url());
  7691. + info.human_readable_name = blink::WebString::FromUTF8(injection_host->name());
  7692. + info.stable_id = blink::WebString::FromUTF8(key);
  7693. +
  7694. + const std::string* csp = injection_host->GetContentSecurityPolicy();
  7695. + if (csp)
  7696. + info.content_security_policy = blink::WebString::FromUTF8(*csp);
  7697. +
  7698. + // Even though there may be an existing world for this |injection_host|'s key,
  7699. + // the properties may have changed (e.g. due to an extension update).
  7700. + // Overwrite any existing entries.
  7701. + blink::SetIsolatedWorldInfo(id, info);
  7702. +
  7703. + return id;
  7704. +}
  7705. +
  7706. +// This class manages its own lifetime.
  7707. +class TimedScriptInjectionCallback : public ScriptInjectionCallback {
  7708. + public:
  7709. + TimedScriptInjectionCallback(base::WeakPtr<ScriptInjection> injection)
  7710. + : ScriptInjectionCallback(
  7711. + base::Bind(&TimedScriptInjectionCallback::OnCompleted,
  7712. + base::Unretained(this))),
  7713. + injection_(injection) {}
  7714. + ~TimedScriptInjectionCallback() override {}
  7715. +
  7716. + void OnCompleted(const std::vector<v8::Local<v8::Value>>& result) {
  7717. + if (injection_) {
  7718. + base::TimeTicks timestamp(base::TimeTicks::Now());
  7719. + base::Optional<base::TimeDelta> elapsed;
  7720. + // If the script will never execute (such as if the context is destroyed),
  7721. + // willExecute() will not be called, but OnCompleted() will. Only log a
  7722. + // time for execution if the script, in fact, executed.
  7723. + if (!start_time_.is_null())
  7724. + elapsed = timestamp - start_time_;
  7725. + injection_->OnJsInjectionCompleted(result, elapsed);
  7726. + }
  7727. + }
  7728. +
  7729. + void WillExecute() override {
  7730. + start_time_ = base::TimeTicks::Now();
  7731. + }
  7732. +
  7733. + private:
  7734. + base::WeakPtr<ScriptInjection> injection_;
  7735. + base::TimeTicks start_time_;
  7736. +};
  7737. +
  7738. +} // namespace
  7739. +
  7740. +// Watches for the deletion of a RenderFrame, after which is_valid will return
  7741. +// false.
  7742. +class ScriptInjection::FrameWatcher : public content::RenderFrameObserver {
  7743. + public:
  7744. + FrameWatcher(content::RenderFrame* render_frame,
  7745. + ScriptInjection* injection)
  7746. + : content::RenderFrameObserver(render_frame),
  7747. + injection_(injection) {}
  7748. + ~FrameWatcher() override {}
  7749. +
  7750. + private:
  7751. + void WillDetach() override { injection_->invalidate_render_frame(); }
  7752. + void OnDestruct() override { injection_->invalidate_render_frame(); }
  7753. +
  7754. + ScriptInjection* injection_;
  7755. +
  7756. + DISALLOW_COPY_AND_ASSIGN(FrameWatcher);
  7757. +};
  7758. +
  7759. +// static
  7760. +std::string ScriptInjection::GetHostIdForIsolatedWorld(int isolated_world_id) {
  7761. + const IsolatedWorldMap& isolated_worlds = g_isolated_worlds.Get();
  7762. +
  7763. + for (const auto& iter : isolated_worlds) {
  7764. + if (iter.second == isolated_world_id)
  7765. + return iter.first;
  7766. + }
  7767. + return std::string();
  7768. +}
  7769. +
  7770. +// static
  7771. +void ScriptInjection::RemoveIsolatedWorld(const std::string& host_id) {
  7772. + g_isolated_worlds.Get().erase(host_id);
  7773. +}
  7774. +
  7775. +ScriptInjection::ScriptInjection(
  7776. + std::unique_ptr<ScriptInjector> injector,
  7777. + content::RenderFrame* render_frame,
  7778. + std::unique_ptr<const InjectionHost> injection_host,
  7779. + UserScript::RunLocation run_location,
  7780. + bool log_activity)
  7781. + : injector_(std::move(injector)),
  7782. + render_frame_(render_frame),
  7783. + injection_host_(std::move(injection_host)),
  7784. + run_location_(run_location),
  7785. + request_id_(kInvalidRequestId),
  7786. + complete_(false),
  7787. + did_inject_js_(false),
  7788. + log_activity_(log_activity),
  7789. + frame_watcher_(new FrameWatcher(render_frame, this)) {
  7790. + CHECK(injection_host_.get());
  7791. +}
  7792. +
  7793. +ScriptInjection::~ScriptInjection() {
  7794. + if (!complete_)
  7795. + NotifyWillNotInject(ScriptInjector::WONT_INJECT);
  7796. +}
  7797. +
  7798. +ScriptInjection::InjectionResult ScriptInjection::TryToInject(
  7799. + UserScript::RunLocation current_location,
  7800. + ScriptsRunInfo* scripts_run_info,
  7801. + CompletionCallback async_completion_callback) {
  7802. + if (current_location < run_location_)
  7803. + return INJECTION_WAITING; // Wait for the right location.
  7804. +
  7805. + if (request_id_ != kInvalidRequestId) {
  7806. + // We're waiting for permission right now, try again later.
  7807. + return INJECTION_WAITING;
  7808. + }
  7809. +
  7810. + if (!injection_host_) {
  7811. + NotifyWillNotInject(ScriptInjector::EXTENSION_REMOVED);
  7812. + return INJECTION_FINISHED; // We're done.
  7813. + }
  7814. +
  7815. + InjectionResult result = Inject(scripts_run_info);
  7816. + // If the injection is blocked, we need to set the manager so we can
  7817. + // notify it upon completion.
  7818. + if (result == INJECTION_BLOCKED)
  7819. + async_completion_callback_ = std::move(async_completion_callback);
  7820. + return result;
  7821. +}
  7822. +
  7823. +ScriptInjection::InjectionResult ScriptInjection::OnPermissionGranted(
  7824. + ScriptsRunInfo* scripts_run_info) {
  7825. + if (!injection_host_) {
  7826. + NotifyWillNotInject(ScriptInjector::EXTENSION_REMOVED);
  7827. + return INJECTION_FINISHED;
  7828. + }
  7829. +
  7830. + return Inject(scripts_run_info);
  7831. +}
  7832. +
  7833. +void ScriptInjection::OnHostRemoved() {
  7834. + injection_host_.reset(nullptr);
  7835. +}
  7836. +
  7837. +void ScriptInjection::NotifyWillNotInject(
  7838. + ScriptInjector::InjectFailureReason reason) {
  7839. + complete_ = true;
  7840. + injector_->OnWillNotInject(reason, render_frame_);
  7841. +}
  7842. +
  7843. +ScriptInjection::InjectionResult ScriptInjection::Inject(
  7844. + ScriptsRunInfo* scripts_run_info) {
  7845. + DCHECK(injection_host_);
  7846. + //DCHECK(scripts_run_info);
  7847. + DCHECK(!complete_);
  7848. + bool should_inject_js = injector_->ShouldInjectJs(
  7849. + run_location_, scripts_run_info->executing_scripts[host_id().id()]);
  7850. + bool should_inject_css = injector_->ShouldInjectCss(
  7851. + run_location_, scripts_run_info->injected_stylesheets[host_id().id()]);
  7852. +
  7853. + // This can happen if the extension specified a script to
  7854. + // be run in multiple rules, and the script has already run.
  7855. + // See crbug.com/631247.
  7856. + if (!should_inject_js && !should_inject_css) {
  7857. + return INJECTION_FINISHED;
  7858. + }
  7859. +
  7860. + if (should_inject_js)
  7861. + InjectJs(&(scripts_run_info->executing_scripts[host_id().id()]),
  7862. + &(scripts_run_info->num_js));
  7863. + if (should_inject_css)
  7864. + InjectCss(&(scripts_run_info->injected_stylesheets[host_id().id()]),
  7865. + &(scripts_run_info->num_css));
  7866. +
  7867. + complete_ = did_inject_js_ || !should_inject_js;
  7868. +
  7869. + if (complete_) {
  7870. + injector_->OnInjectionComplete(std::move(execution_result_), run_location_,
  7871. + render_frame_);
  7872. + } else {
  7873. + ++scripts_run_info->num_blocking_js;
  7874. + }
  7875. +
  7876. + return complete_ ? INJECTION_FINISHED : INJECTION_BLOCKED;
  7877. +}
  7878. +
  7879. +void ScriptInjection::InjectJs(std::set<std::string>* executing_scripts,
  7880. + size_t* num_injected_js_scripts) {
  7881. + DCHECK(!did_inject_js_);
  7882. + std::vector<blink::WebScriptSource> sources = injector_->GetJsSources(
  7883. + run_location_, executing_scripts, num_injected_js_scripts);
  7884. + DCHECK(!sources.empty());
  7885. + int world_id = GetIsolatedWorldIdForInstance(injection_host_.get());
  7886. + bool is_user_gesture = injector_->IsUserGesture();
  7887. +
  7888. + std::unique_ptr<blink::WebScriptExecutionCallback> callback(
  7889. + new TimedScriptInjectionCallback(weak_ptr_factory_.GetWeakPtr()));
  7890. +
  7891. + base::ElapsedTimer exec_timer;
  7892. +
  7893. + // For content scripts executing during page load, we run them asynchronously
  7894. + // in order to reduce UI jank experienced by the user. (We don't do this for
  7895. + // DOCUMENT_START scripts, because there's no UI to jank until after those
  7896. + // run, so we run them as soon as we can.)
  7897. + // Note: We could potentially also run deferred and browser-driven scripts
  7898. + // asynchronously; however, these are rare enough that there probably isn't
  7899. + // UI jank. If this changes, we can update this.
  7900. + bool should_execute_asynchronously =
  7901. + injector_->script_type() == UserScript::CONTENT_SCRIPT &&
  7902. + (run_location_ == UserScript::DOCUMENT_END ||
  7903. + run_location_ == UserScript::DOCUMENT_IDLE);
  7904. + blink::WebLocalFrame::ScriptExecutionType execution_option =
  7905. + should_execute_asynchronously
  7906. + ? blink::WebLocalFrame::kAsynchronousBlockingOnload
  7907. + : blink::WebLocalFrame::kSynchronous;
  7908. +
  7909. + render_frame_->GetWebFrame()->RequestExecuteScriptInIsolatedWorld(
  7910. + world_id, &sources.front(), sources.size(), is_user_gesture,
  7911. + execution_option, callback.release());
  7912. +}
  7913. +
  7914. +void ScriptInjection::OnJsInjectionCompleted(
  7915. + const std::vector<v8::Local<v8::Value>>& results,
  7916. + base::Optional<base::TimeDelta> elapsed) {
  7917. + DCHECK(!did_inject_js_);
  7918. +
  7919. + bool expects_results = injector_->ExpectsResults();
  7920. + if (expects_results) {
  7921. + if (!results.empty() && !results[0].IsEmpty()) {
  7922. + // Right now, we only support returning single results (per frame).
  7923. + // It's safe to always use the main world context when converting
  7924. + // here. V8ValueConverterImpl shouldn't actually care about the
  7925. + // context scope, and it switches to v8::Object's creation context
  7926. + // when encountered.
  7927. + v8::Local<v8::Context> context =
  7928. + render_frame_->GetWebFrame()->MainWorldScriptContext();
  7929. + execution_result_ =
  7930. + content::V8ValueConverter::Create()->FromV8Value(results[0], context);
  7931. + }
  7932. + if (!execution_result_.get())
  7933. + execution_result_ = std::make_unique<base::Value>();
  7934. + }
  7935. + did_inject_js_ = true;
  7936. +
  7937. + // If |async_completion_callback_| is set, it means the script finished
  7938. + // asynchronously, and we should run it.
  7939. + if (!async_completion_callback_.is_null()) {
  7940. + complete_ = true;
  7941. + injector_->OnInjectionComplete(std::move(execution_result_), run_location_,
  7942. + render_frame_);
  7943. + // Warning: this object can be destroyed after this line!
  7944. + std::move(async_completion_callback_).Run(this);
  7945. + }
  7946. +}
  7947. +
  7948. +void ScriptInjection::InjectCss(std::set<std::string>* injected_stylesheets,
  7949. + size_t* num_injected_stylesheets) {
  7950. + std::vector<blink::WebString> css_sources = injector_->GetCssSources(
  7951. + run_location_, injected_stylesheets, num_injected_stylesheets);
  7952. + blink::WebLocalFrame* web_frame = render_frame_->GetWebFrame();
  7953. + // Default CSS origin is "author", but can be overridden to "user" by scripts.
  7954. + base::Optional<CSSOrigin> css_origin = injector_->GetCssOrigin();
  7955. + blink::WebDocument::CSSOrigin blink_css_origin =
  7956. + css_origin && *css_origin == CSS_ORIGIN_USER
  7957. + ? blink::WebDocument::kUserOrigin
  7958. + : blink::WebDocument::kAuthorOrigin;
  7959. + blink::WebStyleSheetKey style_sheet_key;
  7960. + if (const base::Optional<std::string>& injection_key =
  7961. + injector_->GetInjectionKey())
  7962. + style_sheet_key = blink::WebString::FromASCII(*injection_key);
  7963. + for (const blink::WebString& css : css_sources)
  7964. + web_frame->GetDocument().InsertStyleSheet(css, &style_sheet_key,
  7965. + blink_css_origin);
  7966. +}
  7967. +
  7968. +} // namespace extensions
  7969. diff --git a/components/user_scripts/renderer/script_injection.h b/components/user_scripts/renderer/script_injection.h
  7970. new file mode 100755
  7971. --- /dev/null
  7972. +++ b/components/user_scripts/renderer/script_injection.h
  7973. @@ -0,0 +1,156 @@
  7974. +// Copyright 2014 The Chromium Authors. All rights reserved.
  7975. +// Use of this source code is governed by a BSD-style license that can be
  7976. +// found in the LICENSE file.
  7977. +
  7978. +#ifndef USERSCRIPTS_RENDERER_SCRIPT_INJECTION_H_
  7979. +#define USERSCRIPTS_RENDERER_SCRIPT_INJECTION_H_
  7980. +
  7981. +#include <stdint.h>
  7982. +
  7983. +#include <memory>
  7984. +#include <vector>
  7985. +
  7986. +#include "base/callback.h"
  7987. +#include "base/macros.h"
  7988. +#include "base/memory/weak_ptr.h"
  7989. +#include "base/optional.h"
  7990. +#include "../common/user_script.h"
  7991. +#include "injection_host.h"
  7992. +#include "script_injector.h"
  7993. +
  7994. +struct HostID;
  7995. +
  7996. +namespace content {
  7997. +class RenderFrame;
  7998. +}
  7999. +
  8000. +namespace v8 {
  8001. +class Value;
  8002. +template <class T> class Local;
  8003. +}
  8004. +
  8005. +namespace user_scripts {
  8006. +struct ScriptsRunInfo;
  8007. +
  8008. +// A script wrapper which is aware of whether or not it is allowed to execute,
  8009. +// and contains the implementation to do so.
  8010. +class ScriptInjection {
  8011. + public:
  8012. + enum InjectionResult {
  8013. + INJECTION_FINISHED,
  8014. + INJECTION_BLOCKED,
  8015. + INJECTION_WAITING
  8016. + };
  8017. +
  8018. + using CompletionCallback = base::OnceCallback<void(ScriptInjection*)>;
  8019. +
  8020. + // Return the id of the injection host associated with the given world.
  8021. + static std::string GetHostIdForIsolatedWorld(int world_id);
  8022. +
  8023. + // Remove the isolated world associated with the given injection host.
  8024. + static void RemoveIsolatedWorld(const std::string& host_id);
  8025. +
  8026. + ScriptInjection(std::unique_ptr<ScriptInjector> injector,
  8027. + content::RenderFrame* render_frame,
  8028. + std::unique_ptr<const InjectionHost> injection_host,
  8029. + UserScript::RunLocation run_location,
  8030. + bool log_activity);
  8031. + ~ScriptInjection();
  8032. +
  8033. + // Try to inject the script at the |current_location|. This returns
  8034. + // INJECTION_FINISHED if injection has injected or will never inject, returns
  8035. + // INJECTION_BLOCKED if injection is running asynchronously and has not
  8036. + // finished yet, returns INJECTION_WAITING if injections is delayed (either
  8037. + // for permission purposes or because |current_location| is not the designated
  8038. + // |run_location_|).
  8039. + // If INJECTION_BLOCKED is returned, |async_completion_callback| will be
  8040. + // called upon completion.
  8041. + InjectionResult TryToInject(
  8042. + UserScript::RunLocation current_location,
  8043. + ScriptsRunInfo* scripts_run_info,
  8044. + CompletionCallback async_completion_callback);
  8045. +
  8046. + // Called when permission for the given injection has been granted.
  8047. + // Returns INJECTION_FINISHED if injection has injected or will never inject,
  8048. + // returns INJECTION_BLOCKED if injection is ran asynchronously.
  8049. + InjectionResult OnPermissionGranted(ScriptsRunInfo* scripts_run_info);
  8050. +
  8051. + // Resets the pointer of the injection host when the host is gone.
  8052. + void OnHostRemoved();
  8053. +
  8054. + void invalidate_render_frame() { render_frame_ = nullptr; }
  8055. +
  8056. + // Accessors.
  8057. + content::RenderFrame* render_frame() const { return render_frame_; }
  8058. + const HostID& host_id() const { return injection_host_->id(); }
  8059. + int64_t request_id() const { return request_id_; }
  8060. +
  8061. + // Called when JS injection for the given frame has been completed or
  8062. + // cancelled.
  8063. + void OnJsInjectionCompleted(const std::vector<v8::Local<v8::Value>>& results,
  8064. + base::Optional<base::TimeDelta> elapsed);
  8065. +
  8066. + private:
  8067. + class FrameWatcher;
  8068. +
  8069. + // Sends a message to the browser to request permission to inject.
  8070. + void RequestPermissionFromBrowser();
  8071. +
  8072. + // Injects the script. Returns INJECTION_FINISHED if injection has finished,
  8073. + // otherwise INJECTION_BLOCKED.
  8074. + InjectionResult Inject(ScriptsRunInfo* scripts_run_info);
  8075. +
  8076. + // Inject any JS scripts into the frame for the injection.
  8077. + void InjectJs(std::set<std::string>* executing_scripts,
  8078. + size_t* num_injected_js_scripts);
  8079. +
  8080. + // Inject any CSS source into the frame for the injection.
  8081. + void InjectCss(std::set<std::string>* injected_stylesheets,
  8082. + size_t* num_injected_stylesheets);
  8083. +
  8084. + // Notify that we will not inject, and mark it as acknowledged.
  8085. + void NotifyWillNotInject(ScriptInjector::InjectFailureReason reason);
  8086. +
  8087. + // The injector for this injection.
  8088. + std::unique_ptr<ScriptInjector> injector_;
  8089. +
  8090. + // The RenderFrame into which this should inject the script.
  8091. + content::RenderFrame* render_frame_;
  8092. +
  8093. + // The associated injection host.
  8094. + std::unique_ptr<const InjectionHost> injection_host_;
  8095. +
  8096. + // The location in the document load at which we inject the script.
  8097. + UserScript::RunLocation run_location_;
  8098. +
  8099. + // This injection's request id. This will be -1 unless the injection is
  8100. + // currently waiting on permission.
  8101. + int64_t request_id_;
  8102. +
  8103. + // Whether or not the injection is complete, either via injecting the script
  8104. + // or because it will never complete.
  8105. + bool complete_;
  8106. +
  8107. + // Whether or not the injection successfully injected JS.
  8108. + bool did_inject_js_;
  8109. +
  8110. + // Whether or not we should log dom activity for this injection.
  8111. + bool log_activity_;
  8112. +
  8113. + // Results storage.
  8114. + std::unique_ptr<base::Value> execution_result_;
  8115. +
  8116. + // The callback to run upon completing asynchronously.
  8117. + CompletionCallback async_completion_callback_;
  8118. +
  8119. + // A helper class to hold the render frame and watch for its deletion.
  8120. + std::unique_ptr<FrameWatcher> frame_watcher_;
  8121. +
  8122. + base::WeakPtrFactory<ScriptInjection> weak_ptr_factory_{this};
  8123. +
  8124. + DISALLOW_COPY_AND_ASSIGN(ScriptInjection);
  8125. +};
  8126. +
  8127. +} // namespace extensions
  8128. +
  8129. +#endif // USERSCRIPTS_RENDERER_SCRIPT_INJECTION_H_
  8130. diff --git a/components/user_scripts/renderer/script_injection_callback.cc b/components/user_scripts/renderer/script_injection_callback.cc
  8131. new file mode 100755
  8132. --- /dev/null
  8133. +++ b/components/user_scripts/renderer/script_injection_callback.cc
  8134. @@ -0,0 +1,26 @@
  8135. +// Copyright 2015 The Chromium Authors. All rights reserved.
  8136. +// Use of this source code is governed by a BSD-style license that can be
  8137. +// found in the LICENSE file.
  8138. +
  8139. +#include "script_injection_callback.h"
  8140. +
  8141. +#include "third_party/blink/public/platform/web_vector.h"
  8142. +
  8143. +namespace user_scripts {
  8144. +
  8145. +ScriptInjectionCallback::ScriptInjectionCallback(
  8146. + const CompleteCallback& injection_completed_callback)
  8147. + : injection_completed_callback_(injection_completed_callback) {
  8148. +}
  8149. +
  8150. +ScriptInjectionCallback::~ScriptInjectionCallback() {
  8151. +}
  8152. +
  8153. +void ScriptInjectionCallback::Completed(
  8154. + const blink::WebVector<v8::Local<v8::Value>>& result) {
  8155. + std::vector<v8::Local<v8::Value>> stl_result(result.begin(), result.end());
  8156. + injection_completed_callback_.Run(stl_result);
  8157. + delete this;
  8158. +}
  8159. +
  8160. +} // namespace extensions
  8161. diff --git a/components/user_scripts/renderer/script_injection_callback.h b/components/user_scripts/renderer/script_injection_callback.h
  8162. new file mode 100755
  8163. --- /dev/null
  8164. +++ b/components/user_scripts/renderer/script_injection_callback.h
  8165. @@ -0,0 +1,38 @@
  8166. +// Copyright 2015 The Chromium Authors. All rights reserved.
  8167. +// Use of this source code is governed by a BSD-style license that can be
  8168. +// found in the LICENSE file.
  8169. +
  8170. +#ifndef USERSCRIPTS_RENDERER_SCRIPT_INJECTION_CALLBACK_H_
  8171. +#define USERSCRIPTS_RENDERER_SCRIPT_INJECTION_CALLBACK_H_
  8172. +
  8173. +#include <vector>
  8174. +
  8175. +#include "base/callback.h"
  8176. +#include "base/macros.h"
  8177. +#include "third_party/blink/public/web/web_script_execution_callback.h"
  8178. +#include "v8/include/v8.h"
  8179. +
  8180. +namespace user_scripts {
  8181. +
  8182. +// A wrapper around a callback to notify a script injection when injection
  8183. +// completes.
  8184. +// This class manages its own lifetime.
  8185. +class ScriptInjectionCallback : public blink::WebScriptExecutionCallback {
  8186. + public:
  8187. + using CompleteCallback =
  8188. + base::Callback<void(const std::vector<v8::Local<v8::Value>>& result)>;
  8189. +
  8190. + ScriptInjectionCallback(const CompleteCallback& injection_completed_callback);
  8191. + ~ScriptInjectionCallback() override;
  8192. +
  8193. + void Completed(const blink::WebVector<v8::Local<v8::Value>>& result) override;
  8194. +
  8195. + private:
  8196. + CompleteCallback injection_completed_callback_;
  8197. +
  8198. + DISALLOW_COPY_AND_ASSIGN(ScriptInjectionCallback);
  8199. +};
  8200. +
  8201. +} // namespace extensions
  8202. +
  8203. +#endif // USERSCRIPTS_RENDERER_SCRIPT_INJECTION_CALLBACK_H_
  8204. diff --git a/components/user_scripts/renderer/script_injection_manager.cc b/components/user_scripts/renderer/script_injection_manager.cc
  8205. new file mode 100755
  8206. --- /dev/null
  8207. +++ b/components/user_scripts/renderer/script_injection_manager.cc
  8208. @@ -0,0 +1,417 @@
  8209. +// Copyright 2014 The Chromium Authors. All rights reserved.
  8210. +// Use of this source code is governed by a BSD-style license that can be
  8211. +// found in the LICENSE file.
  8212. +
  8213. +#include "script_injection_manager.h"
  8214. +
  8215. +#include <memory>
  8216. +#include <utility>
  8217. +
  8218. +#include "base/auto_reset.h"
  8219. +#include "base/bind.h"
  8220. +#include "base/feature_list.h"
  8221. +#include "base/memory/weak_ptr.h"
  8222. +#include "base/threading/thread_task_runner_handle.h"
  8223. +#include "base/values.h"
  8224. +#include "base/logging.h"
  8225. +#include "content/public/renderer/render_frame.h"
  8226. +#include "content/public/renderer/render_frame_observer.h"
  8227. +#include "content/public/renderer/render_thread.h"
  8228. +#include "extension_frame_helper.h"
  8229. +#include "../common/host_id.h"
  8230. +#include "script_injection.h"
  8231. +#include "scripts_run_info.h"
  8232. +#include "web_ui_injection_host.h"
  8233. +#include "ipc/ipc_message_macros.h"
  8234. +#include "third_party/blink/public/platform/web_url_error.h"
  8235. +#include "third_party/blink/public/web/web_document.h"
  8236. +#include "third_party/blink/public/web/web_frame.h"
  8237. +#include "third_party/blink/public/web/web_local_frame.h"
  8238. +#include "third_party/blink/public/web/web_view.h"
  8239. +#include "url/gurl.h"
  8240. +#include "../common/user_scripts_features.h"
  8241. +
  8242. +namespace user_scripts {
  8243. +
  8244. +namespace {
  8245. +
  8246. +// The length of time to wait after the DOM is complete to try and run user
  8247. +// scripts.
  8248. +const int kScriptIdleTimeoutInMs = 200;
  8249. +
  8250. +// Returns the RunLocation that follows |run_location|.
  8251. +UserScript::RunLocation NextRunLocation(UserScript::RunLocation run_location) {
  8252. + switch (run_location) {
  8253. + case UserScript::DOCUMENT_START:
  8254. + return UserScript::DOCUMENT_END;
  8255. + case UserScript::DOCUMENT_END:
  8256. + return UserScript::DOCUMENT_IDLE;
  8257. + case UserScript::DOCUMENT_IDLE:
  8258. + return UserScript::RUN_LOCATION_LAST;
  8259. + case UserScript::UNDEFINED:
  8260. + case UserScript::RUN_DEFERRED:
  8261. + case UserScript::BROWSER_DRIVEN:
  8262. + case UserScript::RUN_LOCATION_LAST:
  8263. + break;
  8264. + }
  8265. + NOTREACHED();
  8266. + return UserScript::RUN_LOCATION_LAST;
  8267. +}
  8268. +
  8269. +} // namespace
  8270. +
  8271. +class ScriptInjectionManager::RFOHelper : public content::RenderFrameObserver {
  8272. + public:
  8273. + RFOHelper(content::RenderFrame* render_frame,
  8274. + ScriptInjectionManager* manager);
  8275. + ~RFOHelper() override;
  8276. +
  8277. + // commit @9f2aac4
  8278. + void Initialize();
  8279. +
  8280. + private:
  8281. + // RenderFrameObserver implementation.
  8282. + void DidCreateNewDocument() override;
  8283. + void DidCreateDocumentElement() override;
  8284. + void DidFailProvisionalLoad() override;
  8285. + void DidFinishDocumentLoad() override;
  8286. + void WillDetach() override;
  8287. + void OnDestruct() override;
  8288. + void OnStop() override;
  8289. +
  8290. + // Tells the ScriptInjectionManager to run tasks associated with
  8291. + // document_idle.
  8292. + void RunIdle();
  8293. +
  8294. + void StartInjectScripts(UserScript::RunLocation run_location);
  8295. +
  8296. + // Indicate that the frame is no longer valid because it is starting
  8297. + // a new load or closing.
  8298. + void InvalidateAndResetFrame(bool force_reset);
  8299. +
  8300. + // The owning ScriptInjectionManager.
  8301. + ScriptInjectionManager* manager_;
  8302. +
  8303. + bool should_run_idle_ = true; // commit @9f2aac4
  8304. +
  8305. + base::WeakPtrFactory<RFOHelper> weak_factory_{this};
  8306. +};
  8307. +
  8308. +ScriptInjectionManager::RFOHelper::RFOHelper(content::RenderFrame* render_frame,
  8309. + ScriptInjectionManager* manager)
  8310. + : content::RenderFrameObserver(render_frame),
  8311. + manager_(manager),
  8312. + should_run_idle_(true) {}
  8313. +
  8314. +ScriptInjectionManager::RFOHelper::~RFOHelper() {
  8315. +}
  8316. +
  8317. +
  8318. +void ScriptInjectionManager::RFOHelper::Initialize() {
  8319. + // Set up for the initial empty document, for which the Document created
  8320. + // events do not happen as it's already present.
  8321. + DidCreateNewDocument();
  8322. + // The initial empty document for a main frame may have scripts attached to it
  8323. + // but we do not want to invalidate the frame and lose them when the next
  8324. + // document loads. For example the IncognitoApiTest.IncognitoSplitMode test
  8325. + // does `chrome.tabs.create()` with a script to be run, which is added to the
  8326. + // frame before it navigates, so it needs to be preserved. However scripts in
  8327. + // child frames are expected to be run inside the initial empty document. For
  8328. + // example the ExecuteScriptApiTest.FrameWithHttp204 test creates a child
  8329. + // frame at about:blank and expects to run injected scripts inside it.
  8330. + // This is all quite inconsistent however tests both depend on us queuing and
  8331. + // not queueing the DOCUMENT_START events in the initial empty document.
  8332. + if (!render_frame()->IsMainFrame()) {
  8333. + DidCreateDocumentElement();
  8334. + }
  8335. +}
  8336. +
  8337. +void ScriptInjectionManager::RFOHelper::DidCreateNewDocument() {
  8338. + // A new document is going to be shown, so invalidate the old document state.
  8339. + // Don't force-reset the frame, because it is possible that a script injection
  8340. + // was scheduled before the page was loaded, e.g. by navigating to a
  8341. + // javascript: URL before the page has loaded.
  8342. + constexpr bool kForceReset = false;
  8343. + InvalidateAndResetFrame(kForceReset);
  8344. +}
  8345. +
  8346. +void ScriptInjectionManager::RFOHelper::DidCreateDocumentElement() {
  8347. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  8348. + LOG(INFO) << "UserScripts: DidCreateDocumentElement -> DOCUMENT_START";
  8349. +
  8350. + ExtensionFrameHelper::Get(render_frame())
  8351. + ->ScheduleAtDocumentStart(
  8352. + base::BindOnce(&ScriptInjectionManager::RFOHelper::StartInjectScripts,
  8353. + weak_factory_.GetWeakPtr(), UserScript::DOCUMENT_START));
  8354. +}
  8355. +
  8356. +void ScriptInjectionManager::RFOHelper::DidFailProvisionalLoad() {
  8357. + auto it = manager_->frame_statuses_.find(render_frame());
  8358. + if (it != manager_->frame_statuses_.end() &&
  8359. + it->second == UserScript::DOCUMENT_START) {
  8360. + // Since the provisional load failed, the frame stays at its previous loaded
  8361. + // state and origin (or the parent's origin for new/about:blank frames).
  8362. + // Reset the frame to DOCUMENT_IDLE in order to reflect that the frame is
  8363. + // done loading, and avoid any deadlock in the system.
  8364. + //
  8365. + // We skip injection of DOCUMENT_END and DOCUMENT_IDLE scripts, because the
  8366. + // injections closely follow the DOMContentLoaded (and onload) events, which
  8367. + // are not triggered after a failed provisional load.
  8368. + // This assumption is verified in the checkDOMContentLoadedEvent subtest of
  8369. + // ExecuteScriptApiTest.FrameWithHttp204 (browser_tests).
  8370. + constexpr bool kForceReset = true;
  8371. + InvalidateAndResetFrame(kForceReset);
  8372. + should_run_idle_ = false;
  8373. + manager_->frame_statuses_[render_frame()] = UserScript::DOCUMENT_IDLE;
  8374. + }
  8375. +}
  8376. +
  8377. +void ScriptInjectionManager::RFOHelper::DidFinishDocumentLoad() {
  8378. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  8379. + LOG(INFO) << "UserScripts: DidFinishDocumentLoad -> DOCUMENT_END";
  8380. +
  8381. + DCHECK(content::RenderThread::Get());
  8382. + ExtensionFrameHelper::Get(render_frame())
  8383. + ->ScheduleAtDocumentEnd(
  8384. + base::BindOnce(&ScriptInjectionManager::RFOHelper::StartInjectScripts,
  8385. + weak_factory_.GetWeakPtr(), UserScript::DOCUMENT_END));
  8386. +
  8387. + // We try to run idle in two places: a delayed task here and in response to
  8388. + // ContentRendererClient::RunScriptsAtDocumentIdle(). DidFinishDocumentLoad()
  8389. + // corresponds to completing the document's load, whereas
  8390. + // RunScriptsAtDocumentIdle() corresponds to completing the document and all
  8391. + // subresources' load (but before the window.onload event). We don't want to
  8392. + // hold up script injection for a particularly slow subresource, so we set a
  8393. + // delayed task from here - but if we finish everything before that point
  8394. + // (i.e., RunScriptsAtDocumentIdle() is triggered), then there's no reason to
  8395. + // keep waiting.
  8396. + render_frame()
  8397. + ->GetTaskRunner(blink::TaskType::kInternalDefault)
  8398. + ->PostDelayedTask(
  8399. + FROM_HERE,
  8400. + base::BindOnce(&ScriptInjectionManager::RFOHelper::RunIdle,
  8401. + weak_factory_.GetWeakPtr()),
  8402. + base::TimeDelta::FromMilliseconds(kScriptIdleTimeoutInMs));
  8403. +
  8404. + ExtensionFrameHelper::Get(render_frame())
  8405. + ->ScheduleAtDocumentIdle(
  8406. + base::BindOnce(&ScriptInjectionManager::RFOHelper::RunIdle,
  8407. + weak_factory_.GetWeakPtr()));
  8408. +}
  8409. +
  8410. +void ScriptInjectionManager::RFOHelper::WillDetach() {
  8411. + // The frame is closing - invalidate.
  8412. + constexpr bool kForceReset = true;
  8413. + InvalidateAndResetFrame(kForceReset);
  8414. +}
  8415. +
  8416. +void ScriptInjectionManager::RFOHelper::OnDestruct() {
  8417. + manager_->RemoveObserver(this);
  8418. +}
  8419. +
  8420. +void ScriptInjectionManager::RFOHelper::OnStop() {
  8421. + // If the navigation request fails (e.g. 204/205/downloads), notify the
  8422. + // extension to avoid keeping the frame in a START state indefinitely which
  8423. + // leads to deadlocks.
  8424. + DidFailProvisionalLoad();
  8425. +}
  8426. +
  8427. +void ScriptInjectionManager::RFOHelper::RunIdle() {
  8428. + // Only notify the manager if the frame hasn't already had idle run since the
  8429. + // task to RunIdle() was posted.
  8430. + if (should_run_idle_) {
  8431. + should_run_idle_ = false;
  8432. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  8433. + LOG(INFO) << "UserScripts: RunIdle -> DOCUMENT_IDLE";
  8434. + manager_->StartInjectScripts(render_frame(), UserScript::DOCUMENT_IDLE);
  8435. + }
  8436. +}
  8437. +
  8438. +void ScriptInjectionManager::RFOHelper::StartInjectScripts(
  8439. + UserScript::RunLocation run_location) {
  8440. + manager_->StartInjectScripts(render_frame(), run_location);
  8441. +}
  8442. +
  8443. +void ScriptInjectionManager::RFOHelper::InvalidateAndResetFrame(
  8444. + bool force_reset) {
  8445. + // Invalidate any pending idle injections, and reset the frame inject on idle.
  8446. + weak_factory_.InvalidateWeakPtrs();
  8447. + // We reset to inject on idle, because the frame can be reused (in the case of
  8448. + // navigation).
  8449. + should_run_idle_ = true;
  8450. +
  8451. + // Reset the frame if either |force_reset| is true, or if the manager is
  8452. + // keeping track of the state of the frame (in which case we need to clean it
  8453. + // up).
  8454. + if (force_reset || manager_->frame_statuses_.count(render_frame()) != 0)
  8455. + manager_->InvalidateForFrame(render_frame());
  8456. +}
  8457. +
  8458. +ScriptInjectionManager::ScriptInjectionManager(
  8459. + UserScriptSetManager* user_script_set_manager)
  8460. + : user_script_set_manager_(user_script_set_manager),
  8461. + user_script_set_manager_observer_(this) {
  8462. + user_script_set_manager_observer_.Add(user_script_set_manager_);
  8463. +}
  8464. +
  8465. +ScriptInjectionManager::~ScriptInjectionManager() {
  8466. + for (const auto& injection : pending_injections_)
  8467. + injection->invalidate_render_frame();
  8468. + for (const auto& injection : running_injections_)
  8469. + injection->invalidate_render_frame();
  8470. +}
  8471. +
  8472. +void ScriptInjectionManager::OnRenderFrameCreated(
  8473. + content::RenderFrame* render_frame) {
  8474. + rfo_helpers_.push_back(std::make_unique<RFOHelper>(render_frame, this));
  8475. + rfo_helpers_.back()->Initialize(); // commit @9f2aac4
  8476. +}
  8477. +
  8478. +void ScriptInjectionManager::OnInjectionFinished(
  8479. + ScriptInjection* injection) {
  8480. + auto iter =
  8481. + std::find_if(running_injections_.begin(), running_injections_.end(),
  8482. + [injection](const std::unique_ptr<ScriptInjection>& mode) {
  8483. + return injection == mode.get();
  8484. + });
  8485. + if (iter != running_injections_.end())
  8486. + running_injections_.erase(iter);
  8487. +}
  8488. +
  8489. +void ScriptInjectionManager::OnUserScriptsUpdated(
  8490. + const std::set<HostID>& changed_hosts) {
  8491. + for (auto iter = pending_injections_.begin();
  8492. + iter != pending_injections_.end();) {
  8493. + if (changed_hosts.count((*iter)->host_id()) > 0)
  8494. + iter = pending_injections_.erase(iter);
  8495. + else
  8496. + ++iter;
  8497. + }
  8498. +}
  8499. +
  8500. +void ScriptInjectionManager::RemoveObserver(RFOHelper* helper) {
  8501. + for (auto iter = rfo_helpers_.begin(); iter != rfo_helpers_.end(); ++iter) {
  8502. + if (iter->get() == helper) {
  8503. + rfo_helpers_.erase(iter);
  8504. + break;
  8505. + }
  8506. + }
  8507. +}
  8508. +
  8509. +void ScriptInjectionManager::InvalidateForFrame(content::RenderFrame* frame) {
  8510. + // If the frame invalidated is the frame being injected into, we need to
  8511. + // note it.
  8512. + active_injection_frames_.erase(frame);
  8513. +
  8514. + for (auto iter = pending_injections_.begin();
  8515. + iter != pending_injections_.end();) {
  8516. + if ((*iter)->render_frame() == frame)
  8517. + iter = pending_injections_.erase(iter);
  8518. + else
  8519. + ++iter;
  8520. + }
  8521. +
  8522. + frame_statuses_.erase(frame);
  8523. +}
  8524. +
  8525. +void ScriptInjectionManager::StartInjectScripts(
  8526. + content::RenderFrame* frame,
  8527. + UserScript::RunLocation run_location) {
  8528. + auto iter = frame_statuses_.find(frame);
  8529. + // We also don't execute if we detect that the run location is somehow out of
  8530. + // order. This can happen if:
  8531. + // - The first run location reported for the frame isn't DOCUMENT_START, or
  8532. + // - The run location reported doesn't immediately follow the previous
  8533. + // reported run location.
  8534. + // We don't want to run because extensions may have requirements that scripts
  8535. + // running in an earlier run location have run by the time a later script
  8536. + // runs. Better to just not run.
  8537. + // Note that we check run_location > NextRunLocation() in the second clause
  8538. + // (as opposed to !=) because earlier signals (like DidCreateDocumentElement)
  8539. + // can happen multiple times, so we can receive earlier/equal run locations.
  8540. + if ((iter == frame_statuses_.end() &&
  8541. + run_location != UserScript::DOCUMENT_START) ||
  8542. + (iter != frame_statuses_.end() &&
  8543. + run_location > NextRunLocation(iter->second))) {
  8544. + // We also invalidate the frame, because the run order of pending injections
  8545. + // may also be bad.
  8546. + InvalidateForFrame(frame);
  8547. + return;
  8548. + } else if (iter != frame_statuses_.end() && iter->second >= run_location) {
  8549. + // Certain run location signals (like DidCreateDocumentElement) can happen
  8550. + // multiple times. Ignore the subsequent signals.
  8551. + return;
  8552. + }
  8553. +
  8554. + // Otherwise, all is right in the world, and we can get on with the
  8555. + // injections!
  8556. + frame_statuses_[frame] = run_location;
  8557. + InjectScripts(frame, run_location);
  8558. +}
  8559. +
  8560. +void ScriptInjectionManager::InjectScripts(
  8561. + content::RenderFrame* frame,
  8562. + UserScript::RunLocation run_location) {
  8563. + // Find any injections that want to run on the given frame.
  8564. + ScriptInjectionVector frame_injections;
  8565. + for (auto iter = pending_injections_.begin();
  8566. + iter != pending_injections_.end();) {
  8567. + if ((*iter)->render_frame() == frame) {
  8568. + frame_injections.push_back(std::move(*iter));
  8569. + iter = pending_injections_.erase(iter);
  8570. + } else {
  8571. + ++iter;
  8572. + }
  8573. + }
  8574. +
  8575. + // Add any injections for user scripts.
  8576. + int tab_id = ExtensionFrameHelper::Get(frame)->tab_id();
  8577. + user_script_set_manager_->GetAllInjections(&frame_injections, frame, tab_id,
  8578. + run_location);
  8579. +
  8580. + // Note that we are running in |frame|.
  8581. + active_injection_frames_.insert(frame);
  8582. +
  8583. + ScriptsRunInfo scripts_run_info(frame, run_location);
  8584. +
  8585. + for (auto iter = frame_injections.begin(); iter != frame_injections.end();) {
  8586. + // It's possible for thScriptsRunInfoe frame to be invalidated in the course of injection
  8587. + // (if a script removes its own frame, for example). If this happens, abort.
  8588. + if (!active_injection_frames_.count(frame))
  8589. + break;
  8590. + std::unique_ptr<ScriptInjection> injection(std::move(*iter));
  8591. + iter = frame_injections.erase(iter);
  8592. + TryToInject(std::move(injection), run_location, &scripts_run_info);
  8593. + }
  8594. +
  8595. + // We are done running in the frame.
  8596. + active_injection_frames_.erase(frame);
  8597. +
  8598. + scripts_run_info.LogRun(activity_logging_enabled_);
  8599. +}
  8600. +
  8601. +void ScriptInjectionManager::TryToInject(
  8602. + std::unique_ptr<ScriptInjection> injection,
  8603. + UserScript::RunLocation run_location,
  8604. + ScriptsRunInfo* scripts_run_info) {
  8605. + // Try to inject the script. If the injection is waiting (i.e., for
  8606. + // permission), add it to the list of pending injections. If the injection
  8607. + // has blocked, add it to the list of running injections.
  8608. + // The Unretained below is safe because this object owns all the
  8609. + // ScriptInjections, so is guaranteed to outlive them.
  8610. + switch (injection->TryToInject(
  8611. + run_location, scripts_run_info,
  8612. + base::Bind(&ScriptInjectionManager::OnInjectionFinished,
  8613. + base::Unretained(this)))) {
  8614. + case ScriptInjection::INJECTION_WAITING:
  8615. + pending_injections_.push_back(std::move(injection));
  8616. + break;
  8617. + case ScriptInjection::INJECTION_BLOCKED:
  8618. + running_injections_.push_back(std::move(injection));
  8619. + break;
  8620. + case ScriptInjection::INJECTION_FINISHED:
  8621. + break;
  8622. + }
  8623. +}
  8624. +
  8625. +} // namespace extensions
  8626. diff --git a/components/user_scripts/renderer/script_injection_manager.h b/components/user_scripts/renderer/script_injection_manager.h
  8627. new file mode 100755
  8628. --- /dev/null
  8629. +++ b/components/user_scripts/renderer/script_injection_manager.h
  8630. @@ -0,0 +1,102 @@
  8631. +#include <stdint.h>
  8632. +
  8633. +#include <map>
  8634. +#include <set>
  8635. +#include <string>
  8636. +#include <vector>
  8637. +
  8638. +#include "base/callback.h"
  8639. +#include "base/macros.h"
  8640. +#include "base/scoped_observer.h"
  8641. +#include "../common/user_script.h"
  8642. +#include "script_injection.h"
  8643. +#include "user_script_set_manager.h"
  8644. +
  8645. +namespace user_scripts {
  8646. +
  8647. +// The ScriptInjectionManager manages extensions injecting scripts into frames
  8648. +// via both content/user scripts and tabs.executeScript(). It is responsible for
  8649. +// maintaining any pending injections awaiting permission or the appropriate
  8650. +// load point, and injecting them when ready.
  8651. +class ScriptInjectionManager : public UserScriptSetManager::Observer {
  8652. + public:
  8653. + explicit ScriptInjectionManager(
  8654. + UserScriptSetManager* user_script_set_manager);
  8655. + virtual ~ScriptInjectionManager();
  8656. +
  8657. + // Notifies that a new render view has been created.
  8658. + void OnRenderFrameCreated(content::RenderFrame* render_frame);
  8659. +
  8660. + // Removes pending injections of the unloaded extension.
  8661. + //void OnExtensionUnloaded(const std::string& extension_id);
  8662. +
  8663. + void set_activity_logging_enabled(bool enabled) {
  8664. + activity_logging_enabled_ = enabled;
  8665. + }
  8666. +
  8667. + private:
  8668. + // A RenderFrameObserver implementation which watches the various render
  8669. + // frames in order to notify the ScriptInjectionManager of different
  8670. + // document load states and IPCs.
  8671. + class RFOHelper;
  8672. +
  8673. + using FrameStatusMap =
  8674. + std::map<content::RenderFrame*, UserScript::RunLocation>;
  8675. +
  8676. + using ScriptInjectionVector = std::vector<std::unique_ptr<ScriptInjection>>;
  8677. +
  8678. + // Notifies that an injection has been finished.
  8679. + void OnInjectionFinished(ScriptInjection* injection);
  8680. +
  8681. + // UserScriptSetManager::Observer implementation.
  8682. + void OnUserScriptsUpdated(const std::set<HostID>& changed_hosts) override;
  8683. +
  8684. + // Notifies that an RFOHelper should be removed.
  8685. + void RemoveObserver(RFOHelper* helper);
  8686. +
  8687. + // Invalidate any pending tasks associated with |frame|.
  8688. + void InvalidateForFrame(content::RenderFrame* frame);
  8689. +
  8690. + // Starts the process to inject appropriate scripts into |frame|.
  8691. + void StartInjectScripts(content::RenderFrame* frame,
  8692. + UserScript::RunLocation run_location);
  8693. +
  8694. + // Actually injects the scripts into |frame|.
  8695. + void InjectScripts(content::RenderFrame* frame,
  8696. + UserScript::RunLocation run_location);
  8697. +
  8698. + // Try to inject and store injection if it has not finished.
  8699. + void TryToInject(std::unique_ptr<ScriptInjection> injection,
  8700. + UserScript::RunLocation run_location,
  8701. + ScriptsRunInfo* scripts_run_info);
  8702. +
  8703. + // The map of active web frames to their corresponding statuses. The
  8704. + // RunLocation of the frame corresponds to the last location that has ran.
  8705. + FrameStatusMap frame_statuses_;
  8706. +
  8707. + // The frames currently being injected into, so long as that frame is valid.
  8708. + std::set<content::RenderFrame*> active_injection_frames_;
  8709. +
  8710. + // The collection of RFOHelpers.
  8711. + std::vector<std::unique_ptr<RFOHelper>> rfo_helpers_;
  8712. +
  8713. + // The set of UserScripts associated with extensions. Owned by the Dispatcher.
  8714. + UserScriptSetManager* user_script_set_manager_;
  8715. +
  8716. + // Pending injections which are waiting for either the proper run location or
  8717. + // user consent.
  8718. + ScriptInjectionVector pending_injections_;
  8719. +
  8720. + // Running injections which are waiting for async callbacks from blink.
  8721. + ScriptInjectionVector running_injections_;
  8722. +
  8723. + // Whether or not dom activity should be logged for scripts injected.
  8724. + bool activity_logging_enabled_ = false;
  8725. +
  8726. + ScopedObserver<UserScriptSetManager, UserScriptSetManager::Observer>
  8727. + user_script_set_manager_observer_;
  8728. +
  8729. + DISALLOW_COPY_AND_ASSIGN(ScriptInjectionManager);
  8730. +};
  8731. +
  8732. +}
  8733. diff --git a/components/user_scripts/renderer/script_injector.h b/components/user_scripts/renderer/script_injector.h
  8734. new file mode 100755
  8735. --- /dev/null
  8736. +++ b/components/user_scripts/renderer/script_injector.h
  8737. @@ -0,0 +1,96 @@
  8738. +// Copyright 2014 The Chromium Authors. All rights reserved.
  8739. +// Use of this source code is governed by a BSD-style license that can be
  8740. +// found in the LICENSE file.
  8741. +
  8742. +#ifndef USERSCRIPTS_RENDERER_SCRIPT_INJECTOR_H_
  8743. +#define USERSCRIPTS_RENDERER_SCRIPT_INJECTOR_H_
  8744. +
  8745. +#include <memory>
  8746. +#include <vector>
  8747. +
  8748. +#include "../common/constants.h"
  8749. +#include "../common/user_script.h"
  8750. +#include "third_party/blink/public/web/web_script_source.h"
  8751. +
  8752. +class InjectionHost;
  8753. +
  8754. +namespace blink {
  8755. +class WebLocalFrame;
  8756. +}
  8757. +
  8758. +namespace user_scripts {
  8759. +
  8760. +// The pseudo-delegate class for a ScriptInjection that provides all necessary
  8761. +// information about how to inject the script, including what code to inject and
  8762. +// when (run location), but without any injection logic.
  8763. +class ScriptInjector {
  8764. + public:
  8765. + // The possible reasons for not injecting the script.
  8766. + enum InjectFailureReason {
  8767. + EXTENSION_REMOVED, // The extension was removed before injection.
  8768. + NOT_ALLOWED, // The script is not allowed to inject.
  8769. + WONT_INJECT // The injection won't inject because the user rejected
  8770. + // (or just did not accept) the injection.
  8771. + };
  8772. +
  8773. + virtual ~ScriptInjector() {}
  8774. +
  8775. + // Returns the script type of this particular injection.
  8776. + virtual UserScript::InjectionType script_type() const = 0;
  8777. +
  8778. + // Returns true if the script is running inside a user gesture.
  8779. + virtual bool IsUserGesture() const = 0;
  8780. +
  8781. + // Returns the CSS origin of this injection.
  8782. + virtual base::Optional<CSSOrigin> GetCssOrigin() const = 0;
  8783. +
  8784. + // Returns the key for this injection, if it's a CSS injection.
  8785. + virtual const base::Optional<std::string> GetInjectionKey() const = 0;
  8786. +
  8787. + // Returns true if the script expects results.
  8788. + virtual bool ExpectsResults() const = 0;
  8789. +
  8790. + // Returns true if the script should inject JS source at the given
  8791. + // |run_location|.
  8792. + virtual bool ShouldInjectJs(
  8793. + UserScript::RunLocation run_location,
  8794. + const std::set<std::string>& executing_scripts) const = 0;
  8795. +
  8796. + // Returns true if the script should inject CSS at the given |run_location|.
  8797. + virtual bool ShouldInjectCss(
  8798. + UserScript::RunLocation run_location,
  8799. + const std::set<std::string>& injected_stylesheets) const = 0;
  8800. +
  8801. + // Returns the javascript sources to inject at the given |run_location|.
  8802. + // Only called if ShouldInjectJs() is true.
  8803. + virtual std::vector<blink::WebScriptSource> GetJsSources(
  8804. + UserScript::RunLocation run_location,
  8805. + std::set<std::string>* executing_scripts,
  8806. + size_t* num_injected_js_scripts) const = 0;
  8807. +
  8808. + // Returns the css to inject at the given |run_location|.
  8809. + // Only called if ShouldInjectCss() is true.
  8810. + virtual std::vector<blink::WebString> GetCssSources(
  8811. + UserScript::RunLocation run_location,
  8812. + std::set<std::string>* injected_stylesheets,
  8813. + size_t* num_injected_stylesheets) const = 0;
  8814. +
  8815. + // Notifies the script that injection has completed, with a possibly-populated
  8816. + // list of results (depending on whether or not ExpectsResults() was true).
  8817. + // |render_frame| contains the render frame, or null if the frame was
  8818. + // invalidated.
  8819. + virtual void OnInjectionComplete(
  8820. + std::unique_ptr<base::Value> execution_result,
  8821. + UserScript::RunLocation run_location,
  8822. + content::RenderFrame* render_frame) = 0;
  8823. +
  8824. + // Notifies the script that injection will never occur.
  8825. + // |render_frame| contains the render frame, or null if the frame was
  8826. + // invalidated.
  8827. + virtual void OnWillNotInject(InjectFailureReason reason,
  8828. + content::RenderFrame* render_frame) = 0;
  8829. +};
  8830. +
  8831. +} // namespace extensions
  8832. +
  8833. +#endif // USERSCRIPTS_RENDERER_SCRIPT_INJECTOR_H_
  8834. diff --git a/components/user_scripts/renderer/scripts_run_info.cc b/components/user_scripts/renderer/scripts_run_info.cc
  8835. new file mode 100755
  8836. --- /dev/null
  8837. +++ b/components/user_scripts/renderer/scripts_run_info.cc
  8838. @@ -0,0 +1,31 @@
  8839. +// Copyright 2014 The Chromium Authors. All rights reserved.
  8840. +// Use of this source code is governed by a BSD-style license that can be
  8841. +// found in the LICENSE file.
  8842. +
  8843. +#include "scripts_run_info.h"
  8844. +
  8845. +#include "base/metrics/histogram_macros.h"
  8846. +#include "content/public/renderer/render_frame.h"
  8847. +#include "content/public/renderer/render_thread.h"
  8848. +#include "script_context.h"
  8849. +#include "third_party/blink/public/web/web_local_frame.h"
  8850. +
  8851. +namespace user_scripts {
  8852. +
  8853. +ScriptsRunInfo::ScriptsRunInfo(content::RenderFrame* render_frame,
  8854. + UserScript::RunLocation location)
  8855. + : num_css(0u),
  8856. + num_js(0u),
  8857. + num_blocking_js(0u),
  8858. + routing_id_(render_frame->GetRoutingID()),
  8859. + run_location_(location),
  8860. + frame_url_(ScriptContext::GetDocumentLoaderURLForFrame(
  8861. + render_frame->GetWebFrame())) {}
  8862. +
  8863. +ScriptsRunInfo::~ScriptsRunInfo() {
  8864. +}
  8865. +
  8866. +void ScriptsRunInfo::LogRun(bool send_script_activity) {
  8867. +}
  8868. +
  8869. +} // namespace extensions
  8870. diff --git a/components/user_scripts/renderer/scripts_run_info.h b/components/user_scripts/renderer/scripts_run_info.h
  8871. new file mode 100755
  8872. --- /dev/null
  8873. +++ b/components/user_scripts/renderer/scripts_run_info.h
  8874. @@ -0,0 +1,70 @@
  8875. +// Copyright 2014 The Chromium Authors. All rights reserved.
  8876. +// Use of this source code is governed by a BSD-style license that can be
  8877. +// found in the LICENSE file.
  8878. +
  8879. +#ifndef USERSCRIPTS_RENDERER_SCRIPTS_RUN_INFO_H_
  8880. +#define USERSCRIPTS_RENDERER_SCRIPTS_RUN_INFO_H_
  8881. +
  8882. +#include <stddef.h>
  8883. +
  8884. +#include <map>
  8885. +#include <set>
  8886. +#include <string>
  8887. +
  8888. +#include "base/macros.h"
  8889. +#include "base/timer/elapsed_timer.h"
  8890. +#include "../common/user_script.h"
  8891. +
  8892. +namespace content {
  8893. +class RenderFrame;
  8894. +}
  8895. +
  8896. +namespace user_scripts {
  8897. +
  8898. +// A struct containing information about a script run.
  8899. +struct ScriptsRunInfo {
  8900. + // Map of extensions IDs to the executing script paths.
  8901. + typedef std::map<std::string, std::set<std::string> > ExecutingScriptsMap;
  8902. +
  8903. + ScriptsRunInfo(content::RenderFrame* render_frame,
  8904. + UserScript::RunLocation location);
  8905. + ~ScriptsRunInfo();
  8906. +
  8907. + // The number of CSS scripts injected.
  8908. + size_t num_css;
  8909. + // The number of JS scripts injected.
  8910. + size_t num_js;
  8911. + // The number of blocked JS scripts injected.
  8912. + size_t num_blocking_js;
  8913. + // A map of extension ids to executing script paths.
  8914. + ExecutingScriptsMap executing_scripts;
  8915. + // A map of extension ids to injected stylesheet paths.
  8916. + ExecutingScriptsMap injected_stylesheets;
  8917. + // The elapsed time since the ScriptsRunInfo was constructed.
  8918. + base::ElapsedTimer timer;
  8919. +
  8920. + // Log information about a given script run. If |send_script_activity| is
  8921. + // true, this also informs the browser of the script run.
  8922. + void LogRun(bool send_script_activity);
  8923. +
  8924. + static void LogLongInjectionTaskTime(UserScript::RunLocation run_location,
  8925. + const base::TimeDelta& elapsed);
  8926. +
  8927. + private:
  8928. + // The routinig id to use to notify the browser of any injections. Since the
  8929. + // frame may be deleted in injection, we don't hold on to a reference to it
  8930. + // directly.
  8931. + int routing_id_;
  8932. +
  8933. + // The run location at which injection is happening.
  8934. + UserScript::RunLocation run_location_;
  8935. +
  8936. + // The url of the frame, preserved for the same reason as the routing id.
  8937. + GURL frame_url_;
  8938. +
  8939. + DISALLOW_COPY_AND_ASSIGN(ScriptsRunInfo);
  8940. +};
  8941. +
  8942. +} // namespace extensions
  8943. +
  8944. +#endif // USERSCRIPTS_RENDERER_SCRIPTS_RUN_INFO_H_
  8945. diff --git a/components/user_scripts/renderer/user_script_injector.cc b/components/user_scripts/renderer/user_script_injector.cc
  8946. new file mode 100755
  8947. --- /dev/null
  8948. +++ b/components/user_scripts/renderer/user_script_injector.cc
  8949. @@ -0,0 +1,228 @@
  8950. +// Copyright 2014 The Chromium Authors. All rights reserved.
  8951. +// Use of this source code is governed by a BSD-style license that can be
  8952. +// found in the LICENSE file.
  8953. +
  8954. +#include "user_script_injector.h"
  8955. +
  8956. +#include <tuple>
  8957. +#include <vector>
  8958. +
  8959. +#include "base/logging.h"
  8960. +#include "base/lazy_instance.h"
  8961. +#include "content/public/common/url_constants.h"
  8962. +#include "content/public/renderer/render_frame.h"
  8963. +#include "content/public/renderer/render_thread.h"
  8964. +#include "content/public/renderer/render_view.h"
  8965. +#include "components/user_scripts/renderer/grit/user_scripts_renderer_resources.h"
  8966. +#include "injection_host.h"
  8967. +#include "script_context.h"
  8968. +#include "scripts_run_info.h"
  8969. +#include "third_party/blink/public/web/web_document.h"
  8970. +#include "third_party/blink/public/web/web_local_frame.h"
  8971. +#include "third_party/blink/public/web/web_script_source.h"
  8972. +#include "ui/base/resource/resource_bundle.h"
  8973. +#include "url/gurl.h"
  8974. +
  8975. +namespace user_scripts {
  8976. +
  8977. +namespace {
  8978. +
  8979. +struct RoutingInfoKey {
  8980. + int routing_id;
  8981. + int script_id;
  8982. +
  8983. + RoutingInfoKey(int routing_id, int script_id)
  8984. + : routing_id(routing_id), script_id(script_id) {}
  8985. +
  8986. + bool operator<(const RoutingInfoKey& other) const {
  8987. + return std::tie(routing_id, script_id) <
  8988. + std::tie(other.routing_id, other.script_id);
  8989. + }
  8990. +};
  8991. +
  8992. +using RoutingInfoMap = std::map<RoutingInfoKey, bool>;
  8993. +
  8994. +// A map records whether a given |script_id| from a webview-added user script
  8995. +// is allowed to inject on the render of given |routing_id|.
  8996. +// Once a script is added, the decision of whether or not allowed to inject
  8997. +// won't be changed.
  8998. +// After removed by the webview, the user scipt will also be removed
  8999. +// from the render. Therefore, there won't be any query from the same
  9000. +// |script_id| and |routing_id| pair.
  9001. +// base::LazyInstance<RoutingInfoMap>::DestructorAtExit g_routing_info_map =
  9002. +// LAZY_INSTANCE_INITIALIZER;
  9003. +
  9004. +// Greasemonkey API source that is injected with the scripts.
  9005. +struct GreasemonkeyApiJsString {
  9006. + GreasemonkeyApiJsString();
  9007. + blink::WebScriptSource GetSource() const;
  9008. +
  9009. + private:
  9010. + blink::WebString source_;
  9011. +};
  9012. +
  9013. +// The below constructor, monstrous as it is, just makes a WebScriptSource from
  9014. +// the GreasemonkeyApiJs resource.
  9015. +GreasemonkeyApiJsString::GreasemonkeyApiJsString() {
  9016. + std::string greasemonky_api_js(
  9017. + ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(
  9018. + IDR_GREASEMONKEY_API_JS));
  9019. + source_ = blink::WebString::FromUTF8(greasemonky_api_js);
  9020. +}
  9021. +
  9022. +blink::WebScriptSource GreasemonkeyApiJsString::GetSource() const {
  9023. + return blink::WebScriptSource(source_);
  9024. +}
  9025. +
  9026. +base::LazyInstance<GreasemonkeyApiJsString>::Leaky g_greasemonkey_api =
  9027. + LAZY_INSTANCE_INITIALIZER;
  9028. +
  9029. +bool ShouldInjectScripts(const UserScript::FileList& scripts,
  9030. + const std::set<std::string>& injected_files) {
  9031. + for (const std::unique_ptr<UserScript::File>& file : scripts) {
  9032. + // Check if the script is already injected.
  9033. + if (injected_files.count(file->url().path()) == 0) {
  9034. + return true;
  9035. + }
  9036. + }
  9037. + return false;
  9038. +}
  9039. +
  9040. +} // namespace
  9041. +
  9042. +UserScriptInjector::UserScriptInjector(const UserScript* script,
  9043. + UserScriptSet* script_list)
  9044. + : script_(script),
  9045. + user_script_set_(script_list),
  9046. + script_id_(script_->id()),
  9047. + user_script_set_observer_(this) {
  9048. + user_script_set_observer_.Add(script_list);
  9049. +}
  9050. +
  9051. +UserScriptInjector::~UserScriptInjector() {
  9052. +}
  9053. +
  9054. +void UserScriptInjector::OnUserScriptsUpdated(
  9055. + const std::set<HostID>& changed_hosts,
  9056. + const UserScriptList& scripts) {
  9057. + // When user scripts are updated, all the old script pointers are invalidated.
  9058. + script_ = nullptr;
  9059. + // If the host causing this injection changed, then this injection
  9060. + // will be removed, and there's no guarantee the backing script still exists.
  9061. + // if (changed_hosts.count(host_id_) > 0)
  9062. + // return;
  9063. +
  9064. + for (const std::unique_ptr<UserScript>& script : scripts) {
  9065. + if (script->id() == script_id_) {
  9066. + script_ = script.get();
  9067. + break;
  9068. + }
  9069. + }
  9070. + // If |host_id_| wasn't in |changed_hosts|, then the script for this injection
  9071. + // should be guaranteed to exist.
  9072. + DCHECK(script_);
  9073. +}
  9074. +
  9075. +UserScript::InjectionType UserScriptInjector::script_type() const {
  9076. + return UserScript::CONTENT_SCRIPT;
  9077. +}
  9078. +
  9079. +bool UserScriptInjector::IsUserGesture() const {
  9080. + return false;
  9081. +}
  9082. +
  9083. +bool UserScriptInjector::ExpectsResults() const {
  9084. + return false;
  9085. +}
  9086. +
  9087. +base::Optional<CSSOrigin> UserScriptInjector::GetCssOrigin() const {
  9088. + return base::nullopt;
  9089. +}
  9090. +
  9091. +const base::Optional<std::string> UserScriptInjector::GetInjectionKey() const {
  9092. + return base::nullopt;
  9093. +}
  9094. +
  9095. +bool UserScriptInjector::ShouldInjectJs(
  9096. + UserScript::RunLocation run_location,
  9097. + const std::set<std::string>& executing_scripts) const {
  9098. + return script_ && script_->run_location() == run_location &&
  9099. + !script_->js_scripts().empty() &&
  9100. + ShouldInjectScripts(script_->js_scripts(), executing_scripts);
  9101. +}
  9102. +
  9103. +bool UserScriptInjector::ShouldInjectCss(
  9104. + UserScript::RunLocation run_location,
  9105. + const std::set<std::string>& injected_stylesheets) const {
  9106. + return script_ && run_location == UserScript::DOCUMENT_START &&
  9107. + !script_->css_scripts().empty() &&
  9108. + ShouldInjectScripts(script_->css_scripts(), injected_stylesheets);
  9109. +}
  9110. +
  9111. +std::vector<blink::WebScriptSource> UserScriptInjector::GetJsSources(
  9112. + UserScript::RunLocation run_location,
  9113. + std::set<std::string>* executing_scripts,
  9114. + size_t* num_injected_js_scripts) const {
  9115. + DCHECK(script_);
  9116. + std::vector<blink::WebScriptSource> sources;
  9117. +
  9118. + DCHECK_EQ(script_->run_location(), run_location);
  9119. +
  9120. + const UserScript::FileList& js_scripts = script_->js_scripts();
  9121. + sources.reserve(js_scripts.size() +
  9122. + (script_->emulate_greasemonkey() ? 1 : 0));
  9123. + // Emulate Greasemonkey API for scripts that were converted to extension
  9124. + // user scripts.
  9125. + if (script_->emulate_greasemonkey())
  9126. + sources.push_back(g_greasemonkey_api.Get().GetSource());
  9127. + for (const std::unique_ptr<UserScript::File>& file : js_scripts) {
  9128. + const GURL& script_url = file->url();
  9129. + // Check if the script is already injected.
  9130. + if (executing_scripts->count(script_url.path()) != 0)
  9131. + continue;
  9132. +
  9133. + sources.push_back(blink::WebScriptSource(
  9134. + user_script_set_->GetJsSource(*file, script_->emulate_greasemonkey()),
  9135. + script_url));
  9136. +
  9137. + (*num_injected_js_scripts) += 1;
  9138. + executing_scripts->insert(script_url.path());
  9139. + }
  9140. +
  9141. + return sources;
  9142. +}
  9143. +
  9144. +std::vector<blink::WebString> UserScriptInjector::GetCssSources(
  9145. + UserScript::RunLocation run_location,
  9146. + std::set<std::string>* injected_stylesheets,
  9147. + size_t* num_injected_stylesheets) const {
  9148. + DCHECK(script_);
  9149. + DCHECK_EQ(UserScript::DOCUMENT_START, run_location);
  9150. +
  9151. + std::vector<blink::WebString> sources;
  9152. +
  9153. + const UserScript::FileList& css_scripts = script_->css_scripts();
  9154. + sources.reserve(css_scripts.size());
  9155. + for (const std::unique_ptr<UserScript::File>& file : script_->css_scripts()) {
  9156. + const std::string& stylesheet_path = file->url().path();
  9157. + // Check if the stylesheet is already injected.
  9158. + if (injected_stylesheets->count(stylesheet_path) != 0)
  9159. + continue;
  9160. +
  9161. + sources.push_back(user_script_set_->GetCssSource(*file));
  9162. + (*num_injected_stylesheets) += 1;
  9163. + injected_stylesheets->insert(stylesheet_path);
  9164. + }
  9165. + return sources;
  9166. +}
  9167. +
  9168. +void UserScriptInjector::OnInjectionComplete(
  9169. + std::unique_ptr<base::Value> execution_result,
  9170. + UserScript::RunLocation run_location,
  9171. + content::RenderFrame* render_frame) {}
  9172. +
  9173. +void UserScriptInjector::OnWillNotInject(InjectFailureReason reason,
  9174. + content::RenderFrame* render_frame) {
  9175. +}
  9176. +
  9177. +} // namespace extensions
  9178. diff --git a/components/user_scripts/renderer/user_script_injector.h b/components/user_scripts/renderer/user_script_injector.h
  9179. new file mode 100755
  9180. --- /dev/null
  9181. +++ b/components/user_scripts/renderer/user_script_injector.h
  9182. @@ -0,0 +1,86 @@
  9183. +// Copyright 2014 The Chromium Authors. All rights reserved.
  9184. +// Use of this source code is governed by a BSD-style license that can be
  9185. +// found in the LICENSE file.
  9186. +
  9187. +#ifndef USERSCRIPTS_RENDERER_USER_SCRIPT_INJECTOR_H_
  9188. +#define USERSCRIPTS_RENDERER_USER_SCRIPT_INJECTOR_H_
  9189. +
  9190. +#include <memory>
  9191. +#include <string>
  9192. +
  9193. +#include "base/macros.h"
  9194. +#include "base/scoped_observer.h"
  9195. +#include "../common/user_script.h"
  9196. +#include "script_injection.h"
  9197. +#include "user_script_set.h"
  9198. +
  9199. +class InjectionHost;
  9200. +
  9201. +namespace blink {
  9202. +class WebLocalFrame;
  9203. +}
  9204. +
  9205. +namespace user_scripts {
  9206. +
  9207. +// A ScriptInjector for UserScripts.
  9208. +class UserScriptInjector : public ScriptInjector,
  9209. + public UserScriptSet::Observer {
  9210. + public:
  9211. + UserScriptInjector(const UserScript* user_script,
  9212. + UserScriptSet* user_script_set);
  9213. + ~UserScriptInjector() override;
  9214. +
  9215. + private:
  9216. + // UserScriptSet::Observer implementation.
  9217. + void OnUserScriptsUpdated(const std::set<HostID>& changed_hosts,
  9218. + const UserScriptList& scripts) override;
  9219. +
  9220. + // ScriptInjector implementation.
  9221. + UserScript::InjectionType script_type() const override;
  9222. + bool IsUserGesture() const override;
  9223. + base::Optional<CSSOrigin> GetCssOrigin() const override;
  9224. + const base::Optional<std::string> GetInjectionKey() const override;
  9225. + bool ExpectsResults() const override;
  9226. + bool ShouldInjectJs(
  9227. + UserScript::RunLocation run_location,
  9228. + const std::set<std::string>& executing_scripts) const override;
  9229. + bool ShouldInjectCss(
  9230. + UserScript::RunLocation run_location,
  9231. + const std::set<std::string>& injected_stylesheets) const override;
  9232. + std::vector<blink::WebScriptSource> GetJsSources(
  9233. + UserScript::RunLocation run_location,
  9234. + std::set<std::string>* executing_scripts,
  9235. + size_t* num_injected_js_scripts) const override;
  9236. + std::vector<blink::WebString> GetCssSources(
  9237. + UserScript::RunLocation run_location,
  9238. + std::set<std::string>* injected_stylesheets,
  9239. + size_t* num_injected_stylesheets) const override;
  9240. + void OnInjectionComplete(std::unique_ptr<base::Value> execution_result,
  9241. + UserScript::RunLocation run_location,
  9242. + content::RenderFrame* render_frame) override;
  9243. + void OnWillNotInject(InjectFailureReason reason,
  9244. + content::RenderFrame* render_frame) override;
  9245. +
  9246. + // The associated user script. Owned by the UserScriptInjector that created
  9247. + // this object.
  9248. + const UserScript* script_;
  9249. +
  9250. + // The UserScriptSet that eventually owns the UserScript this
  9251. + // UserScriptInjector points to.
  9252. + // Outlives |this|.
  9253. + UserScriptSet* const user_script_set_;
  9254. +
  9255. + // The id of the associated user script. We cache this because when we update
  9256. + // the |script_| associated with this injection, the old referance may be
  9257. + // deleted.
  9258. + int script_id_;
  9259. +
  9260. + ScopedObserver<UserScriptSet, UserScriptSet::Observer>
  9261. + user_script_set_observer_;
  9262. +
  9263. + DISALLOW_COPY_AND_ASSIGN(UserScriptInjector);
  9264. +};
  9265. +
  9266. +} // namespace extensions
  9267. +
  9268. +#endif // USERSCRIPTS_RENDERER_USER_SCRIPT_INJECTOR_H_
  9269. diff --git a/components/user_scripts/renderer/user_script_set.cc b/components/user_scripts/renderer/user_script_set.cc
  9270. new file mode 100755
  9271. --- /dev/null
  9272. +++ b/components/user_scripts/renderer/user_script_set.cc
  9273. @@ -0,0 +1,258 @@
  9274. +// Copyright 2014 The Chromium Authors. All rights reserved.
  9275. +// Use of this source code is governed by a BSD-style license that can be
  9276. +// found in the LICENSE file.
  9277. +
  9278. +#include "user_script_set.h"
  9279. +
  9280. +#include <stddef.h>
  9281. +
  9282. +#include <utility>
  9283. +
  9284. +#include "base/logging.h"
  9285. +#include "base/debug/alias.h"
  9286. +#include "base/memory/ref_counted.h"
  9287. +#include "base/strings/strcat.h"
  9288. +#include "content/public/common/url_constants.h"
  9289. +#include "content/public/renderer/render_frame.h"
  9290. +#include "content/public/renderer/render_thread.h"
  9291. +#include "injection_host.h"
  9292. +#include "script_context.h"
  9293. +#include "script_injection.h"
  9294. +#include "user_script_injector.h"
  9295. +#include "web_ui_injection_host.h"
  9296. +#include "third_party/blink/public/web/web_document.h"
  9297. +#include "third_party/blink/public/web/web_local_frame.h"
  9298. +#include "url/gurl.h"
  9299. +#include "../common/user_scripts_features.h"
  9300. +
  9301. +namespace user_scripts {
  9302. +
  9303. +namespace {
  9304. +
  9305. +// These two strings are injected before and after the Greasemonkey API and
  9306. +// user script to wrap it in an anonymous scope.
  9307. +const char kUserScriptHead[] = "(function (unsafeWindow) {\n";
  9308. +const char kUserScriptTail[] = "\n})(window);";
  9309. +// Maximum number of total content scripts we allow (across all extensions).
  9310. +// The limit exists to diagnose https://crbug.com/723381. The number is
  9311. +// arbitrarily chosen.
  9312. +// TODO(lazyboy): Remove when the bug is fixed.
  9313. +const uint32_t kNumScriptsArbitraryMax = 100000u;
  9314. +
  9315. +GURL GetDocumentUrlForFrame(blink::WebLocalFrame* frame) {
  9316. + GURL data_source_url = ScriptContext::GetDocumentLoaderURLForFrame(frame);
  9317. + if (!data_source_url.is_empty() && frame->IsViewSourceModeEnabled()) {
  9318. + data_source_url = GURL(content::kViewSourceScheme + std::string(":") +
  9319. + data_source_url.spec());
  9320. + }
  9321. +
  9322. + return data_source_url;
  9323. +}
  9324. +
  9325. +} // namespace
  9326. +
  9327. +UserScriptSet::UserScriptSet() {}
  9328. +
  9329. +UserScriptSet::~UserScriptSet() {
  9330. +}
  9331. +
  9332. +void UserScriptSet::AddObserver(Observer* observer) {
  9333. + observers_.AddObserver(observer);
  9334. +}
  9335. +
  9336. +void UserScriptSet::RemoveObserver(Observer* observer) {
  9337. + observers_.RemoveObserver(observer);
  9338. +}
  9339. +
  9340. +void UserScriptSet::GetInjections(
  9341. + std::vector<std::unique_ptr<ScriptInjection>>* injections,
  9342. + content::RenderFrame* render_frame,
  9343. + int tab_id,
  9344. + UserScript::RunLocation run_location,
  9345. + bool log_activity) {
  9346. + GURL document_url = GetDocumentUrlForFrame(render_frame->GetWebFrame());
  9347. + for (const std::unique_ptr<UserScript>& script : scripts_) {
  9348. + std::unique_ptr<ScriptInjection> injection = GetInjectionForScript(
  9349. + script.get(), render_frame, tab_id, run_location, document_url,
  9350. + /* is_declarative, */ log_activity);
  9351. + if (injection.get())
  9352. + injections->push_back(std::move(injection));
  9353. + }
  9354. +}
  9355. +
  9356. +bool UserScriptSet::UpdateUserScripts(
  9357. + base::ReadOnlySharedMemoryRegion shared_memory,
  9358. + const std::set<HostID>& changed_hosts,
  9359. + bool whitelisted_only) {
  9360. + bool only_inject_incognito = false;
  9361. + //ExtensionsRendererClient::Get()->IsIncognitoProcess();
  9362. +
  9363. + // Create the shared memory mapping.
  9364. + shared_memory_mapping_ = shared_memory.Map();
  9365. + if (!shared_memory.IsValid())
  9366. + return false;
  9367. +
  9368. + // First get the size of the memory block.
  9369. + const base::Pickle::Header* pickle_header =
  9370. + shared_memory_mapping_.GetMemoryAs<base::Pickle::Header>();
  9371. + if (!pickle_header)
  9372. + return false;
  9373. +
  9374. + // Now read in the rest of the block.
  9375. + size_t pickle_size =
  9376. + sizeof(base::Pickle::Header) + pickle_header->payload_size;
  9377. +
  9378. + // Unpickle scripts.
  9379. + uint32_t num_scripts = 0;
  9380. + auto memory = shared_memory_mapping_.GetMemoryAsSpan<char>(pickle_size);
  9381. + if (!memory.size())
  9382. + return false;
  9383. +
  9384. + base::Pickle pickle(memory.data(), pickle_size);
  9385. + base::PickleIterator iter(pickle);
  9386. + base::debug::Alias(&pickle_size);
  9387. + CHECK(iter.ReadUInt32(&num_scripts));
  9388. +
  9389. + // Sometimes the shared memory contents seem to be corrupted
  9390. + // (https://crbug.com/723381). Set an arbitrary max limit to the number of
  9391. + // scripts so that we don't add OOM noise to crash reports.
  9392. + CHECK_LT(num_scripts, kNumScriptsArbitraryMax);
  9393. +
  9394. + scripts_.clear();
  9395. + script_sources_.clear();
  9396. + scripts_.reserve(num_scripts);
  9397. + for (uint32_t i = 0; i < num_scripts; ++i) {
  9398. + std::unique_ptr<UserScript> script(new UserScript());
  9399. + script->Unpickle(pickle, &iter);
  9400. +
  9401. + // Note that this is a pointer into shared memory. We don't own it. It gets
  9402. + // cleared up when the last renderer or browser process drops their
  9403. + // reference to the shared memory.
  9404. + for (size_t j = 0; j < script->js_scripts().size(); ++j) {
  9405. + const char* body = NULL;
  9406. + int body_length = 0;
  9407. + CHECK(iter.ReadData(&body, &body_length));
  9408. + script->js_scripts()[j]->set_external_content(
  9409. + base::StringPiece(body, body_length));
  9410. + }
  9411. + for (size_t j = 0; j < script->css_scripts().size(); ++j) {
  9412. + const char* body = NULL;
  9413. + int body_length = 0;
  9414. + CHECK(iter.ReadData(&body, &body_length));
  9415. + script->css_scripts()[j]->set_external_content(
  9416. + base::StringPiece(body, body_length));
  9417. + }
  9418. +
  9419. + if (only_inject_incognito && !script->is_incognito_enabled())
  9420. + continue; // This script shouldn't run in an incognito tab.
  9421. +
  9422. + scripts_.push_back(std::move(script));
  9423. + }
  9424. +
  9425. + for (auto& observer : observers_)
  9426. + observer.OnUserScriptsUpdated(changed_hosts, scripts_);
  9427. + return true;
  9428. +}
  9429. +
  9430. +void UserScriptSet::AddScript(std::unique_ptr<UserScript> script) {
  9431. + scripts_.push_back(std::move(script));
  9432. +}
  9433. +
  9434. +std::unique_ptr<ScriptInjection> UserScriptSet::GetInjectionForScript(
  9435. + const UserScript* script,
  9436. + content::RenderFrame* render_frame,
  9437. + int tab_id,
  9438. + UserScript::RunLocation run_location,
  9439. + const GURL& document_url,
  9440. + //bool is_declarative,
  9441. + bool log_activity) {
  9442. + std::unique_ptr<ScriptInjection> injection;
  9443. + std::unique_ptr<const InjectionHost> injection_host;
  9444. + blink::WebLocalFrame* web_frame = render_frame->GetWebFrame();
  9445. +
  9446. + const HostID& host_id = script->host_id();
  9447. + injection_host.reset(new WebUIInjectionHost(host_id));
  9448. +
  9449. + GURL effective_document_url =
  9450. + ScriptContext::GetEffectiveDocumentURLForInjection(
  9451. + web_frame, document_url, script->match_origin_as_fallback());
  9452. +
  9453. + bool is_subframe = web_frame->Parent();
  9454. + if (!script->MatchesDocument(effective_document_url, is_subframe)) {
  9455. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  9456. + LOG(INFO) << "UserScripts: No Match name=" << script->name() << " " <<
  9457. + "url=" << effective_document_url.spec();
  9458. + return injection;
  9459. + }
  9460. +
  9461. + std::unique_ptr<ScriptInjector> injector(
  9462. + new UserScriptInjector(script, this));
  9463. +
  9464. + bool inject_css = !script->css_scripts().empty() &&
  9465. + run_location == UserScript::DOCUMENT_START;
  9466. + bool inject_js =
  9467. + !script->js_scripts().empty() && script->run_location() == run_location;
  9468. + if (inject_css || inject_js) {
  9469. + injection.reset(new ScriptInjection(std::move(injector), render_frame,
  9470. + std::move(injection_host), run_location,
  9471. + log_activity));
  9472. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  9473. + LOG(INFO) << "UserScripts: Match name=" << script->name() << " " <<
  9474. + "url=" << effective_document_url.spec();
  9475. + } else {
  9476. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts)) {
  9477. + if (script->run_location() != run_location)
  9478. + LOG(INFO) << "UserScripts: wrong run location current " << run_location << " " <<
  9479. + "expeted " << script->run_location();
  9480. + else
  9481. + LOG(INFO) << "UserScripts: Match but no script name=" << script->name() << " " <<
  9482. + "url=" << effective_document_url.spec();
  9483. + }
  9484. + }
  9485. + return injection;
  9486. +}
  9487. +
  9488. +blink::WebString UserScriptSet::GetJsSource(const UserScript::File& file,
  9489. + bool emulate_greasemonkey) {
  9490. + const GURL& url = file.url();
  9491. + auto iter = script_sources_.find(url);
  9492. + if (iter != script_sources_.end()) {
  9493. + return iter->second;
  9494. + }
  9495. +
  9496. + base::StringPiece script_content = file.GetContent();
  9497. + blink::WebString source;
  9498. + if (emulate_greasemonkey) {
  9499. + // We add this dumb function wrapper for user scripts to emulate what
  9500. + // Greasemonkey does. |script_content| becomes:
  9501. + // concat(kUserScriptHead, script_content, kUserScriptTail).
  9502. + std::string content =
  9503. + base::StrCat({kUserScriptHead, script_content, kUserScriptTail});
  9504. + source = blink::WebString::FromUTF8(content);
  9505. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  9506. + LOG(INFO) << "UserScripts: Injecting w/greasemonkey " << file.url();
  9507. + } else {
  9508. + source = blink::WebString::FromUTF8(script_content.data(),
  9509. + script_content.length());
  9510. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  9511. + LOG(INFO) << "UserScripts: Injecting " << file.url();
  9512. + }
  9513. + script_sources_[url] = source;
  9514. + return source;
  9515. +}
  9516. +
  9517. +blink::WebString UserScriptSet::GetCssSource(const UserScript::File& file) {
  9518. + const GURL& url = file.url();
  9519. + auto iter = script_sources_.find(url);
  9520. + if (iter != script_sources_.end())
  9521. + return iter->second;
  9522. +
  9523. + base::StringPiece script_content = file.GetContent();
  9524. + return script_sources_
  9525. + .insert(std::make_pair(
  9526. + url, blink::WebString::FromUTF8(script_content.data(),
  9527. + script_content.length())))
  9528. + .first->second;
  9529. +}
  9530. +
  9531. +} // namespace extensions
  9532. diff --git a/components/user_scripts/renderer/user_script_set.h b/components/user_scripts/renderer/user_script_set.h
  9533. new file mode 100755
  9534. --- /dev/null
  9535. +++ b/components/user_scripts/renderer/user_script_set.h
  9536. @@ -0,0 +1,102 @@
  9537. +// Copyright 2014 The Chromium Authors. All rights reserved.
  9538. +// Use of this source code is governed by a BSD-style license that can be
  9539. +// found in the LICENSE file.
  9540. +
  9541. +#ifndef USERSCRIPTS_RENDERER_USER_SCRIPT_SET_H_
  9542. +#define USERSCRIPTS_RENDERER_USER_SCRIPT_SET_H_
  9543. +
  9544. +#include <map>
  9545. +#include <memory>
  9546. +#include <set>
  9547. +#include <string>
  9548. +#include <vector>
  9549. +
  9550. +#include "base/macros.h"
  9551. +#include "base/memory/read_only_shared_memory_region.h"
  9552. +#include "base/observer_list.h"
  9553. +#include "../common/user_script.h"
  9554. +#include "third_party/blink/public/platform/web_string.h"
  9555. +
  9556. +class GURL;
  9557. +
  9558. +namespace content {
  9559. +class RenderFrame;
  9560. +}
  9561. +
  9562. +namespace user_scripts {
  9563. +class ScriptInjection;
  9564. +
  9565. +// The UserScriptSet is a collection of UserScripts which knows how to update
  9566. +// itself from SharedMemory and create ScriptInjections for UserScripts to
  9567. +// inject on a page.
  9568. +class UserScriptSet {
  9569. + public:
  9570. + class Observer {
  9571. + public:
  9572. + // Called when the set of user scripts is updated. |changed_hosts| contains
  9573. + // the hosts whose scripts have been altered. Note that *all* script objects
  9574. + // are invalidated, even if they aren't in |changed_hosts|.
  9575. + virtual void OnUserScriptsUpdated(const std::set<HostID>& changed_hosts,
  9576. + const UserScriptList& scripts) = 0;
  9577. + };
  9578. +
  9579. + UserScriptSet();
  9580. + ~UserScriptSet();
  9581. +
  9582. + // Adds or removes observers.
  9583. + void AddObserver(Observer* observer);
  9584. + void RemoveObserver(Observer* observer);
  9585. + void AddScript(std::unique_ptr<UserScript> script);
  9586. +
  9587. + // Append any ScriptInjections that should run on the given |render_frame| and
  9588. + // |tab_id|, at the given |run_location|, to |injections|.
  9589. + // |extensions| is passed in to verify the corresponding extension is still
  9590. + // valid.
  9591. + void GetInjections(std::vector<std::unique_ptr<ScriptInjection>>* injections,
  9592. + content::RenderFrame* render_frame,
  9593. + int tab_id,
  9594. + UserScript::RunLocation run_location,
  9595. + bool log_activity);
  9596. +
  9597. + // Updates scripts given the shared memory region containing user scripts.
  9598. + // Returns true if the scripts were successfully updated.
  9599. + bool UpdateUserScripts(base::ReadOnlySharedMemoryRegion shared_memory,
  9600. + const std::set<HostID>& changed_hosts,
  9601. + bool whitelisted_only);
  9602. +
  9603. + // Returns the contents of a script file.
  9604. + // Note that copying is cheap as this uses WebString.
  9605. + blink::WebString GetJsSource(const UserScript::File& file,
  9606. + bool emulate_greasemonkey);
  9607. + blink::WebString GetCssSource(const UserScript::File& file);
  9608. +
  9609. + private:
  9610. + // Returns a new ScriptInjection for the given |script| to execute in the
  9611. + // |render_frame|, or NULL if the script should not execute.
  9612. + std::unique_ptr<ScriptInjection> GetInjectionForScript(
  9613. + const UserScript* script,
  9614. + content::RenderFrame* render_frame,
  9615. + int tab_id,
  9616. + UserScript::RunLocation run_location,
  9617. + const GURL& document_url,
  9618. + //bool is_declarative,
  9619. + bool log_activity);
  9620. +
  9621. + // Shared memory mapping containing raw script data.
  9622. + base::ReadOnlySharedMemoryMapping shared_memory_mapping_;
  9623. +
  9624. + // The UserScripts this injector manages.
  9625. + UserScriptList scripts_;
  9626. +
  9627. + // Map of user script file url -> source.
  9628. + std::map<GURL, blink::WebString> script_sources_;
  9629. +
  9630. + // The associated observers.
  9631. + base::ObserverList<Observer>::Unchecked observers_;
  9632. +
  9633. + DISALLOW_COPY_AND_ASSIGN(UserScriptSet);
  9634. +};
  9635. +
  9636. +} // namespace extensions
  9637. +
  9638. +#endif // USERSCRIPTS_RENDERER_USER_SCRIPT_SET_H_
  9639. diff --git a/components/user_scripts/renderer/user_script_set_manager.cc b/components/user_scripts/renderer/user_script_set_manager.cc
  9640. new file mode 100755
  9641. --- /dev/null
  9642. +++ b/components/user_scripts/renderer/user_script_set_manager.cc
  9643. @@ -0,0 +1,77 @@
  9644. +#include "user_script_set_manager.h"
  9645. +
  9646. +#include "base/logging.h"
  9647. +#include "content/public/renderer/render_thread.h"
  9648. +#include "../common/host_id.h"
  9649. +#include "../common/extension_messages.h"
  9650. +#include "../common/user_scripts_features.h"
  9651. +#include "user_script_set.h"
  9652. +
  9653. +namespace user_scripts {
  9654. +
  9655. +UserScriptSetManager::UserScriptSetManager() {
  9656. + content::RenderThread::Get()->AddObserver(this);
  9657. +}
  9658. +
  9659. +UserScriptSetManager::~UserScriptSetManager() {
  9660. +}
  9661. +
  9662. +void UserScriptSetManager::AddObserver(Observer* observer) {
  9663. + observers_.AddObserver(observer);
  9664. +}
  9665. +
  9666. +void UserScriptSetManager::RemoveObserver(Observer* observer) {
  9667. + observers_.RemoveObserver(observer);
  9668. +}
  9669. +
  9670. +bool UserScriptSetManager::OnControlMessageReceived(
  9671. + const IPC::Message& message) {
  9672. + bool handled = true;
  9673. + IPC_BEGIN_MESSAGE_MAP(UserScriptSetManager, message)
  9674. + IPC_MESSAGE_HANDLER(ExtensionMsg_UpdateUserScripts, OnUpdateUserScripts)
  9675. + IPC_MESSAGE_UNHANDLED(handled = false)
  9676. + IPC_END_MESSAGE_MAP()
  9677. + return handled;
  9678. +}
  9679. +
  9680. +void UserScriptSetManager::GetAllInjections(
  9681. + std::vector<std::unique_ptr<ScriptInjection>>* injections,
  9682. + content::RenderFrame* render_frame,
  9683. + int tab_id,
  9684. + UserScript::RunLocation run_location) {
  9685. +
  9686. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  9687. + LOG(INFO) << "UserScripts: GetAllInjections";
  9688. +
  9689. + // static_scripts_ is UserScriptSet
  9690. + static_scripts_.GetInjections(injections, render_frame, tab_id, run_location,
  9691. + activity_logging_enabled_);
  9692. +}
  9693. +
  9694. +void UserScriptSetManager::OnUpdateUserScripts(
  9695. + base::ReadOnlySharedMemoryRegion shared_memory) {
  9696. + if (!shared_memory.IsValid()) {
  9697. + NOTREACHED() << "Bad scripts handle";
  9698. + return;
  9699. + }
  9700. +
  9701. + UserScriptSet* scripts = NULL;
  9702. + scripts = &static_scripts_;
  9703. +
  9704. + DCHECK(scripts);
  9705. +
  9706. + // If no hosts are included in the set, that indicates that all
  9707. + // hosts were updated. Add them all to the set so that observers and
  9708. + // individual UserScriptSets don't need to know this detail.
  9709. + //const std::set<HostID>* effective_hosts = &changed_hosts;
  9710. + std::set<HostID> all_hosts;
  9711. + const std::set<HostID>* effective_hosts = &all_hosts;
  9712. +
  9713. + if (scripts->UpdateUserScripts(std::move(shared_memory), *effective_hosts,
  9714. + false /*whitelisted_only*/)) {
  9715. + for (auto& observer : observers_)
  9716. + observer.OnUserScriptsUpdated(all_hosts /* *effective_hosts*/);
  9717. + }
  9718. +}
  9719. +
  9720. +}
  9721. \ No newline at end of file
  9722. diff --git a/components/user_scripts/renderer/user_script_set_manager.h b/components/user_scripts/renderer/user_script_set_manager.h
  9723. new file mode 100755
  9724. --- /dev/null
  9725. +++ b/components/user_scripts/renderer/user_script_set_manager.h
  9726. @@ -0,0 +1,62 @@
  9727. +#ifndef USERSCRIPTS_RENDER_SET_MANAGER_H_
  9728. +#define USERSCRIPTS_RENDER_SET_MANAGER_H_
  9729. +
  9730. +#include <map>
  9731. +#include <set>
  9732. +#include <string>
  9733. +#include <vector>
  9734. +
  9735. +#include "base/macros.h"
  9736. +#include "base/memory/read_only_shared_memory_region.h"
  9737. +#include "base/observer_list.h"
  9738. +#include "content/public/renderer/render_thread_observer.h"
  9739. +#include "../common/host_id.h"
  9740. +#include "user_script_set.h"
  9741. +#include "script_injection.h"
  9742. +
  9743. +namespace user_scripts {
  9744. +
  9745. +class UserScriptSetManager : public content::RenderThreadObserver {
  9746. + public:
  9747. + class Observer {
  9748. + public:
  9749. + virtual void OnUserScriptsUpdated(const std::set<HostID>& changed_hosts) = 0;
  9750. + };
  9751. +
  9752. + UserScriptSetManager();
  9753. +
  9754. + ~UserScriptSetManager() override;
  9755. +
  9756. + void AddObserver(Observer* observer);
  9757. + void RemoveObserver(Observer* observer);
  9758. +
  9759. + // Append all injections from |static_scripts| and each of
  9760. + // |programmatic_scripts_| to |injections|.
  9761. + void GetAllInjections(
  9762. + std::vector<std::unique_ptr<ScriptInjection>>* injections,
  9763. + content::RenderFrame* render_frame,
  9764. + int tab_id,
  9765. + UserScript::RunLocation run_location);
  9766. +
  9767. +private:
  9768. + // content::RenderThreadObserver implementation.
  9769. + bool OnControlMessageReceived(const IPC::Message& message) override;
  9770. +
  9771. + base::ObserverList<Observer>::Unchecked observers_;
  9772. +
  9773. + // Handle the UpdateUserScripts extension message.
  9774. + void OnUpdateUserScripts(base::ReadOnlySharedMemoryRegion shared_memory);
  9775. + //, const HostID& host_id,
  9776. + //const std::set<HostID>& changed_hosts,
  9777. + //bool whitelisted_only);
  9778. +
  9779. + // Scripts statically defined in extension manifests.
  9780. + UserScriptSet static_scripts_;
  9781. +
  9782. + // Whether or not dom activity should be logged for scripts injected.
  9783. + bool activity_logging_enabled_ = false;
  9784. +};
  9785. +
  9786. +}
  9787. +
  9788. +#endif
  9789. \ No newline at end of file
  9790. diff --git a/components/user_scripts/renderer/user_scripts_dispatcher.cc b/components/user_scripts/renderer/user_scripts_dispatcher.cc
  9791. new file mode 100755
  9792. --- /dev/null
  9793. +++ b/components/user_scripts/renderer/user_scripts_dispatcher.cc
  9794. @@ -0,0 +1,36 @@
  9795. +#include "user_scripts_dispatcher.h"
  9796. +
  9797. +#include <stddef.h>
  9798. +
  9799. +#include <algorithm>
  9800. +#include <memory>
  9801. +#include <utility>
  9802. +
  9803. +#include "content/public/renderer/render_thread.h"
  9804. +#include "extension_frame_helper.h"
  9805. +
  9806. +namespace user_scripts {
  9807. +
  9808. +// ex ChromeExtensionsDispatcherDelegate
  9809. +UserScriptsDispatcher::UserScriptsDispatcher()
  9810. + : user_script_set_manager_observer_(this) {
  9811. + user_script_set_manager_.reset(new UserScriptSetManager());
  9812. + script_injection_manager_.reset(
  9813. + new ScriptInjectionManager(user_script_set_manager_.get()));
  9814. + user_script_set_manager_observer_.Add(user_script_set_manager_.get());
  9815. +}
  9816. +
  9817. +UserScriptsDispatcher::~UserScriptsDispatcher() {
  9818. +}
  9819. +
  9820. +void UserScriptsDispatcher::OnRenderThreadStarted(content::RenderThread* thread) {
  9821. +}
  9822. +
  9823. +void UserScriptsDispatcher::OnUserScriptsUpdated(const std::set<HostID>& changed_hosts) {
  9824. +}
  9825. +
  9826. +void UserScriptsDispatcher::OnRenderFrameCreated(content::RenderFrame* render_frame) {
  9827. + script_injection_manager_->OnRenderFrameCreated(render_frame);
  9828. +}
  9829. +
  9830. +}
  9831. \ No newline at end of file
  9832. diff --git a/components/user_scripts/renderer/user_scripts_dispatcher.h b/components/user_scripts/renderer/user_scripts_dispatcher.h
  9833. new file mode 100755
  9834. --- /dev/null
  9835. +++ b/components/user_scripts/renderer/user_scripts_dispatcher.h
  9836. @@ -0,0 +1,48 @@
  9837. +#ifndef USERSCRIPTS_RENDER_DISPATCHER_H_
  9838. +#define USERSCRIPTS_RENDER_DISPATCHER_H_
  9839. +
  9840. +#include "user_script_set_manager.h"
  9841. +#include "script_injection_manager.h"
  9842. +
  9843. +#include <stdint.h>
  9844. +
  9845. +#include <map>
  9846. +#include <memory>
  9847. +#include <set>
  9848. +#include <string>
  9849. +#include <utility>
  9850. +#include <vector>
  9851. +
  9852. +#include "base/macros.h"
  9853. +#include "base/scoped_observer.h"
  9854. +#include "content/public/renderer/render_thread_observer.h"
  9855. +#include "content/public/renderer/render_thread.h"
  9856. +#include "../common/host_id.h"
  9857. +#include "user_script_set_manager.h"
  9858. +#include "script_injection.h"
  9859. +
  9860. +namespace user_scripts {
  9861. +
  9862. +class UserScriptsDispatcher : public content::RenderThreadObserver,
  9863. + public UserScriptSetManager::Observer {
  9864. +
  9865. + public:
  9866. + explicit UserScriptsDispatcher();
  9867. + ~UserScriptsDispatcher() override;
  9868. +
  9869. + void OnRenderThreadStarted(content::RenderThread* thread);
  9870. + void OnUserScriptsUpdated(const std::set<HostID>& changed_hosts) override;
  9871. + void OnRenderFrameCreated(content::RenderFrame* render_frame);
  9872. +
  9873. + private:
  9874. + std::unique_ptr<UserScriptSetManager> user_script_set_manager_;
  9875. +
  9876. + std::unique_ptr<ScriptInjectionManager> script_injection_manager_;
  9877. +
  9878. + ScopedObserver<UserScriptSetManager, UserScriptSetManager::Observer>
  9879. + user_script_set_manager_observer_;
  9880. +};
  9881. +
  9882. +}
  9883. +
  9884. +#endif
  9885. \ No newline at end of file
  9886. diff --git a/components/user_scripts/renderer/user_scripts_renderer_client.cc b/components/user_scripts/renderer/user_scripts_renderer_client.cc
  9887. new file mode 100755
  9888. --- /dev/null
  9889. +++ b/components/user_scripts/renderer/user_scripts_renderer_client.cc
  9890. @@ -0,0 +1,76 @@
  9891. +#include "user_scripts_renderer_client.h"
  9892. +
  9893. +#include <memory>
  9894. +#include <utility>
  9895. +
  9896. +#include "base/logging.h"
  9897. +#include "base/lazy_instance.h"
  9898. +#include "content/public/renderer/render_thread.h"
  9899. +
  9900. +#include "../common/user_scripts_features.h"
  9901. +#include "user_scripts_dispatcher.h"
  9902. +#include "extension_frame_helper.h"
  9903. +
  9904. +namespace user_scripts {
  9905. +
  9906. +// was ChromeExtensionsRendererClient
  9907. +UserScriptsRendererClient::UserScriptsRendererClient() {}
  9908. +
  9909. +UserScriptsRendererClient::~UserScriptsRendererClient() {}
  9910. +
  9911. +// static
  9912. +UserScriptsRendererClient* UserScriptsRendererClient::GetInstance() {
  9913. + if (base::FeatureList::IsEnabled(features::kEnableUserScripts) == false)
  9914. + return NULL;
  9915. +
  9916. + static base::LazyInstance<UserScriptsRendererClient>::Leaky client =
  9917. + LAZY_INSTANCE_INITIALIZER;
  9918. + return client.Pointer();
  9919. +}
  9920. +
  9921. +void UserScriptsRendererClient::RenderThreadStarted() {
  9922. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  9923. + LOG(INFO) << "UserScripts: RenderThreadStarted";
  9924. + content::RenderThread* thread = content::RenderThread::Get();
  9925. +
  9926. + dispatcher_ = std::make_unique<UserScriptsDispatcher>();
  9927. +
  9928. + dispatcher_->OnRenderThreadStarted(thread);
  9929. + thread->AddObserver(dispatcher_.get());
  9930. +}
  9931. +
  9932. +void UserScriptsRendererClient::RenderFrameCreated(
  9933. + content::RenderFrame* render_frame,
  9934. + service_manager::BinderRegistry* registry) {
  9935. + new user_scripts::ExtensionFrameHelper(render_frame);
  9936. + dispatcher_->OnRenderFrameCreated(render_frame);
  9937. +}
  9938. +
  9939. +void UserScriptsRendererClient::RunScriptsAtDocumentStart(content::RenderFrame* render_frame) {
  9940. + ExtensionFrameHelper* frame_helper = ExtensionFrameHelper::Get(render_frame);
  9941. + if (!frame_helper)
  9942. + return; // The frame is invisible to extensions.
  9943. +
  9944. + frame_helper->RunScriptsAtDocumentStart();
  9945. + // |frame_helper| and |render_frame| might be dead by now.
  9946. +}
  9947. +
  9948. +void UserScriptsRendererClient::RunScriptsAtDocumentEnd(content::RenderFrame* render_frame) {
  9949. + ExtensionFrameHelper* frame_helper = ExtensionFrameHelper::Get(render_frame);
  9950. + if (!frame_helper)
  9951. + return; // The frame is invisible to extensions.
  9952. +
  9953. + frame_helper->RunScriptsAtDocumentEnd();
  9954. + // |frame_helper| and |render_frame| might be dead by now.
  9955. +}
  9956. +
  9957. +void UserScriptsRendererClient::RunScriptsAtDocumentIdle(content::RenderFrame* render_frame) {
  9958. + ExtensionFrameHelper* frame_helper = ExtensionFrameHelper::Get(render_frame);
  9959. + if (!frame_helper)
  9960. + return; // The frame is invisible to extensions.
  9961. +
  9962. + frame_helper->RunScriptsAtDocumentIdle();
  9963. + // |frame_helper| and |render_frame| might be dead by now.
  9964. +}
  9965. +
  9966. +}
  9967. \ No newline at end of file
  9968. diff --git a/components/user_scripts/renderer/user_scripts_renderer_client.h b/components/user_scripts/renderer/user_scripts_renderer_client.h
  9969. new file mode 100755
  9970. --- /dev/null
  9971. +++ b/components/user_scripts/renderer/user_scripts_renderer_client.h
  9972. @@ -0,0 +1,33 @@
  9973. +#ifndef USERSCRIPTS_RENDER_CLIENT_H_
  9974. +#define USERSCRIPTS_RENDER_CLIENT_H_
  9975. +
  9976. +#include <memory>
  9977. +#include <string>
  9978. +
  9979. +#include "base/macros.h"
  9980. +#include "user_scripts_dispatcher.h"
  9981. +#include "services/service_manager/public/cpp/binder_registry.h"
  9982. +
  9983. +namespace user_scripts {
  9984. +
  9985. +class UserScriptsRendererClient {
  9986. + public:
  9987. + UserScriptsRendererClient();
  9988. + ~UserScriptsRendererClient();
  9989. +
  9990. + static UserScriptsRendererClient* GetInstance();
  9991. +
  9992. + void RenderThreadStarted();
  9993. + void RenderFrameCreated(content::RenderFrame* render_frame,
  9994. + service_manager::BinderRegistry* registry);
  9995. + void RunScriptsAtDocumentStart(content::RenderFrame* render_frame);
  9996. + void RunScriptsAtDocumentEnd(content::RenderFrame* render_frame);
  9997. + void RunScriptsAtDocumentIdle(content::RenderFrame* render_frame);
  9998. +
  9999. + private:
  10000. + std::unique_ptr<UserScriptsDispatcher> dispatcher_;
  10001. +};
  10002. +
  10003. +}
  10004. +
  10005. +#endif
  10006. \ No newline at end of file
  10007. diff --git a/components/user_scripts/renderer/web_ui_injection_host.cc b/components/user_scripts/renderer/web_ui_injection_host.cc
  10008. new file mode 100755
  10009. --- /dev/null
  10010. +++ b/components/user_scripts/renderer/web_ui_injection_host.cc
  10011. @@ -0,0 +1,40 @@
  10012. +// Copyright 2015 The Chromium Authors. All rights reserved.
  10013. +// Use of this source code is governed by a BSD-style license that can be
  10014. +// found in the LICENSE file.
  10015. +
  10016. +#include "web_ui_injection_host.h"
  10017. +#include "base/no_destructor.h"
  10018. +
  10019. +namespace {
  10020. +
  10021. +// The default secure CSP to be used in order to prevent remote scripts.
  10022. +const char kDefaultSecureCSP[] = "script-src 'self'; object-src 'self';";
  10023. +
  10024. +}
  10025. +
  10026. +WebUIInjectionHost::WebUIInjectionHost(const HostID& host_id)
  10027. + : InjectionHost(host_id),
  10028. + url_(host_id.id()) {
  10029. +}
  10030. +
  10031. +WebUIInjectionHost::~WebUIInjectionHost() {
  10032. +}
  10033. +
  10034. +const std::string* WebUIInjectionHost::GetContentSecurityPolicy() const {
  10035. + // Use the main world CSP.
  10036. + // return nullptr;
  10037. +
  10038. + // The isolated world will use its own CSP which blocks remotely hosted
  10039. + // code.
  10040. + static const base::NoDestructor<std::string> default_isolated_world_csp(
  10041. + kDefaultSecureCSP);
  10042. + return default_isolated_world_csp.get();
  10043. +}
  10044. +
  10045. +const GURL& WebUIInjectionHost::url() const {
  10046. + return url_;
  10047. +}
  10048. +
  10049. +const std::string& WebUIInjectionHost::name() const {
  10050. + return id().id();
  10051. +}
  10052. diff --git a/components/user_scripts/renderer/web_ui_injection_host.h b/components/user_scripts/renderer/web_ui_injection_host.h
  10053. new file mode 100755
  10054. --- /dev/null
  10055. +++ b/components/user_scripts/renderer/web_ui_injection_host.h
  10056. @@ -0,0 +1,28 @@
  10057. +// Copyright 2015 The Chromium Authors. All rights reserved.
  10058. +// Use of this source code is governed by a BSD-style license that can be
  10059. +// found in the LICENSE file.
  10060. +
  10061. +#ifndef USERSCRIPTS_RENDERER_WEB_UI_INJECTION_HOST_H_
  10062. +#define USERSCRIPTS_RENDERER_WEB_UI_INJECTION_HOST_H_
  10063. +
  10064. +#include "base/macros.h"
  10065. +#include "injection_host.h"
  10066. +
  10067. +class WebUIInjectionHost : public InjectionHost {
  10068. + public:
  10069. + WebUIInjectionHost(const HostID& host_id);
  10070. + ~WebUIInjectionHost() override;
  10071. +
  10072. + private:
  10073. + // InjectionHost:
  10074. + const std::string* GetContentSecurityPolicy() const override;
  10075. + const GURL& url() const override;
  10076. + const std::string& name() const override;
  10077. +
  10078. + private:
  10079. + GURL url_;
  10080. +
  10081. + DISALLOW_COPY_AND_ASSIGN(WebUIInjectionHost);
  10082. +};
  10083. +
  10084. +#endif // USERSCRIPTS_RENDERER_WEB_UI_INJECTION_HOST_H_
  10085. diff --git a/components/user_scripts/strings/userscripts_strings.grdp b/components/user_scripts/strings/userscripts_strings.grdp
  10086. new file mode 100755
  10087. --- /dev/null
  10088. +++ b/components/user_scripts/strings/userscripts_strings.grdp
  10089. @@ -0,0 +1,50 @@
  10090. +<?xml version="1.0" encoding="utf-8"?>
  10091. +<grit-part>
  10092. +
  10093. + <!-- Preferences -->
  10094. + <message name="IDS_PREFS_USERSCRIPTS_SETTINGS"
  10095. + desc="Title of the dialog that presents a request for payment for some good or service. Sentence-cased."
  10096. + formatter_data="android_java">
  10097. + User Scripts
  10098. + </message>
  10099. +
  10100. + <message name="IDS_OPTION_USERSCRIPT_FLAG" desc="." formatter_data="android_java">
  10101. + Activate User Scripts
  10102. + </message>
  10103. +
  10104. + <message name="IDS_SCRIPTS_DISABLED_DESCRIPTION" desc="." formatter_data="android_java">
  10105. + Experimental support for userscripts are currently disabled. You can enable them by going to chrome://flags.
  10106. + </message>
  10107. +
  10108. + <message name="IDS_OPTION_USERSCRIPT_FLAG_ON" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10109. + ON
  10110. + </message>
  10111. + <message name="IDS_OPTION_USERSCRIPT_FLAG_OFF" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10112. + OFF
  10113. + </message>
  10114. +
  10115. + <message name="IDS_ADD_SCRIPT" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10116. + Add script
  10117. + </message>
  10118. + <message name="IDS_SCRIPTS_LIST_DESCRIPTION" desc="." formatter_data="android_java">
  10119. + Experimental support for Greasemonkey-style user scripts. Use at your own risk.
  10120. + </message>
  10121. +
  10122. + <message name="IDS_SCRIPTS_VIEW_SOURCE" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10123. + View source
  10124. + </message>
  10125. + <message name="IDS_SCRIPTS_OPEN_URL" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10126. + Open Url
  10127. + </message>
  10128. +
  10129. + <message name="IDS_ASK_TO_INSTALL" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10130. + Do you want to install
  10131. + </message>
  10132. + <message name="IDS_YES" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10133. + Yes
  10134. + </message>
  10135. + <message name="IDS_NO" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10136. + No
  10137. + </message>
  10138. +
  10139. +</grit-part>
  10140. \ No newline at end of file
  10141. diff --git a/tools/gritsettings/resource_ids.spec b/tools/gritsettings/resource_ids.spec
  10142. --- a/tools/gritsettings/resource_ids.spec
  10143. +++ b/tools/gritsettings/resource_ids.spec
  10144. @@ -464,6 +464,12 @@
  10145. "components/autofill/core/browser/autofill_address_rewriter_resources.grd":{
  10146. "includes": [2880]
  10147. },
  10148. + "components/user_scripts/renderer/resources/user_scripts_renderer_resources.grd": {
  10149. + "includes": [6000],
  10150. + },
  10151. + "components/user_scripts/browser/resources/browser_resources.grd": {
  10152. + "includes": [6020],
  10153. + },
  10154. # END components/ section.
  10155. # START ios/ section.
  10156. --
  10157. 2.17.1